diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp new file mode 100644 index 00000000000..2c6f3b13fa7 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp @@ -0,0 +1,68 @@ +//===--- DynamicStaticInitializersCheck.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 "DynamicStaticInitializersCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +AST_MATCHER(clang::VarDecl, hasConstantDeclaration) { + const Expr *Init = Node.getInit(); + if (Init && !Init->isValueDependent()) { + if (Node.isConstexpr()) + return true; + return Node.checkInitIsICE(); + } + return false; +} + +DynamicStaticInitializersCheck::DynamicStaticInitializersCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RawStringHeaderFileExtensions(Options.getLocalOrGlobal( + "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { + if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ',')) { + llvm::errs() << "Invalid header file extension: " + << RawStringHeaderFileExtensions << "\n"; + } +} + +void DynamicStaticInitializersCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions); +} + +void DynamicStaticInitializersCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus || getLangOpts().ThreadsafeStatics) + return; + Finder->addMatcher( + varDecl(hasGlobalStorage(), unless(hasConstantDeclaration())).bind("var"), + this); +} + +void DynamicStaticInitializersCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var"); + SourceLocation Loc = Var->getLocation(); + if (!Loc.isValid() || !utils::isPresumedLocInHeaderFile(Loc, *Result.SourceManager, + HeaderFileExtensions)) + return; + // If the initializer is a constant expression, then the compiler + // doesn't have to dynamically initialize it. + diag(Loc, "static variable %0 may be dynamically initialized in this header file") + << Var; +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang |

