clang-tools 23.0.0git
InitVariablesCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10
11#include "../utils/LexerUtils.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/AST/StmtObjC.h"
14#include "clang/AST/Type.h"
15#include "clang/ASTMatchers/ASTMatchFinder.h"
16#include "clang/Lex/Preprocessor.h"
17#include <optional>
18
19using namespace clang::ast_matchers;
20
22
23namespace {
24AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); }
25AST_MATCHER(Stmt, isObjCForCollectionStmt) {
26 return isa<ObjCForCollectionStmt>(&Node);
27}
28} // namespace
29
31 ClangTidyContext *Context)
32 : ClangTidyCheck(Name, Context),
33 IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
34 utils::IncludeSorter::IS_LLVM),
35 areDiagsSelfContained()),
36 MathHeader(Options.get("MathHeader", "<math.h>")) {}
37
39 Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
40 Options.store(Opts, "MathHeader", MathHeader);
41}
42
43void InitVariablesCheck::registerMatchers(MatchFinder *Finder) {
44 const std::string BadDecl = "badDecl";
45 Finder->addMatcher(
46 varDecl(unless(hasInitializer(anything())), unless(isInstantiated()),
47 isLocalVarDecl(), unless(isStaticLocal()), isDefinition(),
48 unless(hasParent(cxxCatchStmt())),
49 unless(hasParent(declStmt(hasParent(isObjCForCollectionStmt())))),
50 optionally(hasParent(declStmt(hasParent(
51 cxxForRangeStmt(hasLoopVariable(varDecl().bind(BadDecl))))))),
52 unless(equalsBoundNode(BadDecl)))
53 .bind("vardecl"),
54 this);
55}
56
57void InitVariablesCheck::registerPPCallbacks(const SourceManager &SM,
58 Preprocessor *PP,
59 Preprocessor *ModuleExpanderPP) {
60 IncludeInserter.registerPreprocessor(PP);
61}
62
63void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) {
64 const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("vardecl");
65 const ASTContext &Context = *Result.Context;
66 const SourceManager &Source = Context.getSourceManager();
67
68 // Clang diagnostic error may cause the variable to be an invalid int vardecl
69 if (MatchedDecl->isInvalidDecl())
70 return;
71
72 // We want to warn about cases where the type name
73 // comes from a macro like this:
74 //
75 // TYPENAME_FROM_MACRO var;
76 //
77 // but not if the entire declaration comes from
78 // one:
79 //
80 // DEFINE_SOME_VARIABLE();
81 //
82 // or if the definition comes from a macro like SWAP
83 // that uses an internal temporary variable.
84 //
85 // Thus check that the variable name does
86 // not come from a macro expansion.
87 if (MatchedDecl->getEndLoc().isMacroID())
88 return;
89
90 const QualType TypePtr = MatchedDecl->getType();
91 std::optional<const char *> InitializationString;
92 bool AddMathInclude = false;
93
94 if (TypePtr->isEnumeralType()) {
95 InitializationString = nullptr;
96 } else if (TypePtr->isBooleanType()) {
97 InitializationString = " = false";
98 } else if (TypePtr->isIntegerType()) {
99 InitializationString = " = 0";
100 } else if (TypePtr->isFloatingType()) {
101 InitializationString = " = NAN";
102 AddMathInclude = true;
103 } else if (TypePtr->isAnyPointerType() || TypePtr->isMemberPointerType()) {
104 if (getLangOpts().CPlusPlus11)
105 InitializationString = " = nullptr";
106 else
107 InitializationString = " = NULL";
108 }
109
110 if (InitializationString) {
111 auto Diagnostic =
112 diag(MatchedDecl->getLocation(), "variable %0 is not initialized")
113 << MatchedDecl;
114 if (*InitializationString != nullptr)
115 Diagnostic << FixItHint::CreateInsertion(
116 utils::lexer::findNextTerminator(MatchedDecl->getEndLoc(),
117 *Result.SourceManager,
118 Result.Context->getLangOpts()),
119 *InitializationString);
120 if (AddMathInclude) {
121 Diagnostic << IncludeInserter.createIncludeInsertion(
122 Source.getFileID(MatchedDecl->getBeginLoc()), MathHeader);
123 }
124 }
125}
126} // namespace clang::tidy::cppcoreguidelines
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
InitVariablesCheck(StringRef Name, ClangTidyContext *Context)
AST_MATCHER(BinaryOperator, isRelationalOperator)
SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
llvm::StringMap< ClangTidyValue > OptionMap