1 //===--- InterfacesGlobalInitCheck.cpp - clang-tidy------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "InterfacesGlobalInitCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang { 16 namespace tidy { 17 namespace cppcoreguidelines { 18 19 void InterfacesGlobalInitCheck::registerMatchers(MatchFinder *Finder) { 20 const auto GlobalVarDecl = 21 varDecl(hasGlobalStorage(), 22 hasDeclContext(anyOf(translationUnitDecl(), // Global scope. 23 namespaceDecl(), // Namespace scope. 24 recordDecl())), // Class scope. 25 unless(isConstexpr())); 26 27 const auto ReferencesUndefinedGlobalVar = declRefExpr(hasDeclaration( 28 varDecl(GlobalVarDecl, unless(isDefinition())).bind("referencee"))); 29 30 Finder->addMatcher( 31 varDecl(GlobalVarDecl, isDefinition(), 32 hasInitializer(expr(hasDescendant(ReferencesUndefinedGlobalVar)))) 33 .bind("var"), 34 this); 35 } 36 37 void InterfacesGlobalInitCheck::check(const MatchFinder::MatchResult &Result) { 38 const auto *const Var = Result.Nodes.getNodeAs<VarDecl>("var"); 39 // For now assume that people who write macros know what they're doing. 40 if (Var->getLocation().isMacroID()) 41 return; 42 const auto *const Referencee = Result.Nodes.getNodeAs<VarDecl>("referencee"); 43 // If the variable has been defined, we're good. 44 const auto *const ReferenceeDef = Referencee->getDefinition(); 45 if (ReferenceeDef != nullptr && 46 Result.SourceManager->isBeforeInTranslationUnit( 47 ReferenceeDef->getLocation(), Var->getLocation())) { 48 return; 49 } 50 diag(Var->getLocation(), 51 "initializing non-local variable with non-const expression depending on " 52 "uninitialized non-local variable %0") 53 << Referencee; 54 } 55 56 } // namespace cppcoreguidelines 57 } // namespace tidy 58 } // namespace clang 59