diff options
| author | Aaron Ballman <aaron@aaronballman.com> | 2019-10-02 17:18:57 +0000 |
|---|---|---|
| committer | Aaron Ballman <aaron@aaronballman.com> | 2019-10-02 17:18:57 +0000 |
| commit | b879fd05bd7628cfb27d8e127dc8751389dcd1d7 (patch) | |
| tree | 7ee81f7e1c5ba7aaa03d83f3972a2f0b6974e792 /clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp | |
| parent | eb6700b57e969e75014394a02e8130542f3f6457 (diff) | |
| download | bcm5719-llvm-b879fd05bd7628cfb27d8e127dc8751389dcd1d7.tar.gz bcm5719-llvm-b879fd05bd7628cfb27d8e127dc8751389dcd1d7.zip | |
Add the misc-init-local-variables check.
This checks finds all primitive type local variables (integers, doubles, pointers) that are declared without an initial value. Includes fixit functionality to initialize said variables with a default value. This is zero for most types and NaN for floating point types. The use of NaNs is copied from the D programming language.
Patch by Jussi Pakkanen.
llvm-svn: 373489
Diffstat (limited to 'clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp new file mode 100644 index 00000000000..8a628317a30 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp @@ -0,0 +1,105 @@ +//===--- InitVariablesCheck.cpp - clang-tidy ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InitVariablesCheck.h" + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +namespace { +AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); } +} // namespace + +InitVariablesCheck::InitVariablesCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + Options.getLocalOrGlobal("IncludeStyle", "llvm"))), + MathHeader(Options.get("MathHeader", "math.h")) {} + +void InitVariablesCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(varDecl(unless(hasInitializer(anything())), + unless(isInstantiated()), isLocalVarDecl(), + unless(isStaticLocal()), isDefinition()) + .bind("vardecl"), + this); +} + +void InitVariablesCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + IncludeInserter = + std::make_unique<utils::IncludeInserter>(SM, getLangOpts(), IncludeStyle); + PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks()); +} + +void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("vardecl"); + const ASTContext &Context = *Result.Context; + const SourceManager &Source = Context.getSourceManager(); + + // We want to warn about cases where the type name + // comes from a macro like this: + // + // TYPENAME_FROM_MACRO var; + // + // but not if the entire declaration comes from + // one: + // + // DEFINE_SOME_VARIABLE(); + // + // or if the definition comes from a macro like SWAP + // that uses an internal temporary variable. + // + // Thus check that the variable name does + // not come from a macro expansion. + if (MatchedDecl->getEndLoc().isMacroID()) + return; + + QualType TypePtr = MatchedDecl->getType(); + const char *InitializationString = nullptr; + bool AddMathInclude = false; + + if (TypePtr->isIntegerType()) + InitializationString = " = 0"; + else if (TypePtr->isFloatingType()) { + InitializationString = " = NAN"; + AddMathInclude = true; + } else if (TypePtr->isAnyPointerType()) { + if (getLangOpts().CPlusPlus11) + InitializationString = " = nullptr"; + else + InitializationString = " = NULL"; + } + + if (InitializationString) { + auto Diagnostic = + diag(MatchedDecl->getLocation(), "variable %0 is not initialized") + << MatchedDecl + << FixItHint::CreateInsertion( + MatchedDecl->getLocation().getLocWithOffset( + MatchedDecl->getName().size()), + InitializationString); + if (AddMathInclude) { + auto IncludeHint = IncludeInserter->CreateIncludeInsertion( + Source.getFileID(MatchedDecl->getBeginLoc()), MathHeader, false); + if (IncludeHint) + Diagnostic << *IncludeHint; + } + } +} + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang |

