10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
18 namespace readability {
20 AST_MATCHER(FunctionDecl, doesDeclarationForceExternallyVisibleDefinition) {
21 return Node.doesDeclarationForceExternallyVisibleDefinition();
24 RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef
Name,
27 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)) {}
36 namedDecl(anyOf(varDecl(unless(isDefinition())),
37 functionDecl(unless(anyOf(
38 isDefinition(), isDefaulted(),
39 doesDeclarationForceExternallyVisibleDefinition(),
40 hasParent(friendDecl()))))))
46 const auto *D = Result.Nodes.getNodeAs<NamedDecl>(
"Decl");
47 const auto *Prev = D->getPreviousDecl();
50 if (!Prev->getLocation().isValid())
52 if (Prev->getLocation() == D->getLocation())
55 (D->getLocation().isMacroID() || Prev->getLocation().isMacroID()))
58 for (
const auto &
Parent : Result.Context->getParents(*Prev))
59 if (
Parent.get<FriendDecl>())
62 const SourceManager &SM = *Result.SourceManager;
64 const bool DifferentHeaders =
65 !SM.isInMainFile(D->getLocation()) &&
66 !SM.isWrittenInSameFile(Prev->getLocation(), D->getLocation());
68 bool MultiVar =
false;
69 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
71 for (
const auto Other : VD->getDeclContext()->decls()) {
72 if (Other != D && Other->getBeginLoc() == VD->getBeginLoc()) {
79 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
80 D->getSourceRange().getEnd(), 0, SM, Result.Context->getLangOpts());
82 auto Diag =
diag(D->getLocation(),
"redundant %0 declaration") << D;
83 if (!MultiVar && !DifferentHeaders)
84 Diag << FixItHint::CreateRemoval(
85 SourceRange(D->getSourceRange().getBegin(), EndLoc));
87 diag(Prev->getLocation(),
"previously declared here", DiagnosticIDs::Note);