1 //===--- RedundantAccessSpecifiersCheck.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 9 #include "RedundantAccessSpecifiersCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang::tidy::readability { 16 registerMatchers(MatchFinder * Finder)17void RedundantAccessSpecifiersCheck::registerMatchers(MatchFinder *Finder) { 18 Finder->addMatcher( 19 cxxRecordDecl(has(accessSpecDecl())).bind("redundant-access-specifiers"), 20 this); 21 } 22 check(const MatchFinder::MatchResult & Result)23void RedundantAccessSpecifiersCheck::check( 24 const MatchFinder::MatchResult &Result) { 25 const auto *MatchedDecl = 26 Result.Nodes.getNodeAs<CXXRecordDecl>("redundant-access-specifiers"); 27 28 const AccessSpecDecl *LastASDecl = nullptr; 29 for (DeclContext::specific_decl_iterator<AccessSpecDecl> 30 AS(MatchedDecl->decls_begin()), 31 ASEnd(MatchedDecl->decls_end()); 32 AS != ASEnd; ++AS) { 33 const AccessSpecDecl *ASDecl = *AS; 34 35 // Ignore macro expansions. 36 if (ASDecl->getLocation().isMacroID()) { 37 LastASDecl = ASDecl; 38 continue; 39 } 40 41 if (LastASDecl == nullptr) { 42 // First declaration. 43 LastASDecl = ASDecl; 44 45 if (CheckFirstDeclaration) { 46 AccessSpecifier DefaultSpecifier = 47 MatchedDecl->isClass() ? AS_private : AS_public; 48 if (ASDecl->getAccess() == DefaultSpecifier) { 49 diag(ASDecl->getLocation(), 50 "redundant access specifier has the same accessibility as the " 51 "implicit access specifier") 52 << FixItHint::CreateRemoval(ASDecl->getSourceRange()); 53 } 54 } 55 56 continue; 57 } 58 59 if (LastASDecl->getAccess() == ASDecl->getAccess()) { 60 // Ignore macro expansions. 61 if (LastASDecl->getLocation().isMacroID()) { 62 LastASDecl = ASDecl; 63 continue; 64 } 65 66 diag(ASDecl->getLocation(), 67 "redundant access specifier has the same accessibility as the " 68 "previous access specifier") 69 << FixItHint::CreateRemoval(ASDecl->getSourceRange()); 70 diag(LastASDecl->getLocation(), "previously declared here", 71 DiagnosticIDs::Note); 72 } else { 73 LastASDecl = ASDecl; 74 } 75 } 76 } 77 78 } // namespace clang::tidy::readability 79