• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-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 "identifierHasVariable.h"
17 #include "ir/base/scriptFunction.h"
18 #include "ir/expressions/memberExpression.h"
19 #include "ir/ts/tsEnumDeclaration.h"
20 
21 namespace ark::es2panda::compiler::ast_verifier {
22 
23 class IdentifierHasVariable::ExceptionsMatcher {
24 public:
ExceptionsMatcher(const IdentifierHasVariable * inv,const ir::Identifier * ast)25     ExceptionsMatcher(const IdentifierHasVariable *inv, const ir::Identifier *ast) : inv_(inv), ast_(ast) {}
Match()26     bool Match()
27     {
28         auto res = IsLengthProp() || IsEmptyName() || IsInObjectExpr() || IsInPackageDecl() || IsBuiltinType() ||
29                    IsUnionMemberAccess();
30         return res;
31     }
32 
33 private:
IsLengthProp()34     bool IsLengthProp()
35     {
36         return ast_->Parent() != nullptr && ast_->Parent()->IsMemberExpression() && ast_->Name().Is("length");
37     }
38 
IsEmptyName()39     bool IsEmptyName()
40     {
41         // NOTE(kkonkuznetsov): some identifiers have empty names
42         return ast_->Name().Empty();
43     }
44 
IsInObjectExpr()45     bool IsInObjectExpr()
46     {
47         // NOTE(kkonkuznetsov): object expressions
48         const auto *parent = ast_->Parent();
49         while (parent != nullptr) {
50             if (parent->IsObjectExpression()) {
51                 return true;
52             }
53 
54             parent = parent->Parent();
55         }
56         return false;
57     }
58 
IsInPackageDecl()59     bool IsInPackageDecl()
60     {
61         // NOTE(kkonkuznetsov): skip package declarations
62         const auto *parent = ast_->Parent();
63         while (parent != nullptr) {
64             if (parent->IsETSPackageDeclaration()) {
65                 return true;
66             }
67             parent = parent->Parent();
68         }
69         return false;
70     }
71 
IsBuiltinType()72     bool IsBuiltinType()
73     {
74         auto name = ast_->Name();
75         // NOTE(mmartin): find a better solution to handle utility type resolution
76         return name.Is(Signatures::PARTIAL_TYPE_NAME) || name.Is(Signatures::REQUIRED_TYPE_NAME) ||
77                name.Is(Signatures::READONLY_TYPE_NAME) || name.Is(Signatures::FIXED_ARRAY_TYPE_NAME) ||
78                name.Is(compiler::Signatures::ANY_TYPE_NAME);
79     }
80 
IsUnionMemberAccess()81     bool IsUnionMemberAccess()
82     {
83         return ast_->Parent() != nullptr && ast_->Parent()->IsMemberExpression() &&
84                ast_->Parent()->AsMemberExpression()->Object()->TsType()->IsETSUnionType() &&
85                !inv_->UnionLoweringOccurred();
86     }
87 
88 private:
89     const IdentifierHasVariable *inv_ {};
90     const ir::Identifier *ast_ {};
91 };
92 
operator ()(const ir::AstNode * ast)93 CheckResult IdentifierHasVariable::operator()(const ir::AstNode *ast)
94 {
95     if (ast->IsScriptFunction() && ast->AsScriptFunction()->IsExternal()) {
96         // Identifiers in external functions' definitions are not resolved, so skip it
97         ES2PANDA_ASSERT(!ast->AsScriptFunction()->IsExternalOverload());
98         return {CheckDecision::CORRECT, CheckAction::SKIP_SUBTREE};
99     }
100     if (!ast->IsIdentifier()) {
101         return {CheckDecision::CORRECT, CheckAction::CONTINUE};
102     }
103 
104     if (ast->AsIdentifier()->Variable() != nullptr) {
105         return {CheckDecision::CORRECT, CheckAction::CONTINUE};
106     }
107 
108     const auto *id = ast->AsIdentifier();
109     if (ExceptionsMatcher {this, id}.Match()) {
110         return {CheckDecision::CORRECT, CheckAction::CONTINUE};
111     }
112 
113     AddCheckMessage("NULL_VARIABLE", *id);
114     return {CheckDecision::INCORRECT, CheckAction::CONTINUE};
115 }
116 
117 }  // namespace ark::es2panda::compiler::ast_verifier
118