clang-tools 22.0.0git
OverrideWithDifferentVisibilityCheck.cpp
Go to the documentation of this file.
1//===--- OverrideWithDifferentVisibilityCheck.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
10#include "../utils/Matchers.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15using namespace clang;
16
17namespace {
18
19AST_MATCHER(NamedDecl, isOperatorDecl) {
20 const DeclarationName::NameKind NK = Node.getDeclName().getNameKind();
21 return NK != DeclarationName::Identifier &&
22 NK != DeclarationName::CXXConstructorName &&
23 NK != DeclarationName::CXXDestructorName;
24}
25
26} // namespace
27
28namespace clang::tidy {
29
30template <>
32 misc::OverrideWithDifferentVisibilityCheck::ChangeKind> {
33 static llvm::ArrayRef<std::pair<
48};
49
50namespace misc {
51
53 StringRef Name, ClangTidyContext *Context)
54 : ClangTidyCheck(Name, Context),
55 DetectVisibilityChange(
56 Options.get("DisallowedVisibilityChange", ChangeKind::Any)),
57 CheckDestructors(Options.get("CheckDestructors", false)),
58 CheckOperators(Options.get("CheckOperators", false)),
59 IgnoredFunctions(utils::options::parseStringList(
60 Options.get("IgnoredFunctions", ""))) {}
61
64 Options.store(Opts, "DisallowedVisibilityChange", DetectVisibilityChange);
65 Options.store(Opts, "CheckDestructors", CheckDestructors);
66 Options.store(Opts, "CheckOperators", CheckOperators);
67 Options.store(Opts, "IgnoredFunctions",
68 utils::options::serializeStringList(IgnoredFunctions));
69}
70
72 MatchFinder *Finder) {
73 const auto IgnoredDecl =
74 namedDecl(matchers::matchesAnyListedName(IgnoredFunctions));
75 const auto FilterDestructors =
76 CheckDestructors ? decl() : decl(unless(cxxDestructorDecl()));
77 const auto FilterOperators =
78 CheckOperators ? namedDecl() : namedDecl(unless(isOperatorDecl()));
79 Finder->addMatcher(
80 cxxMethodDecl(
81 isVirtual(), FilterDestructors, FilterOperators,
82 ofClass(
83 cxxRecordDecl(unless(isExpansionInSystemHeader())).bind("class")),
84 forEachOverridden(cxxMethodDecl(ofClass(cxxRecordDecl().bind("base")),
85 unless(IgnoredDecl))
86 .bind("base_func")))
87 .bind("func"),
88 this);
89}
90
92 const MatchFinder::MatchResult &Result) {
93 const auto *const MatchedFunction =
94 Result.Nodes.getNodeAs<FunctionDecl>("func");
95 if (!MatchedFunction->isCanonicalDecl())
96 return;
97
98 const auto *const ParentClass =
99 Result.Nodes.getNodeAs<CXXRecordDecl>("class");
100 const auto *const BaseClass = Result.Nodes.getNodeAs<CXXRecordDecl>("base");
101 CXXBasePaths Paths;
102 if (!ParentClass->isDerivedFrom(BaseClass, Paths))
103 return;
104
105 const auto *const OverriddenFunction =
106 Result.Nodes.getNodeAs<FunctionDecl>("base_func");
107 const AccessSpecifier ActualAccess = MatchedFunction->getAccess();
108 AccessSpecifier OverriddenAccess = OverriddenFunction->getAccess();
109
110 const CXXBaseSpecifier *InheritanceWithStrictVisibility = nullptr;
111 for (const CXXBasePath &Path : Paths) {
112 for (const CXXBasePathElement &Elem : Path) {
113 if (Elem.Base->getAccessSpecifier() > OverriddenAccess) {
114 OverriddenAccess = Elem.Base->getAccessSpecifier();
115 InheritanceWithStrictVisibility = Elem.Base;
116 }
117 }
118 }
119
120 if (ActualAccess != OverriddenAccess) {
121 if (DetectVisibilityChange == ChangeKind::Widening &&
122 ActualAccess > OverriddenAccess)
123 return;
124 if (DetectVisibilityChange == ChangeKind::Narrowing &&
125 ActualAccess < OverriddenAccess)
126 return;
127
128 if (InheritanceWithStrictVisibility) {
129 diag(MatchedFunction->getLocation(),
130 "visibility of function %0 is changed from %1 (through %1 "
131 "inheritance of class %2) to %3")
132 << MatchedFunction << OverriddenAccess
133 << InheritanceWithStrictVisibility->getType() << ActualAccess;
134 diag(InheritanceWithStrictVisibility->getBeginLoc(),
135 "%0 is inherited as %1 here", DiagnosticIDs::Note)
136 << InheritanceWithStrictVisibility->getType() << OverriddenAccess;
137 } else {
138 diag(MatchedFunction->getLocation(),
139 "visibility of function %0 is changed from %1 in class %2 to %3")
140 << MatchedFunction << OverriddenAccess << BaseClass << ActualAccess;
141 }
142 diag(OverriddenFunction->getLocation(), "function declared here as %0",
143 DiagnosticIDs::Note)
144 << OverriddenFunction->getAccess();
145 }
146}
147
148} // namespace misc
149
150} // namespace clang::tidy
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringMap< ClangTidyValue > OptionMap
static llvm::ArrayRef< std::pair< misc::OverrideWithDifferentVisibilityCheck::ChangeKind, StringRef > > getEnumMapping()
This class should be specialized by any enum type that needs to be converted to and from an llvm::Str...