LambdaFunctionNameCheck.cpp 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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. #include "LambdaFunctionNameCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/Frontend/CompilerInstance.h"
  12. #include "clang/Lex/MacroInfo.h"
  13. #include "clang/Lex/Preprocessor.h"
  14. using namespace clang::ast_matchers;
  15. namespace clang::tidy::bugprone {
  16. namespace {
  17. // Keep track of macro expansions that contain both __FILE__ and __LINE__. If
  18. // such a macro also uses __func__ or __FUNCTION__, we don't want to issue a
  19. // warning because __FILE__ and __LINE__ may be useful even if __func__ or
  20. // __FUNCTION__ is not, especially if the macro could be used in the context of
  21. // either a function body or a lambda body.
  22. class MacroExpansionsWithFileAndLine : public PPCallbacks {
  23. public:
  24. explicit MacroExpansionsWithFileAndLine(
  25. LambdaFunctionNameCheck::SourceRangeSet *SME)
  26. : SuppressMacroExpansions(SME) {}
  27. void MacroExpands(const Token &MacroNameTok,
  28. const MacroDefinition &MD, SourceRange Range,
  29. const MacroArgs *Args) override {
  30. bool HasFile = false;
  31. bool HasLine = false;
  32. for (const auto& T : MD.getMacroInfo()->tokens()) {
  33. if (T.is(tok::identifier)) {
  34. StringRef IdentName = T.getIdentifierInfo()->getName();
  35. if (IdentName == "__FILE__") {
  36. HasFile = true;
  37. } else if (IdentName == "__LINE__") {
  38. HasLine = true;
  39. }
  40. }
  41. }
  42. if (HasFile && HasLine) {
  43. SuppressMacroExpansions->insert(Range);
  44. }
  45. }
  46. private:
  47. LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions;
  48. };
  49. } // namespace
  50. void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {
  51. // Match on PredefinedExprs inside a lambda.
  52. Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"),
  53. this);
  54. }
  55. void LambdaFunctionNameCheck::registerPPCallbacks(
  56. const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
  57. PP->addPPCallbacks(std::make_unique<MacroExpansionsWithFileAndLine>(
  58. &SuppressMacroExpansions));
  59. }
  60. void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
  61. const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
  62. if (E->getIdentKind() != PredefinedExpr::Func &&
  63. E->getIdentKind() != PredefinedExpr::Function) {
  64. // We don't care about other PredefinedExprs.
  65. return;
  66. }
  67. if (E->getLocation().isMacroID()) {
  68. auto ER =
  69. Result.SourceManager->getImmediateExpansionRange(E->getLocation());
  70. if (SuppressMacroExpansions.find(ER.getAsRange()) !=
  71. SuppressMacroExpansions.end()) {
  72. // This is a macro expansion for which we should not warn.
  73. return;
  74. }
  75. }
  76. diag(E->getLocation(),
  77. "inside a lambda, '%0' expands to the name of the function call "
  78. "operator; consider capturing the name of the enclosing function "
  79. "explicitly")
  80. << PredefinedExpr::getIdentKindName(E->getIdentKind());
  81. }
  82. } // namespace clang::tidy::bugprone