1 //===--- LambdaFunctionNameCheck.cpp - clang-tidy--------------------------===//
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
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
{
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
{
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
{
40 for (const auto& T
: MD
.getMacroInfo()->tokens()) {
41 if (T
.is(tok::identifier
)) {
42 StringRef IdentName
= T
.getIdentifierInfo()->getName();
43 if (IdentName
== "__FILE__") {
45 } else if (IdentName
== "__LINE__") {
50 if (HasFile
&& HasLine
) {
51 SuppressMacroExpansions
->insert(Range
);
56 LambdaFunctionNameCheck::SourceRangeSet
* SuppressMacroExpansions
;
61 LambdaFunctionNameCheck::LambdaFunctionNameCheck(StringRef Name
,
62 ClangTidyContext
*Context
)
63 : ClangTidyCheck(Name
, Context
),
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"),
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.
90 if (E
->getLocation().isMacroID()) {
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.
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 "
107 << PredefinedExpr::getIdentKindName(E
->getIdentKind());
110 } // namespace clang::tidy::bugprone