[Workflow] Try to fix code-formatter failing to find changes in some cases.
[llvm-project.git] / clang-tools-extra / clang-tidy / bugprone / LambdaFunctionNameCheck.cpp
bloba01b7f5a4ee6e68fd9391d2e7cda1dc053641bf5
1 //===--- LambdaFunctionNameCheck.cpp - clang-tidy--------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "LambdaFunctionNameCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/MacroInfo.h"
14 #include "clang/Lex/Preprocessor.h"
16 using namespace clang::ast_matchers;
18 namespace clang::tidy::bugprone {
20 namespace {
22 static constexpr bool DefaultIgnoreMacros = false;
24 // Keep track of macro expansions that contain both __FILE__ and __LINE__. If
25 // such a macro also uses __func__ or __FUNCTION__, we don't want to issue a
26 // warning because __FILE__ and __LINE__ may be useful even if __func__ or
27 // __FUNCTION__ is not, especially if the macro could be used in the context of
28 // either a function body or a lambda body.
29 class MacroExpansionsWithFileAndLine : public PPCallbacks {
30 public:
31 explicit MacroExpansionsWithFileAndLine(
32 LambdaFunctionNameCheck::SourceRangeSet *SME)
33 : SuppressMacroExpansions(SME) {}
35 void MacroExpands(const Token &MacroNameTok,
36 const MacroDefinition &MD, SourceRange Range,
37 const MacroArgs *Args) override {
38 bool HasFile = false;
39 bool HasLine = false;
40 for (const auto& T : MD.getMacroInfo()->tokens()) {
41 if (T.is(tok::identifier)) {
42 StringRef IdentName = T.getIdentifierInfo()->getName();
43 if (IdentName == "__FILE__") {
44 HasFile = true;
45 } else if (IdentName == "__LINE__") {
46 HasLine = true;
50 if (HasFile && HasLine) {
51 SuppressMacroExpansions->insert(Range);
55 private:
56 LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions;
59 } // namespace
61 LambdaFunctionNameCheck::LambdaFunctionNameCheck(StringRef Name,
62 ClangTidyContext *Context)
63 : ClangTidyCheck(Name, Context),
64 IgnoreMacros(
65 Options.getLocalOrGlobal("IgnoreMacros", DefaultIgnoreMacros)) {}
67 void LambdaFunctionNameCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
68 Options.store(Opts, "IgnoreMacros", IgnoreMacros);
71 void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {
72 // Match on PredefinedExprs inside a lambda.
73 Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"),
74 this);
77 void LambdaFunctionNameCheck::registerPPCallbacks(
78 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
79 PP->addPPCallbacks(std::make_unique<MacroExpansionsWithFileAndLine>(
80 &SuppressMacroExpansions));
83 void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
84 const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
85 if (E->getIdentKind() != PredefinedExpr::Func &&
86 E->getIdentKind() != PredefinedExpr::Function) {
87 // We don't care about other PredefinedExprs.
88 return;
90 if (E->getLocation().isMacroID()) {
91 if (IgnoreMacros)
92 return;
94 auto ER =
95 Result.SourceManager->getImmediateExpansionRange(E->getLocation());
96 if (SuppressMacroExpansions.find(ER.getAsRange()) !=
97 SuppressMacroExpansions.end()) {
98 // This is a macro expansion for which we should not warn.
99 return;
103 diag(E->getLocation(),
104 "inside a lambda, '%0' expands to the name of the function call "
105 "operator; consider capturing the name of the enclosing function "
106 "explicitly")
107 << PredefinedExpr::getIdentKindName(E->getIdentKind());
110 } // namespace clang::tidy::bugprone