• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 #ifndef ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
17 #define ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
18 
19 #include <algorithm>
20 #include <iterator>
21 #include <regex>
22 #include <string>
23 #include <unordered_set>
24 
25 #include "ast_verifier/checkContext.h"
26 
27 #include "ir/astNode.h"
28 #include "ir/statements/blockStatement.h"
29 #include "lexer/token/sourceLocation.h"
30 #include "parser/program/program.h"
31 #include "util/ustring.h"
32 #include "utils/arena_containers.h"
33 #include "varbinder/variable.h"
34 
35 namespace ark::es2panda::compiler::ast_verifier {
36 
37 using InvariantCheck = std::function<CheckResult(CheckContext &ctx, const ir::AstNode *)>;
38 using Invariants = std::map<std::string, InvariantCheck>;
39 
40 using InvariantNameSet = std::set<std::string>;
41 
42 class VerificationContext final {
43 public:
IntroduceNewInvariants(util::StringView phaseName)44     void IntroduceNewInvariants(util::StringView phaseName)
45     {
46         if (phaseName == "ScopesInitPhase") {
47             accumulatedChecks_.insert("NodeHasParentForAll");
48             accumulatedChecks_.insert("NodeHasSourceRangeForAll");
49             accumulatedChecks_.insert("EveryChildHasValidParentForAll");
50             accumulatedChecks_.insert("EveryChildInParentRangeForAll");
51             accumulatedChecks_.insert("VariableHasScopeForAll");
52         }
53         if (phaseName == "CheckerPhase") {
54             accumulatedChecks_.insert("NodeHasTypeForAll");
55             accumulatedChecks_.insert("IdentifierHasVariableForAll");
56             accumulatedChecks_.insert("ReferenceTypeAnnotationIsNullForAll");
57             accumulatedChecks_.insert("ArithmeticOperationValidForAll");
58             accumulatedChecks_.insert("SequenceExpressionHasLastTypeForAll");
59             accumulatedChecks_.insert("CheckInfiniteLoopForAll");
60             accumulatedChecks_.insert("ForLoopCorrectlyInitializedForAll");
61             accumulatedChecks_.insert("VariableHasEnclosingScopeForAll");
62             accumulatedChecks_.insert("ModifierAccessValidForAll");
63             accumulatedChecks_.insert("ImportExportAccessValid");
64             accumulatedChecks_.insert("VariableNameIdentifierNameSameForAll");
65             accumulatedChecks_.insert("CheckAbstractMethodForAll");
66             accumulatedChecks_.insert("GetterSetterValidationForAll");
67             accumulatedChecks_.insert("CheckScopeDeclarationForAll");
68             accumulatedChecks_.insert("CheckConstPropertiesForAll");
69         }
70     }
71 
AccumulatedChecks()72     const InvariantNameSet &AccumulatedChecks() const
73     {
74         return accumulatedChecks_;
75     }
76 
77 private:
78     InvariantNameSet accumulatedChecks_ {};
79 };
80 
81 /*
82  * ASTVerifier used for checking various invariants that should hold during AST transformation in lowerings
83  * For all available checks lookup the constructor
84  */
85 class ASTVerifier final {
86 public:
87     NO_COPY_SEMANTIC(ASTVerifier);
88     NO_MOVE_SEMANTIC(ASTVerifier);
89 
90     explicit ASTVerifier(ArenaAllocator *allocator);
91     ~ASTVerifier() = default;
92 
93     /**
94      * @brief Run all existing invariants on some ast node (and consequently it's children)
95      * @param ast AstNode which will be analyzed
96      * @return Messages report of analysis
97      */
98     Messages VerifyFull(const ir::AstNode *ast);
99 
100     /**
101      * @brief Run some particular invariants on some ast node
102      * @note invariants must be supplied as strings to invariant_set, additionally invariant
103      * name can be suffixed by `ForAll` string to include recursive analysis of provided node
104      * I.e. 'HasParent' invariant can be named 'HasParentRecursive' to traverse all child nodes as well
105      * @param ast AstNode which will be analyzed
106      * @param invariantSet Set of invariants to check
107      * @return Messages report of analysis
108      */
109     Messages Verify(const ir::AstNode *ast, const InvariantNameSet &invariantSet);
110 
111 private:
112     static constexpr const char *RECURSIVE_SUFFIX = "ForAll";
113 
RecursiveInvariant(const InvariantCheck & func)114     static InvariantCheck RecursiveInvariant(const InvariantCheck &func)
115     {
116         return [func](CheckContext &ctx, const ir::AstNode *ast) -> CheckResult {
117             std::function<void(const ir::AstNode *)> aux;
118             auto finalDecision = CheckDecision::CORRECT;
119             aux = [&ctx, func, &aux, &finalDecision](const ir::AstNode *child) -> void {
120                 const auto [decision, action] = func(ctx, child);
121                 if (decision == CheckDecision::INCORRECT) {
122                     finalDecision = CheckDecision::INCORRECT;
123                 }
124                 if (action == CheckAction::SKIP_SUBTREE) {
125                     return;
126                 }
127                 child->Iterate(aux);
128             };
129             aux(ast);
130             return {finalDecision, CheckAction::CONTINUE};
131         };
132     }
133 
134     template <typename T>
AddInvariant(ArenaAllocator * allocator,const std::string & name)135     void AddInvariant(ArenaAllocator *allocator, const std::string &name)
136     {
137         auto check = *allocator->New<T>(*allocator);
138         invariantsChecks_[name] = check;
139         invariantsNames_.insert(name);
140         invariantsChecks_[name + RECURSIVE_SUFFIX] = RecursiveInvariant(check);
141         invariantsNames_.insert(name + RECURSIVE_SUFFIX);
142     }
143 
144     Invariants invariantsChecks_;
145     InvariantNameSet invariantsNames_;
146 };
147 
148 }  // namespace ark::es2panda::compiler::ast_verifier
149 
150 #endif  // ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
151