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