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 traverse(TK_AsIs, varDecl(GlobalVarDecl, isDefinition(), 32 hasInitializer(expr(hasDescendant( 33 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