clang-tools  6.0.0
LambdaFunctionNameCheck.cpp
Go to the documentation of this file.
1 //===--- LambdaFunctionNameCheck.cpp - clang-tidy--------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 #include "clang/Lex/MacroInfo.h"
15 #include "clang/Lex/Preprocessor.h"
16 
17 using namespace clang::ast_matchers;
18 
19 namespace clang {
20 namespace tidy {
21 namespace misc {
22 
23 namespace {
24 
25 // Keep track of macro expansions that contain both __FILE__ and __LINE__. If
26 // such a macro also uses __func__ or __FUNCTION__, we don't want to issue a
27 // warning because __FILE__ and __LINE__ may be useful even if __func__ or
28 // __FUNCTION__ is not, especially if the macro could be used in the context of
29 // either a function body or a lambda body.
30 class MacroExpansionsWithFileAndLine : public PPCallbacks {
31 public:
32  explicit MacroExpansionsWithFileAndLine(
33  LambdaFunctionNameCheck::SourceRangeSet *SME)
34  : SuppressMacroExpansions(SME) {}
35 
36  void MacroExpands(const Token &MacroNameTok,
37  const MacroDefinition &MD, SourceRange Range,
38  const MacroArgs *Args) override {
39  bool has_file = false;
40  bool has_line = false;
41  for (const auto& T : MD.getMacroInfo()->tokens()) {
42  if (T.is(tok::identifier)) {
43  StringRef IdentName = T.getIdentifierInfo()->getName();
44  if (IdentName == "__FILE__") {
45  has_file = true;
46  } else if (IdentName == "__LINE__") {
47  has_line = true;
48  }
49  }
50  }
51  if (has_file && has_line) {
52  SuppressMacroExpansions->insert(Range);
53  }
54  }
55 
56 private:
57  LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions;
58 };
59 
60 } // namespace
61 
62 void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {
63  // Match on PredefinedExprs inside a lambda.
64  Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"),
65  this);
66 }
67 
68 void LambdaFunctionNameCheck::registerPPCallbacks(CompilerInstance &Compiler) {
69  Compiler.getPreprocessor().addPPCallbacks(
70  llvm::make_unique<MacroExpansionsWithFileAndLine>(
71  &SuppressMacroExpansions));
72 }
73 
74 void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
75  const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
76  if (E->getIdentType() != PredefinedExpr::Func &&
77  E->getIdentType() != PredefinedExpr::Function) {
78  // We don't care about other PredefinedExprs.
79  return;
80  }
81  if (E->getLocation().isMacroID()) {
82  auto ER =
83  Result.SourceManager->getImmediateExpansionRange(E->getLocation());
84  if (SuppressMacroExpansions.find(SourceRange(ER.first, ER.second)) !=
85  SuppressMacroExpansions.end()) {
86  // This is a macro expansion for which we should not warn.
87  return;
88  }
89  }
90  diag(E->getLocation(),
91  "inside a lambda, '%0' expands to the name of the function call "
92  "operator; consider capturing the name of the enclosing function "
93  "explicitly")
94  << PredefinedExpr::getIdentTypeName(E->getIdentType());
95 }
96 
97 } // namespace misc
98 } // namespace tidy
99 } // namespace clang
CharSourceRange Range
SourceRange for the file name.