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