Files
llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp
Bruno Ricci 17ff026b73 [AST] Refactor PredefinedExpr
Make the following changes to PredefinedExpr:

1. Move PredefinedExpr below StringLiteral so that it can use its definition.
2. Rename IdentType to IdentKind to be more in line with clang's conventions,
   and propagate the change to its users.
3. Move the location and the IdentKind into the newly available space of
   the bit-fields of Stmt.
4. Only store the function name when needed. When parsing all of Boost,
   of the 1357 PredefinedExpr 919 have no function name.

Differential Revision: https://reviews.llvm.org/D53605

Reviewed By: rjmccall

llvm-svn: 345460
2018-10-27 19:21:19 +00:00

100 lines
3.3 KiB
C++

//===--- LambdaFunctionNameCheck.cpp - clang-tidy--------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "LambdaFunctionNameCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace bugprone {
namespace {
// Keep track of macro expansions that contain both __FILE__ and __LINE__. If
// such a macro also uses __func__ or __FUNCTION__, we don't want to issue a
// warning because __FILE__ and __LINE__ may be useful even if __func__ or
// __FUNCTION__ is not, especially if the macro could be used in the context of
// either a function body or a lambda body.
class MacroExpansionsWithFileAndLine : public PPCallbacks {
public:
explicit MacroExpansionsWithFileAndLine(
LambdaFunctionNameCheck::SourceRangeSet *SME)
: SuppressMacroExpansions(SME) {}
void MacroExpands(const Token &MacroNameTok,
const MacroDefinition &MD, SourceRange Range,
const MacroArgs *Args) override {
bool has_file = false;
bool has_line = false;
for (const auto& T : MD.getMacroInfo()->tokens()) {
if (T.is(tok::identifier)) {
StringRef IdentName = T.getIdentifierInfo()->getName();
if (IdentName == "__FILE__") {
has_file = true;
} else if (IdentName == "__LINE__") {
has_line = true;
}
}
}
if (has_file && has_line) {
SuppressMacroExpansions->insert(Range);
}
}
private:
LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions;
};
} // namespace
void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {
// Match on PredefinedExprs inside a lambda.
Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"),
this);
}
void LambdaFunctionNameCheck::registerPPCallbacks(CompilerInstance &Compiler) {
Compiler.getPreprocessor().addPPCallbacks(
llvm::make_unique<MacroExpansionsWithFileAndLine>(
&SuppressMacroExpansions));
}
void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
if (E->getIdentKind() != PredefinedExpr::Func &&
E->getIdentKind() != PredefinedExpr::Function) {
// We don't care about other PredefinedExprs.
return;
}
if (E->getLocation().isMacroID()) {
auto ER =
Result.SourceManager->getImmediateExpansionRange(E->getLocation());
if (SuppressMacroExpansions.find(ER.getAsRange()) !=
SuppressMacroExpansions.end()) {
// This is a macro expansion for which we should not warn.
return;
}
}
diag(E->getLocation(),
"inside a lambda, '%0' expands to the name of the function call "
"operator; consider capturing the name of the enclosing function "
"explicitly")
<< PredefinedExpr::getIdentKindName(E->getIdentKind());
}
} // namespace bugprone
} // namespace tidy
} // namespace clang