1 //===--- InitVariablesCheck.cpp - clang-tidy ------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "InitVariablesCheck.h"
11 #include "../utils/LexerUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/Type.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Lex/Preprocessor.h"
18 using namespace clang::ast_matchers
;
20 namespace clang::tidy::cppcoreguidelines
{
23 AST_MATCHER(VarDecl
, isLocalVarDecl
) { return Node
.isLocalVarDecl(); }
26 InitVariablesCheck::InitVariablesCheck(StringRef Name
,
27 ClangTidyContext
*Context
)
28 : ClangTidyCheck(Name
, Context
),
29 IncludeInserter(Options
.getLocalOrGlobal("IncludeStyle",
30 utils::IncludeSorter::IS_LLVM
),
31 areDiagsSelfContained()),
32 MathHeader(Options
.get("MathHeader", "<math.h>")) {}
34 void InitVariablesCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
35 Options
.store(Opts
, "IncludeStyle", IncludeInserter
.getStyle());
36 Options
.store(Opts
, "MathHeader", MathHeader
);
39 void InitVariablesCheck::registerMatchers(MatchFinder
*Finder
) {
40 std::string BadDecl
= "badDecl";
42 varDecl(unless(hasInitializer(anything())), unless(isInstantiated()),
43 isLocalVarDecl(), unless(isStaticLocal()), isDefinition(),
44 unless(hasParent(cxxCatchStmt())),
45 optionally(hasParent(declStmt(hasParent(
46 cxxForRangeStmt(hasLoopVariable(varDecl().bind(BadDecl
))))))),
47 unless(equalsBoundNode(BadDecl
)))
52 void InitVariablesCheck::registerPPCallbacks(const SourceManager
&SM
,
54 Preprocessor
*ModuleExpanderPP
) {
55 IncludeInserter
.registerPreprocessor(PP
);
58 void InitVariablesCheck::check(const MatchFinder::MatchResult
&Result
) {
59 const auto *MatchedDecl
= Result
.Nodes
.getNodeAs
<VarDecl
>("vardecl");
60 const ASTContext
&Context
= *Result
.Context
;
61 const SourceManager
&Source
= Context
.getSourceManager();
63 // Clang diagnostic error may cause the variable to be an invalid int vardecl
64 if (MatchedDecl
->isInvalidDecl())
67 // We want to warn about cases where the type name
68 // comes from a macro like this:
70 // TYPENAME_FROM_MACRO var;
72 // but not if the entire declaration comes from
75 // DEFINE_SOME_VARIABLE();
77 // or if the definition comes from a macro like SWAP
78 // that uses an internal temporary variable.
80 // Thus check that the variable name does
81 // not come from a macro expansion.
82 if (MatchedDecl
->getEndLoc().isMacroID())
85 QualType TypePtr
= MatchedDecl
->getType();
86 std::optional
<const char *> InitializationString
;
87 bool AddMathInclude
= false;
89 if (TypePtr
->isEnumeralType())
90 InitializationString
= nullptr;
91 else if (TypePtr
->isBooleanType())
92 InitializationString
= " = false";
93 else if (TypePtr
->isIntegerType())
94 InitializationString
= " = 0";
95 else if (TypePtr
->isFloatingType()) {
96 InitializationString
= " = NAN";
97 AddMathInclude
= true;
98 } else if (TypePtr
->isAnyPointerType()) {
99 if (getLangOpts().CPlusPlus11
)
100 InitializationString
= " = nullptr";
102 InitializationString
= " = NULL";
105 if (InitializationString
) {
107 diag(MatchedDecl
->getLocation(), "variable %0 is not initialized")
109 if (*InitializationString
!= nullptr)
110 Diagnostic
<< FixItHint::CreateInsertion(
111 utils::lexer::findNextTerminator(MatchedDecl
->getLocation(),
112 *Result
.SourceManager
,
113 Result
.Context
->getLangOpts()),
114 *InitializationString
);
115 if (AddMathInclude
) {
116 Diagnostic
<< IncludeInserter
.createIncludeInsertion(
117 Source
.getFileID(MatchedDecl
->getBeginLoc()), MathHeader
);
121 } // namespace clang::tidy::cppcoreguidelines