1 //===--- RedundantDeclarationCheck.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 10 #include "RedundantDeclarationCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Lex/Lexer.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace readability { 20 21 RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef Name, 22 ClangTidyContext *Context) 23 : ClangTidyCheck(Name, Context), 24 IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {} 25 26 void RedundantDeclarationCheck::registerMatchers(MatchFinder *Finder) { 27 Finder->addMatcher( 28 namedDecl(anyOf(varDecl(unless(isDefinition())), 29 functionDecl(unless(anyOf(isDefinition(), isDefaulted(), 30 hasParent(friendDecl())))))) 31 .bind("Decl"), 32 this); 33 } 34 35 void RedundantDeclarationCheck::check(const MatchFinder::MatchResult &Result) { 36 const auto *D = Result.Nodes.getNodeAs<NamedDecl>("Decl"); 37 const auto *Prev = D->getPreviousDecl(); 38 if (!Prev) 39 return; 40 if (!Prev->getLocation().isValid()) 41 return; 42 if (Prev->getLocation() == D->getLocation()) 43 return; 44 if (IgnoreMacros && 45 (D->getLocation().isMacroID() || Prev->getLocation().isMacroID())) 46 return; 47 // Don't complain when the previous declaration is a friend declaration. 48 for (const auto &Parent : Result.Context->getParents(*Prev)) 49 if (Parent.get<FriendDecl>()) 50 return; 51 52 const SourceManager &SM = *Result.SourceManager; 53 54 const bool DifferentHeaders = 55 !SM.isInMainFile(D->getLocation()) && 56 !SM.isWrittenInSameFile(Prev->getLocation(), D->getLocation()); 57 58 bool MultiVar = false; 59 if (const auto *VD = dyn_cast<VarDecl>(D)) { 60 // Is this a multivariable declaration? 61 for (const auto Other : VD->getDeclContext()->decls()) { 62 if (Other != D && Other->getLocStart() == VD->getLocStart()) { 63 MultiVar = true; 64 break; 65 } 66 } 67 } 68 69 SourceLocation EndLoc = Lexer::getLocForEndOfToken( 70 D->getSourceRange().getEnd(), 0, SM, Result.Context->getLangOpts()); 71 { 72 auto Diag = diag(D->getLocation(), "redundant %0 declaration") << D; 73 if (!MultiVar && !DifferentHeaders) 74 Diag << FixItHint::CreateRemoval( 75 SourceRange(D->getSourceRange().getBegin(), EndLoc)); 76 } 77 diag(Prev->getLocation(), "previously declared here", DiagnosticIDs::Note); 78 } 79 80 } // namespace readability 81 } // namespace tidy 82 } // namespace clang 83