1b879fd05SAaron Ballman //===--- InitVariablesCheck.cpp - clang-tidy ------------------------------===// 2b879fd05SAaron Ballman // 3b879fd05SAaron Ballman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b879fd05SAaron Ballman // See https://llvm.org/LICENSE.txt for license information. 5b879fd05SAaron Ballman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b879fd05SAaron Ballman // 7b879fd05SAaron Ballman //===----------------------------------------------------------------------===// 8b879fd05SAaron Ballman 9b879fd05SAaron Ballman #include "InitVariablesCheck.h" 10b879fd05SAaron Ballman 11*028ea71fSJulian Schmidt #include "../utils/LexerUtils.h" 12b879fd05SAaron Ballman #include "clang/AST/ASTContext.h" 13*028ea71fSJulian Schmidt #include "clang/AST/Type.h" 14b879fd05SAaron Ballman #include "clang/ASTMatchers/ASTMatchFinder.h" 15860aefd0SNathan James #include "clang/Lex/Preprocessor.h" 1671f55735SKazu Hirata #include <optional> 17b879fd05SAaron Ballman 18b879fd05SAaron Ballman using namespace clang::ast_matchers; 19b879fd05SAaron Ballman 207d2ea6c4SCarlos Galvez namespace clang::tidy::cppcoreguidelines { 21b879fd05SAaron Ballman 22b879fd05SAaron Ballman namespace { 23b879fd05SAaron Ballman AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); } 24b879fd05SAaron Ballman } // namespace 25b879fd05SAaron Ballman 26b879fd05SAaron Ballman InitVariablesCheck::InitVariablesCheck(StringRef Name, 27b879fd05SAaron Ballman ClangTidyContext *Context) 28b879fd05SAaron Ballman : ClangTidyCheck(Name, Context), 2913c9bbc2SNathan James IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", 30b859c39cSNathan James utils::IncludeSorter::IS_LLVM), 31b859c39cSNathan James areDiagsSelfContained()), 32fdfe324dSAlexander Kornienko MathHeader(Options.get("MathHeader", "<math.h>")) {} 33b879fd05SAaron Ballman 34db90d315SNathan James void InitVariablesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 3513c9bbc2SNathan James Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); 36db90d315SNathan James Options.store(Opts, "MathHeader", MathHeader); 37db90d315SNathan James } 38db90d315SNathan James 39b879fd05SAaron Ballman void InitVariablesCheck::registerMatchers(MatchFinder *Finder) { 40efcd09ceSNathan James std::string BadDecl = "badDecl"; 41efcd09ceSNathan James Finder->addMatcher( 42efcd09ceSNathan James varDecl(unless(hasInitializer(anything())), unless(isInstantiated()), 43efcd09ceSNathan James isLocalVarDecl(), unless(isStaticLocal()), isDefinition(), 44669494e9SNathan James unless(hasParent(cxxCatchStmt())), 45efcd09ceSNathan James optionally(hasParent(declStmt(hasParent( 46efcd09ceSNathan James cxxForRangeStmt(hasLoopVariable(varDecl().bind(BadDecl))))))), 47efcd09ceSNathan James unless(equalsBoundNode(BadDecl))) 48b879fd05SAaron Ballman .bind("vardecl"), 49b879fd05SAaron Ballman this); 50b879fd05SAaron Ballman } 51b879fd05SAaron Ballman 52b879fd05SAaron Ballman void InitVariablesCheck::registerPPCallbacks(const SourceManager &SM, 53b879fd05SAaron Ballman Preprocessor *PP, 54b879fd05SAaron Ballman Preprocessor *ModuleExpanderPP) { 5513c9bbc2SNathan James IncludeInserter.registerPreprocessor(PP); 56b879fd05SAaron Ballman } 57b879fd05SAaron Ballman 58b879fd05SAaron Ballman void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) { 59b879fd05SAaron Ballman const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("vardecl"); 60b879fd05SAaron Ballman const ASTContext &Context = *Result.Context; 61b879fd05SAaron Ballman const SourceManager &Source = Context.getSourceManager(); 62b879fd05SAaron Ballman 63ce6de98bSSockke // Clang diagnostic error may cause the variable to be an invalid int vardecl 64ce6de98bSSockke if (MatchedDecl->isInvalidDecl()) 65ce6de98bSSockke return; 66ce6de98bSSockke 67b879fd05SAaron Ballman // We want to warn about cases where the type name 68b879fd05SAaron Ballman // comes from a macro like this: 69b879fd05SAaron Ballman // 70b879fd05SAaron Ballman // TYPENAME_FROM_MACRO var; 71b879fd05SAaron Ballman // 72b879fd05SAaron Ballman // but not if the entire declaration comes from 73b879fd05SAaron Ballman // one: 74b879fd05SAaron Ballman // 75b879fd05SAaron Ballman // DEFINE_SOME_VARIABLE(); 76b879fd05SAaron Ballman // 77b879fd05SAaron Ballman // or if the definition comes from a macro like SWAP 78b879fd05SAaron Ballman // that uses an internal temporary variable. 79b879fd05SAaron Ballman // 80b879fd05SAaron Ballman // Thus check that the variable name does 81b879fd05SAaron Ballman // not come from a macro expansion. 82b879fd05SAaron Ballman if (MatchedDecl->getEndLoc().isMacroID()) 83b879fd05SAaron Ballman return; 84b879fd05SAaron Ballman 85b879fd05SAaron Ballman QualType TypePtr = MatchedDecl->getType(); 86f71ffd3bSKazu Hirata std::optional<const char *> InitializationString; 87b879fd05SAaron Ballman bool AddMathInclude = false; 88b879fd05SAaron Ballman 894a097efeSLiuke Gehry if (TypePtr->isEnumeralType()) 904a097efeSLiuke Gehry InitializationString = nullptr; 9133e21295SDanny Mösch else if (TypePtr->isBooleanType()) 9233e21295SDanny Mösch InitializationString = " = false"; 934a097efeSLiuke Gehry else if (TypePtr->isIntegerType()) 94b879fd05SAaron Ballman InitializationString = " = 0"; 95b879fd05SAaron Ballman else if (TypePtr->isFloatingType()) { 96b879fd05SAaron Ballman InitializationString = " = NAN"; 97b879fd05SAaron Ballman AddMathInclude = true; 98b879fd05SAaron Ballman } else if (TypePtr->isAnyPointerType()) { 99b879fd05SAaron Ballman if (getLangOpts().CPlusPlus11) 100b879fd05SAaron Ballman InitializationString = " = nullptr"; 101b879fd05SAaron Ballman else 102b879fd05SAaron Ballman InitializationString = " = NULL"; 103b879fd05SAaron Ballman } 104b879fd05SAaron Ballman 105b879fd05SAaron Ballman if (InitializationString) { 106b879fd05SAaron Ballman auto Diagnostic = 107b879fd05SAaron Ballman diag(MatchedDecl->getLocation(), "variable %0 is not initialized") 1084a097efeSLiuke Gehry << MatchedDecl; 1094a097efeSLiuke Gehry if (*InitializationString != nullptr) 1104a097efeSLiuke Gehry Diagnostic << FixItHint::CreateInsertion( 111*028ea71fSJulian Schmidt utils::lexer::findNextTerminator(MatchedDecl->getLocation(), 112*028ea71fSJulian Schmidt *Result.SourceManager, 113*028ea71fSJulian Schmidt Result.Context->getLangOpts()), 1144a097efeSLiuke Gehry *InitializationString); 115b879fd05SAaron Ballman if (AddMathInclude) { 11613c9bbc2SNathan James Diagnostic << IncludeInserter.createIncludeInsertion( 117fdfe324dSAlexander Kornienko Source.getFileID(MatchedDecl->getBeginLoc()), MathHeader); 118b879fd05SAaron Ballman } 119b879fd05SAaron Ballman } 120b879fd05SAaron Ballman } 1217d2ea6c4SCarlos Galvez } // namespace clang::tidy::cppcoreguidelines 122