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 //===----------------------------------------------------------------------===// 8 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" 15 16 using namespace clang::ast_matchers; 17 18 namespace clang { 19 namespace tidy { 20 namespace bugprone { 21 22 namespace { 23 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) {} 34 35 void MacroExpands(const Token &MacroNameTok, 36 const MacroDefinition &MD, SourceRange Range, 37 const MacroArgs *Args) override { 38 bool has_file = false; 39 bool has_line = 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 has_file = true; 45 } else if (IdentName == "__LINE__") { 46 has_line = true; 47 } 48 } 49 } 50 if (has_file && has_line) { 51 SuppressMacroExpansions->insert(Range); 52 } 53 } 54 55 private: 56 LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions; 57 }; 58 59 } // namespace 60 61 void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) { 62 // Match on PredefinedExprs inside a lambda. 63 Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"), 64 this); 65 } 66 67 void LambdaFunctionNameCheck::registerPPCallbacks( 68 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { 69 PP->addPPCallbacks(llvm::make_unique<MacroExpansionsWithFileAndLine>( 70 &SuppressMacroExpansions)); 71 } 72 73 void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) { 74 const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E"); 75 if (E->getIdentKind() != PredefinedExpr::Func && 76 E->getIdentKind() != PredefinedExpr::Function) { 77 // We don't care about other PredefinedExprs. 78 return; 79 } 80 if (E->getLocation().isMacroID()) { 81 auto ER = 82 Result.SourceManager->getImmediateExpansionRange(E->getLocation()); 83 if (SuppressMacroExpansions.find(ER.getAsRange()) != 84 SuppressMacroExpansions.end()) { 85 // This is a macro expansion for which we should not warn. 86 return; 87 } 88 } 89 diag(E->getLocation(), 90 "inside a lambda, '%0' expands to the name of the function call " 91 "operator; consider capturing the name of the enclosing function " 92 "explicitly") 93 << PredefinedExpr::getIdentKindName(E->getIdentKind()); 94 } 95 96 } // namespace bugprone 97 } // namespace tidy 98 } // namespace clang 99