1 //===--- InitVariablesCheck.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 "InitVariablesCheck.h" 10 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 namespace { 21 AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); } 22 } // namespace 23 24 InitVariablesCheck::InitVariablesCheck(StringRef Name, 25 ClangTidyContext *Context) 26 : ClangTidyCheck(Name, Context), 27 IncludeStyle(utils::IncludeSorter::parseIncludeStyle( 28 Options.getLocalOrGlobal("IncludeStyle", "llvm"))), 29 MathHeader(Options.get("MathHeader", "math.h")) {} 30 31 void InitVariablesCheck::registerMatchers(MatchFinder *Finder) { 32 std::string BadDecl = "badDecl"; 33 Finder->addMatcher( 34 varDecl(unless(hasInitializer(anything())), unless(isInstantiated()), 35 isLocalVarDecl(), unless(isStaticLocal()), isDefinition(), 36 optionally(hasParent(declStmt(hasParent( 37 cxxForRangeStmt(hasLoopVariable(varDecl().bind(BadDecl))))))), 38 unless(equalsBoundNode(BadDecl))) 39 .bind("vardecl"), 40 this); 41 } 42 43 void InitVariablesCheck::registerPPCallbacks(const SourceManager &SM, 44 Preprocessor *PP, 45 Preprocessor *ModuleExpanderPP) { 46 IncludeInserter = 47 std::make_unique<utils::IncludeInserter>(SM, getLangOpts(), IncludeStyle); 48 PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks()); 49 } 50 51 void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) { 52 const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("vardecl"); 53 const ASTContext &Context = *Result.Context; 54 const SourceManager &Source = Context.getSourceManager(); 55 56 // We want to warn about cases where the type name 57 // comes from a macro like this: 58 // 59 // TYPENAME_FROM_MACRO var; 60 // 61 // but not if the entire declaration comes from 62 // one: 63 // 64 // DEFINE_SOME_VARIABLE(); 65 // 66 // or if the definition comes from a macro like SWAP 67 // that uses an internal temporary variable. 68 // 69 // Thus check that the variable name does 70 // not come from a macro expansion. 71 if (MatchedDecl->getEndLoc().isMacroID()) 72 return; 73 74 QualType TypePtr = MatchedDecl->getType(); 75 const char *InitializationString = nullptr; 76 bool AddMathInclude = false; 77 78 if (TypePtr->isIntegerType()) 79 InitializationString = " = 0"; 80 else if (TypePtr->isFloatingType()) { 81 InitializationString = " = NAN"; 82 AddMathInclude = true; 83 } else if (TypePtr->isAnyPointerType()) { 84 if (getLangOpts().CPlusPlus11) 85 InitializationString = " = nullptr"; 86 else 87 InitializationString = " = NULL"; 88 } 89 90 if (InitializationString) { 91 auto Diagnostic = 92 diag(MatchedDecl->getLocation(), "variable %0 is not initialized") 93 << MatchedDecl 94 << FixItHint::CreateInsertion( 95 MatchedDecl->getLocation().getLocWithOffset( 96 MatchedDecl->getName().size()), 97 InitializationString); 98 if (AddMathInclude) { 99 auto IncludeHint = IncludeInserter->CreateIncludeInsertion( 100 Source.getFileID(MatchedDecl->getBeginLoc()), MathHeader, false); 101 if (IncludeHint) 102 Diagnostic << *IncludeHint; 103 } 104 } 105 } 106 107 } // namespace cppcoreguidelines 108 } // namespace tidy 109 } // namespace clang 110