• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /**
3  * Copyright (c) 2025 Huawei Device Co., Ltd.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "lsp/include/register_code_fix/fix_nan_equality.h"
18 #include <iostream>
19 #include <string>
20 #include "lsp/include/code_fix_provider.h"
21 #include "lsp/include/internal_api.h"
22 
23 namespace ark::es2panda::lsp {
24 
25 const int G_FIX_NAN_EQUALITY_CODE = 1003;  // change this to the error code you want to handle
26 
MakeChangeForNaNEquality(ChangeTracker & changeTracker,es2panda_Context * context,size_t pos,std::vector<ark::es2panda::ir::AstNode * > & fixedNodes)27 void FixNaNEquality::MakeChangeForNaNEquality(ChangeTracker &changeTracker, es2panda_Context *context, size_t pos,
28                                               std::vector<ark::es2panda::ir::AstNode *> &fixedNodes)
29 {
30     auto *token = GetTouchingToken(context, pos, false);
31     if (token == nullptr || !token->IsBinaryExpression()) {
32         return;
33     }
34 
35     const auto *binaryExpr = token->AsBinaryExpression();
36     if (binaryExpr->Left() == nullptr || binaryExpr->Right() == nullptr) {
37         return;
38     }
39 
40     auto isLeftNaN = binaryExpr->Left()->IsIdentifier() && binaryExpr->Left()->AsIdentifier()->Name() == "NaN";
41     auto isRightNaN = binaryExpr->Right()->IsIdentifier() && binaryExpr->Right()->AsIdentifier()->Name() == "NaN";
42     if (!isLeftNaN && !isRightNaN) {
43         return;
44     }
45 
46     auto *expr = isLeftNaN ? binaryExpr->Right() : binaryExpr->Left();
47     std::string exprText = expr->ToString();
48     std::string newText;
49 
50     if (binaryExpr->Type() == ir::AstNodeType::TS_IMPORT_EQUALS_DECLARATION) {
51         newText = "Number.isNaN(" + exprText + ")";
52     } else {
53         return;
54     }
55 
56     // auto *ctx = reinterpret_cast<ark::es2panda::public_lib::Context *>(context);
57 
58     fixedNodes.push_back(const_cast<ir::AstNode *>(token));
59     // ark::es2panda::ir::AstNode *bClone = token->Clone(ctx->allocator, nullptr);
60 
61     ChangeNodeOptions changeNodeOptions;
62     changeNodeOptions.insertNodeOptions->prefix = "";
63     changeNodeOptions.insertNodeOptions->suffix = "";
64     changeNodeOptions.insertNodeOptions->delta = 0;
65 
66     ark::es2panda::lsp::ChangeNodeOptions options = {};
67     changeTracker.ReplaceNode(context, token, token, changeNodeOptions);
68 }
69 
GetCodeActionsToFixNaNEquality(const CodeFixContext & context)70 std::vector<FileTextChanges> FixNaNEquality::GetCodeActionsToFixNaNEquality(const CodeFixContext &context)
71 {
72     TextChangesContext textChangesContext = {context.host, context.formatContext, context.preferences};
73     std::vector<ir::AstNode *> fixedNodes;
74     auto fileTextChanges = ChangeTracker::With(textChangesContext, [&](ChangeTracker &tracker) {
75         MakeChangeForNaNEquality(tracker, context.context, context.span.start, fixedNodes);
76     });
77 
78     return fileTextChanges;
79 }
80 
FixNaNEquality()81 FixNaNEquality::FixNaNEquality()
82 {
83     const char *fixNanEqualityId = "FixNaNEquality";
84     SetErrorCodes({G_FIX_NAN_EQUALITY_CODE});  // "NaN comparison" error code
85     SetFixIds({fixNanEqualityId});             // "fixNaNEquality" fix ID
86 }
87 
GetCodeActions(const CodeFixContext & context)88 std::vector<CodeFixAction> FixNaNEquality::GetCodeActions(const CodeFixContext &context)
89 {
90     std::vector<CodeFixAction> returnedActions;
91     auto changes = GetCodeActionsToFixNaNEquality(context);
92     if (!changes.empty()) {
93         CodeFixAction codeAction;
94         codeAction.fixName = "fixNaNEquality";
95         codeAction.description = "Use Number.isNaN instead of comparing with NaN";
96         codeAction.changes = changes;
97         codeAction.fixId = "FixNaNEquality";
98         codeAction.fixAllDescription = "Replace all NaN equality comparisons";
99         returnedActions.push_back(codeAction);
100     }
101     return returnedActions;
102 }
103 
GetAllCodeActions(const CodeFixAllContext & codeFixAll)104 CombinedCodeActions FixNaNEquality::GetAllCodeActions(const CodeFixAllContext &codeFixAll)
105 {
106     const std::vector<ir::AstNode *> fixedNodes;
107     CodeFixProvider provider;
108 
109     const auto changes = provider.CodeFixAll(
110         codeFixAll, GetErrorCodes(), [&](ChangeTracker &tracker, const DiagnosticWithLocation &diag) {
111             Initializer initializer = Initializer();
112             auto ctx =
113                 initializer.CreateContext(diag.file.source.data(), ES2PANDA_STATE_CHECKED, diag.file.source.data());
114             MakeChangeForNaNEquality(tracker, ctx, diag.start, const_cast<std::vector<ir::AstNode *> &>(fixedNodes));
115             initializer.DestroyContext(ctx);
116         });
117 
118     CombinedCodeActions combinedCodeActions;
119     combinedCodeActions.changes = changes.changes;
120     combinedCodeActions.commands = changes.commands;
121     return combinedCodeActions;
122 }
123 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects, cert-err58-cpp)
124 AutoCodeFixRegister<FixNaNEquality> g_fixNaNEquality("FixNaNEquality");
125 }  // namespace ark::es2panda::lsp
126