• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 #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/invariantBase.h"
26 #include "ast_verifier/invariants/sequenceExpressionHasLastType.h"
27 #include "ast_verifier/invariants/checkAbstractMethod.h"
28 #include "ast_verifier/invariants/everyChildHasValidParent.h"
29 #include "ast_verifier/invariants/everyChildInParentRange.h"
30 #include "ast_verifier/invariants/getterSetterValidation.h"
31 #include "ast_verifier/invariants/identifierHasVariable.h"
32 #include "ast_verifier/invariants/nodeHasParent.h"
33 #include "ast_verifier/invariants/nodeHasSourceRange.h"
34 #include "ast_verifier/invariants/nodeHasType.h"
35 #include "ast_verifier/invariants/referenceTypeAnnotationIsNull.h"
36 #include "ast_verifier/invariants/variableHasScope.h"
37 #include "ast_verifier/invariants/variableHasEnclosingScope.h"
38 #include "ast_verifier/invariants/forLoopCorrectlyInitialized.h"
39 #include "ast_verifier/invariants/modifierAccessValid.h"
40 #include "ast_verifier/invariants/importExportAccessValid.h"
41 #include "ast_verifier/invariants/arithmeticOperationValid.h"
42 #include "ast_verifier/invariants/variableNameIdentifierNameSame.h"
43 #include "ast_verifier/invariants/checkScopeDeclaration.h"
44 #include "ast_verifier/invariants/checkStructDeclaration.h"
45 #include "ast_verifier/invariants/checkConstProperties.h"
46 
47 #include "ir/astNode.h"
48 #include "ir/statements/blockStatement.h"
49 #include "lexer/token/sourceLocation.h"
50 #include "parser/program/program.h"
51 #include "util/ustring.h"
52 #include "util/options.h"
53 #include "utils/arena_containers.h"
54 #include "varbinder/variable.h"
55 #include "public/public.h"
56 
57 #ifdef ASTV_ENABLE_LOGGING
58 // CC-OFFNXT(G.PRE.02) macro to enable conditionally
59 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
60 #define LOG_ASTV(lvl, msg) LOG(lvl, ES2PANDA) << "[ASTV] " << msg
61 #else
62 // CC-OFFNXT(G.PRE.02) macro to enable conditionally
63 #define LOG_ASTV(lvl, msg)
64 #endif  // ASTV_ENABLE_LOGGING
65 
66 namespace ark::es2panda::compiler::ast_verifier {
67 
68 // NOTE(dkofanov) Fix and enable ImportExportAccessValid:
69 using InvariantsRegistry =
70     InvariantsRegistryImpl<NodeHasParent, NodeHasSourceRange, EveryChildHasValidParent, EveryChildInParentRange,
71                            CheckStructDeclaration, VariableHasScope, NodeHasType, NoPrimitiveTypes,
72                            IdentifierHasVariable, ReferenceTypeAnnotationIsNull, ArithmeticOperationValid,
73                            SequenceExpressionHasLastType, ForLoopCorrectlyInitialized, VariableHasEnclosingScope,
74                            ModifierAccessValid, VariableNameIdentifierNameSame, CheckAbstractMethod,
75                            GetterSetterValidation, CheckScopeDeclaration, CheckConstProperties>;
76 
77 /*
78  * ASTVerifier checks whether various conditions are invariant (across AST transformations).
79  */
80 class ASTVerifier : public InvariantsRegistry {
81 public:
82     NO_COPY_SEMANTIC(ASTVerifier);
83     NO_MOVE_SEMANTIC(ASTVerifier);
84 
ASTVerifier(const public_lib::Context & context,const parser::Program & program)85     ASTVerifier(const public_lib::Context &context, const parser::Program &program)
86         : program_ {program}, context_ {context}
87     {
88         for (size_t i = VerifierInvariants::BASE_FIRST; i <= VerifierInvariants::BASE_LAST; i++) {
89             allowed_[i] = true;
90         }
91         for (size_t i = 0; i < VerifierInvariants::COUNT; i++) {
92             enabled_[i] = TreatAsWarning(VerifierInvariants {i}) || TreatAsError(VerifierInvariants {i});
93         }
94     }
95 
~ASTVerifier()96     ~ASTVerifier()
97     {
98         ES2PANDA_ASSERT(!HasErrors());
99         ES2PANDA_ASSERT(!HasWarnings());
100     }
101 
After()102     void After()
103     {
104         if (Options().IsAstVerifierAfterPhases()) {
105             Verify("after");
106         }
107         if (!suppressed_ && (HasErrors() || HasWarnings())) {
108             DumpMessages();
109             hasErrors_ = false;
110             hasWarnings_ = false;
111         }
112     }
113 
Before()114     void Before()
115     {
116         if (Options().IsAstVerifierBeforePhases()) {
117             Verify("before");
118         }
119     }
120 
121     void Verify(std::string_view phaseName) noexcept;
122 
IntroduceNewInvariants(std::string_view occurredPhaseName)123     void IntroduceNewInvariants(std::string_view occurredPhaseName)
124     {
125         if (occurredPhaseName == "plugins-after-parse") {
126             for (size_t i = VerifierInvariants::AFTER_PLUGINS_AFTER_PARSE_FIRST;
127                  i <= VerifierInvariants::AFTER_PLUGINS_AFTER_PARSE_LAST; i++) {
128                 allowed_[i] = true;
129             }
130         }
131         if (occurredPhaseName == "ScopesInitPhase") {
132             for (size_t i = VerifierInvariants::AFTER_SCOPES_INIT_PHASE_FIRST;
133                  i <= VerifierInvariants::AFTER_SCOPES_INIT_PHASE_LAST; i++) {
134                 allowed_[i] = true;
135             }
136         }
137         if (occurredPhaseName == "CheckerPhase") {
138             for (size_t i = VerifierInvariants::AFTER_CHECKER_PHASE_FIRST;
139                  i <= VerifierInvariants::AFTER_CHECKER_PHASE_LAST; i++) {
140                 allowed_[i] = true;
141             }
142             // NOTE(dkofanov): This should be called after "NumberLowering" phase:
143             Get<NoPrimitiveTypes>()->SetNumberLoweringOccured();
144         }
145         if (occurredPhaseName == "UnionLowering") {
146             Get<IdentifierHasVariable>()->SetUnionLoweringOccurred();
147         }
148     }
149 
Suppress()150     void Suppress()
151     {
152         suppressed_ = true;
153     }
154 
155     void DumpMessages() const;
156 
TreatAsWarning(VerifierInvariants id)157     bool TreatAsWarning(VerifierInvariants id) const
158     {
159         return Options().GetAstVerifierWarnings()[id];
160     }
TreatAsError(VerifierInvariants id)161     bool TreatAsError(VerifierInvariants id) const
162     {
163         return Options().GetAstVerifierErrors()[id];
164     }
HasErrors()165     bool HasErrors() const
166     {
167         return hasErrors_;
168     }
HasWarnings()169     bool HasWarnings() const
170     {
171         return hasWarnings_;
172     }
173 
174 private:
175     template <typename T, std::enable_if_t<std::is_base_of_v<InvariantMessages, T>, void *> = nullptr>
NeedCheckInvariant(const T &)176     bool NeedCheckInvariant(const T & /*unused*/)
177     {
178         return enabled_[T::ID] && allowed_[T::ID];
179     }
180 
Options()181     const util::Options &Options() const
182     {
183         return *context_.config->options;
184     }
185 
186 public:
187     using SourcePath = std::string_view;
188     using PhaseName = std::string_view;
189     using InvariantsMessages = std::map<VerifierInvariants, Messages>;
190     using WarningsErrors = std::map<std::string_view, InvariantsMessages>;
191     using SourceMessages = std::map<SourcePath, WarningsErrors>;
192     using GroupedMessages = std::vector<std::pair<PhaseName, SourceMessages>>;
193 
194 private:
195     const parser::Program &program_;
196     const public_lib::Context &context_;
197     InvArray<bool> enabled_ {};
198     InvArray<bool> allowed_ {};
199 
200     bool hasErrors_ {false};
201     bool hasWarnings_ {false};
202     bool suppressed_ {false};
203     GroupedMessages report_;
204 
205     struct SinglePassVerifier;
206 };
207 
208 }  // namespace ark::es2panda::compiler::ast_verifier
209 
210 #endif  // ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
211