diff --git a/ets2panda/lsp/BUILD.gn b/ets2panda/lsp/BUILD.gn index 5927ee5e6810eedf918db2d3578f072f8c86fcb8..bf9410f9ff6c13c3370c48e15fb58b82540dd2a8 100644 --- a/ets2panda/lsp/BUILD.gn +++ b/ets2panda/lsp/BUILD.gn @@ -100,6 +100,7 @@ ohos_source_set("libes2panda_lsp_static") { "src/register_code_fix/fix_missing_call_parantheses.cpp", "src/register_code_fix/fix_nan_equality.cpp", "src/register_code_fix/fix_return_type_in_async_function.cpp", + "src/register_code_fix/fix_remove_override_modifier.cpp", "src/register_code_fix/forgotten_this_property_access.cpp", "src/register_code_fix/import_fixes.cpp", "src/register_code_fix/remove_accidental_call_parentheses.cpp", diff --git a/ets2panda/lsp/CMakeLists.txt b/ets2panda/lsp/CMakeLists.txt index 0126ccf9b1593baf081b0844b0194678b62c1435..617efbc81895a9de3a4de885960eb7bc15d91cbd 100644 --- a/ets2panda/lsp/CMakeLists.txt +++ b/ets2panda/lsp/CMakeLists.txt @@ -124,6 +124,7 @@ set(ES2PANDA_LSP_SRC ./src/register_code_fix/forgotten_this_property_access.cpp ./src/register_code_fix/import_fixes.cpp ./src/register_code_fix/remove_accidental_call_parentheses.cpp + ./src/register_code_fix/fix_remove_override_modifier.cpp ./src/register_code_fix/fix_add_function_return_statement.cpp ./src/register_code_fix/ui_plugin_suggest.cpp ./src/get_signature.cpp diff --git a/ets2panda/lsp/include/register_code_fix/fix_remove_override_modifier.h b/ets2panda/lsp/include/register_code_fix/fix_remove_override_modifier.h new file mode 100644 index 0000000000000000000000000000000000000000..d924adbe1d7385715928ec2b6668227cc0ddd9b7 --- /dev/null +++ b/ets2panda/lsp/include/register_code_fix/fix_remove_override_modifier.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIX_REMOVE_OVERRIDE_MODIFIER_H +#define FIX_REMOVE_OVERRIDE_MODIFIER_H + +#include + +#include "lsp/include/code_fixes/code_fix_types.h" +#include "lsp/include/services/text_change/change_tracker.h" +#include "lsp/include/types.h" + +namespace ark::es2panda::lsp { + +class FixRemoveOverrideModifier : public CodeFixRegistration { +public: + FixRemoveOverrideModifier(); + + std::vector GetCodeActions(const CodeFixContext &context) override; + CombinedCodeActions GetAllCodeActions(const CodeFixAllContext &codeFixAll) override; + +private: + void MakeChangeForRemoveOverrideModifier(ChangeTracker &changeTracker, es2panda_Context *context, size_t pos); + std::vector GetCodeActionsToRemoveOverrideModifier(const CodeFixContext &context); +}; + +} // namespace ark::es2panda::lsp + +#endif // FIX_REMOVE_OVERRIDE_MODIFIER_H \ No newline at end of file diff --git a/ets2panda/lsp/src/register_code_fix/fix_remove_override_modifier.cpp b/ets2panda/lsp/src/register_code_fix/fix_remove_override_modifier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f0c8b41016341a436c051700bb7edce6ecdae35 --- /dev/null +++ b/ets2panda/lsp/src/register_code_fix/fix_remove_override_modifier.cpp @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lsp/include/register_code_fix/fix_remove_override_modifier.h" + +#include +#include + +#include "compiler/lowering/util.h" +#include "generated/code_fix_register.h" +#include "lsp/include/code_fix_provider.h" +#include "lsp/include/internal_api.h" + +namespace ark::es2panda::lsp { +using codefixes::REMOVE_OVERRIDE_MODIFIER; + +ir::AstNode *FindNearestClass(ir::AstNode *node) +{ + while (node != nullptr) { + if (node->IsClassDefinition()) { + return node; + } + node = node->Parent(); + } + return nullptr; +} + +void FixRemoveOverrideModifier::MakeChangeForRemoveOverrideModifier(ChangeTracker &changeTracker, + es2panda_Context *context, size_t pos) +{ + auto *token = GetTouchingToken(context, pos, false); + if (token == nullptr) { + return; + } + + // Remove the override modifier if found + TextRange overrideTokenRange = {0, 0}; + changeTracker.RfindNearestKeyWordTextRange(context, token->Start().index, "override", overrideTokenRange); + if (overrideTokenRange.end == 0) { + return; + } + + auto astContext = reinterpret_cast(context); + changeTracker.DeleteRange(astContext->sourceFile, overrideTokenRange); +} + +std::vector FixRemoveOverrideModifier::GetCodeActionsToRemoveOverrideModifier( + const CodeFixContext &context) +{ + TextChangesContext textChangesContext = {context.host, context.formatContext, context.preferences}; + auto fileTextChanges = ChangeTracker::With(textChangesContext, [&](ChangeTracker &tracker) { + MakeChangeForRemoveOverrideModifier(tracker, context.context, context.span.start); + }); + + return fileTextChanges; +} + +FixRemoveOverrideModifier::FixRemoveOverrideModifier() +{ + auto errorCodes = REMOVE_OVERRIDE_MODIFIER.GetSupportedCodeNumbers(); + SetErrorCodes({errorCodes.begin(), errorCodes.end()}); + SetFixIds({REMOVE_OVERRIDE_MODIFIER.GetFixId().data()}); +} + +std::vector FixRemoveOverrideModifier::GetCodeActions(const CodeFixContext &context) +{ + std::vector returnedActions; + auto changes = GetCodeActionsToRemoveOverrideModifier(context); + if (!changes.empty()) { + CodeFixAction codeAction; + codeAction.fixName = REMOVE_OVERRIDE_MODIFIER.GetFixId().data(); + codeAction.description = "Remove override modifier"; + codeAction.changes = changes; + codeAction.fixId = REMOVE_OVERRIDE_MODIFIER.GetFixId().data(); + codeAction.fixAllDescription = "Remove all unnecessary override modifiers"; + returnedActions.push_back(codeAction); + } + + return returnedActions; +} + +CombinedCodeActions FixRemoveOverrideModifier::GetAllCodeActions(const CodeFixAllContext &codeFixAllCtx) +{ + CodeFixProvider provider; + const auto changes = provider.CodeFixAll( + codeFixAllCtx, GetErrorCodes(), [&](ChangeTracker &tracker, const DiagnosticWithLocation &diag) { + MakeChangeForRemoveOverrideModifier(tracker, codeFixAllCtx.context, diag.GetStart()); + }); + + CombinedCodeActions combinedCodeActions; + combinedCodeActions.changes = changes.changes; + combinedCodeActions.commands = changes.commands; + + return combinedCodeActions; +} + +// NOLINTNEXTLINE(fuchsia-statically-constructed-objects, cert-err58-cpp) +AutoCodeFixRegister g_fixRemoveOverrideModifier(REMOVE_OVERRIDE_MODIFIER.GetFixId().data()); +} // namespace ark::es2panda::lsp \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/CMakeLists.txt b/ets2panda/test/unit/lsp/CMakeLists.txt index 5792c19b5e7c2b8e153c6f6174b2a11885d3f0cd..6e2f62a0b91176943e7a77baa8594c090b02d9dc 100644 --- a/ets2panda/test/unit/lsp/CMakeLists.txt +++ b/ets2panda/test/unit/lsp/CMakeLists.txt @@ -293,6 +293,10 @@ ets2panda_add_gtest(lsp_api_test_remove_accidental_call_parentheses CPP_SOURCES remove_accidental_call_parentheses_test.cpp ) +ets2panda_add_gtest(lsp_api_test_fix_remove_override_modifier_test CPP_SOURCES + fix_remove_override_modifier_test.cpp +) + ets2panda_add_gtest(lsp_api_add_missing_new_operator CPP_SOURCES add_missing_new_operator_test.cpp ) diff --git a/ets2panda/test/unit/lsp/fix_remove_override_modifier_test.cpp b/ets2panda/test/unit/lsp/fix_remove_override_modifier_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4503d19d4dd1696dc710fc313aaab9e3181caa75 --- /dev/null +++ b/ets2panda/test/unit/lsp/fix_remove_override_modifier_test.cpp @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "generated/code_fix_register.h" +#include "lsp_api_test.h" + +#include + +#include "lsp/include/api.h" +#include "lsp/include/cancellation_token.h" +#include "lsp/include/register_code_fix/fix_remove_override_modifier.h" + +namespace { + +using ark::es2panda::lsp::Initializer; +using ark::es2panda::lsp::codefixes::REMOVE_OVERRIDE_MODIFIER; + +constexpr std::string_view EXPECTED_FIX_NAME = REMOVE_OVERRIDE_MODIFIER.GetFixId(); +constexpr auto ERROR_CODES = REMOVE_OVERRIDE_MODIFIER.GetSupportedCodeNumbers(); +constexpr std::string_view EXPECTED_FIX_DESCRIPTION = "Remove override modifier"; +constexpr int DEFAULT_THROTTLE = 20; + +class FixRemoveOverrideModifierTests : public LSPAPITests { +public: + static ark::es2panda::lsp::CancellationToken CreateNonCancellationToken() + { + return ark::es2panda::lsp::CancellationToken(DEFAULT_THROTTLE, &GetNullHost()); + } + + static size_t LineColToPos(es2panda_Context *context, const size_t line, const size_t col) + { + auto ctx = reinterpret_cast(context); + auto index = ark::es2panda::lexer::LineIndex(ctx->parserProgram->SourceCode()); + auto pos = index.GetOffset(ark::es2panda::lexer::SourceLocation(line, col, ctx->parserProgram)); + return pos; + } + + static void ValidateCodeFixActionInfo(const CodeFixActionInfo &info, const size_t expectedTextChangeStart, + const size_t expectedTextChangeLength, const std::string &expectedFileName) + { + ASSERT_EQ(info.fixName_, EXPECTED_FIX_NAME); + ASSERT_EQ(info.fixId_, EXPECTED_FIX_NAME); + ASSERT_EQ(info.description_, EXPECTED_FIX_DESCRIPTION); + ASSERT_EQ(info.changes_[0].fileName, expectedFileName); + ASSERT_EQ(info.changes_[0].textChanges[0].span.start, expectedTextChangeStart); + ASSERT_EQ(info.changes_[0].textChanges[0].span.length, expectedTextChangeLength); + ASSERT_EQ(info.changes_[0].textChanges[0].newText, ""); + } + +private: + class NullCancellationToken : public ark::es2panda::lsp::HostCancellationToken { + public: + bool IsCancellationRequested() override + { + return false; + } + }; + + static NullCancellationToken &GetNullHost() + { + static NullCancellationToken instance; + return instance; + } +}; + +TEST_F(FixRemoveOverrideModifierTests, TestFixRemoveOverrideModifier01) +{ + std::vector fileNames = {"TestFixRemoveOverrideModifier01.ets"}; + std::vector fileContents = {R"( +class Animal { +} +class Dog extends Animal { + override foo() {} +} +)"}; + auto filePaths = CreateTempFile(fileNames, fileContents); + ASSERT_EQ(fileNames.size(), filePaths.size()); + + Initializer initializer = Initializer(); + auto *context = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED); + const size_t start = LineColToPos(context, 5, 17); + const size_t length = 1; + const size_t expectedTextChangeStart = 49; + const size_t expectedTextChangeLength = 8; + const int expectedFixResultSize = 1; + + std::vector errorCodes(ERROR_CODES.begin(), ERROR_CODES.end()); + CodeFixOptions emptyOptions = {CreateNonCancellationToken(), ark::es2panda::lsp::FormatCodeSettings(), {}}; + + auto fixResult = + ark::es2panda::lsp::GetCodeFixesAtPositionImpl(context, start, start + length, errorCodes, emptyOptions); + ASSERT_EQ(fixResult.size(), expectedFixResultSize); + + ValidateCodeFixActionInfo(fixResult[0], expectedTextChangeStart, expectedTextChangeLength, filePaths[0]); + + initializer.DestroyContext(context); +} + +} // namespace \ No newline at end of file diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index b07d3fb9be364cbc3059bace2b430f90c63d9d58..ee7e0ac28c942d940714a0c6d7136a302064e267 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -1045,6 +1045,7 @@ semantic: - name: OVERRIDE_DOESNT_OVERRIDE id: 136 message: "Method {}{} in {} not overriding any method" + code_fix_ids: [RemoveOverrideModifier] - name: PARAM_COUNT_MISMATCH id: 124