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