• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <string>
17 #include <utility>
18 #include <vector>
19 #include "compiler/lowering/util.h"
20 #include "get_safe_delete_info.h"
21 #include "ir/astNode.h"
22 #include "internal_api.h"
23 #include "public/public.h"
24 #include "references.h"
25 
26 namespace {
27 constexpr size_t BUILTIN_TYPE_COUNT = 9;
28 constexpr std::array<const char *, BUILTIN_TYPE_COUNT> BUILTIN_TYPES = {
29     "Number", "String", "Boolean", "void", "BigInt", "Never", "undefined", "null", "Object"};
30 }  // namespace
31 
32 namespace ark::es2panda::lsp {
33 
IsBuiltinTypeReference(ir::AstNode * node)34 bool IsBuiltinTypeReference(ir::AstNode *node)
35 {
36     if (node == nullptr || node->Type() != ir::AstNodeType::IDENTIFIER) {
37         return false;
38     }
39     auto *parent = node->Parent();
40     while (parent != nullptr) {
41         if (parent->Type() == ir::AstNodeType::ETS_TYPE_REFERENCE_PART ||
42             parent->Type() == ir::AstNodeType::ETS_TYPE_REFERENCE) {
43             std::string nameStr(node->AsIdentifier()->Name());
44             auto it =
45                 std::find_if(BUILTIN_TYPES.begin(), BUILTIN_TYPES.end(), [&](const char *s) { return nameStr == s; });
46             if (it != BUILTIN_TYPES.end()) {
47                 return true;
48             }
49         }
50         parent = parent->Parent();
51     }
52     return false;
53 }
54 
IsDeletableDecl(ir::AstNode * node)55 bool IsDeletableDecl(ir::AstNode *node)
56 {
57     return node->IsFunctionDeclaration() || node->IsVariableDeclarator() || node->IsClassProperty() ||
58            node->Type() == ir::AstNodeType::METHOD_DEFINITION || node->Type() == ir::AstNodeType::CLASS_DECLARATION ||
59            node->IsTSTypeParameterDeclaration() || node->IsImportDefaultSpecifier() ||
60            node->Type() == ir::AstNodeType::ETS_TYPE_REFERENCE_PART || node->IsCallExpression() ||
61            node->IsETSImportDeclaration() || node->IsImportSpecifier() || node->IsBinaryExpression() ||
62            node->IsTSInterfaceDeclaration() || node->IsETSTypeReferencePart() || node->IsImportNamespaceSpecifier() ||
63            node->IsTSTypeAliasDeclaration() || node->IsExpressionStatement() || node->IsMemberExpression() ||
64            node->IsTypeofExpression();
65 }
66 
FindNearestDeletableDecl(ir::AstNode * node)67 ir::AstNode *FindNearestDeletableDecl(ir::AstNode *node)
68 {
69     ir::AstNode *cur = node;
70     while (cur != nullptr) {
71         if (IsDeletableDecl(cur)) {
72             return cur;
73         }
74         cur = cur->Parent();
75     }
76     return nullptr;
77 }
78 
NormalizeFilePath(const std::string & filePath)79 std::string NormalizeFilePath(const std::string &filePath)
80 {
81     std::string normPath = filePath;
82     std::transform(normPath.begin(), normPath.end(), normPath.begin(), ::tolower);
83     std::replace(normPath.begin(), normPath.end(), '\\', '/');
84     return normPath;
85 }
86 
87 /**
88  * Distinguish a namespace from a class by checking whether the class body contains only the $init$ method and has
89  * no constructor
90  */
IsNamespaceClass(ir::AstNode * astNode)91 bool IsNamespaceClass(ir::AstNode *astNode)
92 {
93     if (astNode->Type() != ir::AstNodeType::CLASS_DECLARATION) {
94         return false;
95     }
96     auto *classDecl = static_cast<ir::ClassDeclaration *>(astNode);
97     const auto &body = classDecl->Definition()->Body();
98     bool hasConstructor = false;
99     bool onlyInit = true;
100     for (auto *member : body) {
101         if (member->Type() == ir::AstNodeType::METHOD_DEFINITION) {
102             auto *method = static_cast<ir::MethodDefinition *>(member);
103             util::StringView keyName = method->Key()->AsIdentifier()->Name();
104             if (keyName == "constructor") {
105                 hasConstructor = true;
106             }
107             if (keyName != "_$init$_") {
108                 onlyInit = false;
109             }
110         }
111     }
112     return !hasConstructor && onlyInit;
113 }
114 
GetSafeDeleteInfoImpl(es2panda_Context * context,size_t position)115 bool GetSafeDeleteInfoImpl(es2panda_Context *context, size_t position)
116 {
117     auto astNode = GetTouchingToken(context, position, false);
118     if (astNode == nullptr) {
119         return false;
120     }
121 
122     auto declInfo = GetDeclInfoImpl(astNode);
123     auto fileName = std::get<0>(declInfo);
124     std::string normFileName = NormalizeFilePath(fileName);
125     if (!normFileName.empty() && normFileName.find("ets1.2/build-tools/ets2panda/lib/stdlib") != std::string::npos) {
126         return false;
127     }
128     if (!normFileName.empty() && normFileName.find("/sdk/") != std::string::npos) {
129         return false;
130     }
131 
132     if (IsBuiltinTypeReference(astNode)) {
133         return false;
134     }
135 
136     astNode = FindNearestDeletableDecl(astNode);
137     if (astNode == nullptr) {
138         return false;
139     }
140 
141     if (IsNamespaceClass(astNode)) {
142         return false;
143     }
144 
145     if (astNode->IsTSTypeParameterDeclaration()) {
146         return false;
147     }
148 
149     return true;
150 }
151 }  // namespace ark::es2panda::lsp
152