xref: /llvm-project/clang-tools-extra/clang-tidy/readability/RedundantAccessSpecifiersCheck.cpp (revision 7d2ea6c422d3f5712b7253407005e1a465a76946)
129dc0b17SAaron Ballman //===--- RedundantAccessSpecifiersCheck.cpp - clang-tidy ------------------===//
229dc0b17SAaron Ballman //
329dc0b17SAaron Ballman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
429dc0b17SAaron Ballman // See https://llvm.org/LICENSE.txt for license information.
529dc0b17SAaron Ballman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
629dc0b17SAaron Ballman //
729dc0b17SAaron Ballman //===----------------------------------------------------------------------===//
829dc0b17SAaron Ballman 
929dc0b17SAaron Ballman #include "RedundantAccessSpecifiersCheck.h"
1029dc0b17SAaron Ballman #include "clang/AST/ASTContext.h"
1129dc0b17SAaron Ballman #include "clang/ASTMatchers/ASTMatchFinder.h"
1229dc0b17SAaron Ballman 
1329dc0b17SAaron Ballman using namespace clang::ast_matchers;
1429dc0b17SAaron Ballman 
15*7d2ea6c4SCarlos Galvez namespace clang::tidy::readability {
1629dc0b17SAaron Ballman 
registerMatchers(MatchFinder * Finder)1729dc0b17SAaron Ballman void RedundantAccessSpecifiersCheck::registerMatchers(MatchFinder *Finder) {
1829dc0b17SAaron Ballman   Finder->addMatcher(
1929dc0b17SAaron Ballman       cxxRecordDecl(has(accessSpecDecl())).bind("redundant-access-specifiers"),
2029dc0b17SAaron Ballman       this);
2129dc0b17SAaron Ballman }
2229dc0b17SAaron Ballman 
check(const MatchFinder::MatchResult & Result)2329dc0b17SAaron Ballman void RedundantAccessSpecifiersCheck::check(
2429dc0b17SAaron Ballman     const MatchFinder::MatchResult &Result) {
2529dc0b17SAaron Ballman   const auto *MatchedDecl =
2629dc0b17SAaron Ballman       Result.Nodes.getNodeAs<CXXRecordDecl>("redundant-access-specifiers");
2729dc0b17SAaron Ballman 
2829dc0b17SAaron Ballman   const AccessSpecDecl *LastASDecl = nullptr;
2929dc0b17SAaron Ballman   for (DeclContext::specific_decl_iterator<AccessSpecDecl>
3029dc0b17SAaron Ballman            AS(MatchedDecl->decls_begin()),
3129dc0b17SAaron Ballman        ASEnd(MatchedDecl->decls_end());
3229dc0b17SAaron Ballman        AS != ASEnd; ++AS) {
3329dc0b17SAaron Ballman     const AccessSpecDecl *ASDecl = *AS;
3429dc0b17SAaron Ballman 
3529dc0b17SAaron Ballman     // Ignore macro expansions.
3629dc0b17SAaron Ballman     if (ASDecl->getLocation().isMacroID()) {
3729dc0b17SAaron Ballman       LastASDecl = ASDecl;
3829dc0b17SAaron Ballman       continue;
3929dc0b17SAaron Ballman     }
4029dc0b17SAaron Ballman 
4129dc0b17SAaron Ballman     if (LastASDecl == nullptr) {
4229dc0b17SAaron Ballman       // First declaration.
4329dc0b17SAaron Ballman       LastASDecl = ASDecl;
4429dc0b17SAaron Ballman 
4529dc0b17SAaron Ballman       if (CheckFirstDeclaration) {
4629dc0b17SAaron Ballman         AccessSpecifier DefaultSpecifier =
4729dc0b17SAaron Ballman             MatchedDecl->isClass() ? AS_private : AS_public;
4829dc0b17SAaron Ballman         if (ASDecl->getAccess() == DefaultSpecifier) {
4929dc0b17SAaron Ballman           diag(ASDecl->getLocation(),
5029dc0b17SAaron Ballman                "redundant access specifier has the same accessibility as the "
5129dc0b17SAaron Ballman                "implicit access specifier")
5229dc0b17SAaron Ballman               << FixItHint::CreateRemoval(ASDecl->getSourceRange());
5329dc0b17SAaron Ballman         }
5429dc0b17SAaron Ballman       }
5529dc0b17SAaron Ballman 
5629dc0b17SAaron Ballman       continue;
5729dc0b17SAaron Ballman     }
5829dc0b17SAaron Ballman 
5929dc0b17SAaron Ballman     if (LastASDecl->getAccess() == ASDecl->getAccess()) {
6029dc0b17SAaron Ballman       // Ignore macro expansions.
6129dc0b17SAaron Ballman       if (LastASDecl->getLocation().isMacroID()) {
6229dc0b17SAaron Ballman         LastASDecl = ASDecl;
6329dc0b17SAaron Ballman         continue;
6429dc0b17SAaron Ballman       }
6529dc0b17SAaron Ballman 
6629dc0b17SAaron Ballman       diag(ASDecl->getLocation(),
6729dc0b17SAaron Ballman            "redundant access specifier has the same accessibility as the "
6829dc0b17SAaron Ballman            "previous access specifier")
6929dc0b17SAaron Ballman           << FixItHint::CreateRemoval(ASDecl->getSourceRange());
7029dc0b17SAaron Ballman       diag(LastASDecl->getLocation(), "previously declared here",
7129dc0b17SAaron Ballman            DiagnosticIDs::Note);
7229dc0b17SAaron Ballman     } else {
7329dc0b17SAaron Ballman       LastASDecl = ASDecl;
7429dc0b17SAaron Ballman     }
7529dc0b17SAaron Ballman   }
7629dc0b17SAaron Ballman }
7729dc0b17SAaron Ballman 
78*7d2ea6c4SCarlos Galvez } // namespace clang::tidy::readability
79