diff --git a/ets2panda/lsp/BUILD.gn b/ets2panda/lsp/BUILD.gn index 4c7e5927d8fccacbb9369b5ff82f4b68f1b702c8..286190b91ed7e1626d3801e3bb19364a20b994a6 100644 --- a/ets2panda/lsp/BUILD.gn +++ b/ets2panda/lsp/BUILD.gn @@ -88,6 +88,7 @@ ohos_source_set("libes2panda_lsp_static") { "src/references.cpp", "src/register_code_fix/add_missing_declare_property.cpp", "src/register_code_fix/fix_class_doesnt_implement_inherited_abstract_member.cpp", + "src/register_code_fix/fix_expected_comma.cpp", "src/register_code_fix/convert_const_to_let.cpp", "src/register_code_fix/fix_missing_call_parantheses.cpp", "src/register_code_fix/fix_nan_equality.cpp", diff --git a/ets2panda/lsp/CMakeLists.txt b/ets2panda/lsp/CMakeLists.txt index bb3d59457c48eef00230ab2c6729276cd534dbc4..f952e497423ccd5c5a4243b4c97c8d0385ea1617 100644 --- a/ets2panda/lsp/CMakeLists.txt +++ b/ets2panda/lsp/CMakeLists.txt @@ -111,6 +111,7 @@ set(ES2PANDA_LSP_SRC ./src/navigate_to.cpp ./src/code_fix_provider.cpp ./src/register_code_fix/fix_class_doesnt_implement_inherited_abstract_member.cpp + ./src/register_code_fix/fix_expected_comma.cpp ./src/register_code_fix/add_missing_declare_property.cpp ./src/register_code_fix/convert_const_to_let.cpp ./src/register_code_fix/fix_missing_call_parantheses.cpp diff --git a/ets2panda/lsp/include/register_code_fix/fix_expected_comma.h b/ets2panda/lsp/include/register_code_fix/fix_expected_comma.h new file mode 100644 index 0000000000000000000000000000000000000000..d1aea039ba220658cdf9d14f59f03ce2bb6ece13 --- /dev/null +++ b/ets2panda/lsp/include/register_code_fix/fix_expected_comma.h @@ -0,0 +1,37 @@ +/** + * 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_EXPECTED_COMMA_H +#define FIX_EXPECTED_COMMA_H + +#include "lsp/include/services/text_change/change_tracker.h" +#include "lsp/include/code_fixes/code_fix_types.h" +#include "lsp/include/types.h" +#include "lsp/include/api.h" + +namespace ark::es2panda::lsp { + +class FixExpectedComma : public CodeFixRegistration { +public: + FixExpectedComma(); + std::vector GetCodeActions(const CodeFixContext &context) override; + CombinedCodeActions GetAllCodeActions(const CodeFixAllContext &codeFixAll) override; + static std::vector GetCodeActionsToFix(const CodeFixContext &context); + static ir::AstNode *GetNodeAtLocation(es2panda_Context *context, Range range); + static void MakeChange(ChangeTracker &changeTracker, es2panda_Context *context, Range range, + const std::string &possibleFix); +}; +} // namespace ark::es2panda::lsp +#endif // FIX_EXPECTED_COMMA_H diff --git a/ets2panda/lsp/src/register_code_fix/fix_expected_comma.cpp b/ets2panda/lsp/src/register_code_fix/fix_expected_comma.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e37751fd2d974f97bc9f51a3a67aeac131e99d1f --- /dev/null +++ b/ets2panda/lsp/src/register_code_fix/fix_expected_comma.cpp @@ -0,0 +1,105 @@ +/** + * 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/internal_api.h" +#include "lsp/include/code_fix_provider.h" +#include "lsp/include/register_code_fix/fix_expected_comma.h" + +namespace ark::es2panda::lsp { +const int G_FIX_EXPECTED_COMMA = 1016; + +void FixExpectedComma::MakeChange(ChangeTracker &changeTracker, es2panda_Context *context, Range range, + const std::string &possibleFix) +{ + if (possibleFix.empty()) { + return; + } + + auto node = GetNodeAtLocation(context, range); + if (node == nullptr) { + return; + } + + if (node->Parent()->IsObjectExpression() && node->IsProperty()) { + changeTracker.ReplaceNodeWithText(context, node->Parent(), possibleFix); + } +} + +ir::AstNode *FixExpectedComma::GetNodeAtLocation(es2panda_Context *context, Range range) +{ + auto *ctx = reinterpret_cast(context); + auto ast = ctx->parserProgram->Ast(); + auto nodeAtLocation = + ast->FindChild([&range](ir::AstNode *node) { return node->Range().start.line == range.start.line_; }); + + return nodeAtLocation; +} + +std::vector FixExpectedComma::GetCodeActionsToFix(const CodeFixContext &context) +{ + CodeFixProvider provider; + auto diagnostics = provider.GetDiagnostics(context); + TextChangesContext textChangesContext = {context.host, context.formatContext, context.preferences}; + std::vector fileTextChanges; + + for (auto &diag : diagnostics->diagnostic) { + auto code = std::get(diag.code_); + if (code != G_FIX_EXPECTED_COMMA) { + continue; + } + + auto changes = ChangeTracker::With(textChangesContext, [&](ChangeTracker &tracker) { + MakeChange(tracker, context.context, diag.range_, diag.source_); + }); + + fileTextChanges.insert(fileTextChanges.end(), changes.begin(), changes.end()); + } + + return fileTextChanges; +} + +FixExpectedComma::FixExpectedComma() +{ + const char *fixId = "FixExpectedComma"; + SetErrorCodes({G_FIX_EXPECTED_COMMA}); + SetFixIds({fixId}); +} + +std::vector FixExpectedComma::GetCodeActions(const CodeFixContext &context) +{ + std::vector returnedActions; + + auto changes = GetCodeActionsToFix(context); + if (!changes.empty()) { + CodeFixAction codeAction; + codeAction.fixName = "fixExpectedComma"; + codeAction.description = "Use comma instead of semicolon at possition"; + codeAction.changes = changes; + codeAction.fixId = "FixExpectedComma"; + returnedActions.push_back(codeAction); + } + + return returnedActions; +} + +CombinedCodeActions FixExpectedComma::GetAllCodeActions(const CodeFixAllContext &codeFixAll) +{ + std::vector fixedNodes; + CodeFixProvider provider; + + return provider.GetAllFixes(codeFixAll); +} +// NOLINTNEXTLINE(fuchsia-statically-constructed-objects, cert-err58-cpp) +} // namespace ark::es2panda::lsp diff --git a/ets2panda/test/unit/lsp/CMakeLists.txt b/ets2panda/test/unit/lsp/CMakeLists.txt index 06df7356e7ca56749ff9627c3445c18711ba02a4..b71f0e88e39b45ef089c1de37b659e15f7215b48 100644 --- a/ets2panda/test/unit/lsp/CMakeLists.txt +++ b/ets2panda/test/unit/lsp/CMakeLists.txt @@ -208,6 +208,10 @@ ets2panda_add_gtest(lsp_api_test_find_rename_locations CPP_SOURCES find_rename_locations_test.cpp ) +ets2panda_add_gtest(lsp_api_test_fix_expected_comma CPP_SOURCES + fix_expected_comma_test.cpp + ) + ets2panda_add_gtest(lsp_api_test_change_tracker CPP_SOURCES change_tracker_test.cpp ) diff --git a/ets2panda/test/unit/lsp/fix_expected_comma_test.cpp b/ets2panda/test/unit/lsp/fix_expected_comma_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7723cf669de8a8e3c22f0903da0c6ada21359279 --- /dev/null +++ b/ets2panda/test/unit/lsp/fix_expected_comma_test.cpp @@ -0,0 +1,83 @@ +/** + * 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 "gtest/gtest.h" +#include "lsp/include/code_fixes/code_fix_types.h" +#include "lsp/include/register_code_fix/fix_expected_comma.h" +#include "lsp/include/internal_api.h" +#include "public/es2panda_lib.h" +#include "lsp_api_test.h" + +namespace { +constexpr int DEFAULT_THROTTLE = 20; +const size_t GETTER_CALL_IDX = 92; + +class FixExpectedCommaTests : public LSPAPITests { +public: + class NullCancellationToken : public ark::es2panda::lsp::HostCancellationToken { + public: + bool IsCancellationRequested() override + { + return false; + } + }; + + static ark::es2panda::lsp::CancellationToken CreateToken() + { + static NullCancellationToken nullToken; + return ark::es2panda::lsp::CancellationToken(DEFAULT_THROTTLE, &nullToken); + } + + static ark::es2panda::lsp::CodeFixContext CreateCodeFixContext(es2panda_Context *ctx, size_t pos) + { + ark::es2panda::lsp::RulesMap rules; + ark::es2panda::lsp::FormatCodeSettings formatSettings; + ark::es2panda::lsp::UserPreferences preferences; + LanguageServiceHost host; + ark::es2panda::lsp::FormatContext fmtCtx {formatSettings, rules}; + TextChangesContext textCtx {host, fmtCtx, preferences}; + return ark::es2panda::lsp::CodeFixContext {{textCtx, ctx, CreateToken()}, 0, TextSpan {pos, 0}}; + } +}; + +TEST_F(FixExpectedCommaTests, FixObjectExpression) +{ + ark::es2panda::lsp::Initializer initializer; + const std::string sourceCode = R"( +interface A { +name: string; +age: number; +} +const a: A = { +name: "foo"; +age: 123; +} + )"; + + const auto c1 = 1; + const auto textChange = R"({ + name: "foo", + age: 123, +})"; + es2panda_Context *ctx = + initializer.CreateContext("fec_fix_object_expression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + ark::es2panda::lsp::FixExpectedComma fix; + ark::es2panda::lsp::CodeFixContext context = CreateCodeFixContext(ctx, GETTER_CALL_IDX); + auto actions = fix.GetCodeActions(context); + ASSERT_EQ(actions.size(), c1); + ASSERT_EQ(actions[0].changes[0].textChanges[0].newText, textChange); + initializer.DestroyContext(ctx); +} +} // namespace diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 9a9440342d68c36cb550610b74158cd609639d22..87f665e708e80df5f93aea26948e7b9ed2dc8e89 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1149,6 +1149,7 @@ syntax: - name: UNEXPECTED_TOKEN id: 16 message: "Unexpected token." + code_fix_ids: [FixExpectedToken] - name: UNEXPECTED_TOKEN_AS id: 95