clang-tools 23.0.0git
OverrideWithDifferentVisibilityCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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::matchesAnyListedRegexName(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(cxxRecordDecl().bind("class")),
83 forEachOverridden(cxxMethodDecl(ofClass(cxxRecordDecl().bind("base")),
84 unless(IgnoredDecl))
85 .bind("base_func")))
86 .bind("func"),
87 this);
88}
89
91 const MatchFinder::MatchResult &Result) {
92 const auto *const MatchedFunction =
93 Result.Nodes.getNodeAs<FunctionDecl>("func");
94 if (!MatchedFunction->isCanonicalDecl())
95 return;
96
97 const auto *const ParentClass =
98 Result.Nodes.getNodeAs<CXXRecordDecl>("class");
99 const auto *const BaseClass = Result.Nodes.getNodeAs<CXXRecordDecl>("base");
100 CXXBasePaths Paths;
101 if (!ParentClass->isDerivedFrom(BaseClass, Paths))
102 return;
103
104 const auto *const OverriddenFunction =
105 Result.Nodes.getNodeAs<FunctionDecl>("base_func");
106 const AccessSpecifier ActualAccess = MatchedFunction->getAccess();
107 AccessSpecifier OverriddenAccess = OverriddenFunction->getAccess();
108
109 const CXXBaseSpecifier *InheritanceWithStrictVisibility = nullptr;
110 for (const CXXBasePath &Path : Paths) {
111 for (const CXXBasePathElement &Elem : Path) {
112 if (Elem.Base->getAccessSpecifier() > OverriddenAccess) {
113 OverriddenAccess = Elem.Base->getAccessSpecifier();
114 InheritanceWithStrictVisibility = Elem.Base;
115 }
116 }
117 }
118
119 if (ActualAccess != OverriddenAccess) {
120 if (DetectVisibilityChange == ChangeKind::Widening &&
121 ActualAccess > OverriddenAccess)
122 return;
123 if (DetectVisibilityChange == ChangeKind::Narrowing &&
124 ActualAccess < OverriddenAccess)
125 return;
126
127 if (InheritanceWithStrictVisibility) {
128 diag(MatchedFunction->getLocation(),
129 "visibility of function %0 is changed from %1 (through %1 "
130 "inheritance of class %2) to %3")
131 << MatchedFunction << OverriddenAccess
132 << InheritanceWithStrictVisibility->getType() << ActualAccess;
133 diag(InheritanceWithStrictVisibility->getBeginLoc(),
134 "%0 is inherited as %1 here", DiagnosticIDs::Note)
135 << InheritanceWithStrictVisibility->getType() << OverriddenAccess;
136 } else {
137 diag(MatchedFunction->getLocation(),
138 "visibility of function %0 is changed from %1 in class %2 to %3")
139 << MatchedFunction << OverriddenAccess << BaseClass << ActualAccess;
140 }
141 diag(OverriddenFunction->getLocation(), "function declared here as %0",
142 DiagnosticIDs::Note)
143 << OverriddenFunction->getAccess();
144 }
145}
146
147} // namespace misc
148
149} // 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 > matchesAnyListedRegexName(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...