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