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