[clang-tools-extra] a0f325b - [clang-tidy] Added check 'misc-override-with-different-visibility' (#140086)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 18 02:00:45 PDT 2025
Author: Balázs Kéri
Date: 2025-08-18T11:00:42+02:00
New Revision: a0f325bd41c931e4584feeb592987338c5b67d80
URL: https://github.com/llvm/llvm-project/commit/a0f325bd41c931e4584feeb592987338c5b67d80
DIFF: https://github.com/llvm/llvm-project/commit/a0f325bd41c931e4584feeb592987338c5b67d80.diff
LOG: [clang-tidy] Added check 'misc-override-with-different-visibility' (#140086)
Added:
clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp
clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h
clang-tools-extra/docs/clang-tidy/checks/misc/override-with-different-visibility.rst
clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-different-visibility/test-system-header.h
clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-ignore.cpp
clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility-options.cpp
clang-tools-extra/test/clang-tidy/checkers/misc/override-with-different-visibility.cpp
Modified:
clang-tools-extra/clang-tidy/misc/CMakeLists.txt
clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index fd7affd22a463..2cfee5fd10713 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -32,6 +32,7 @@ add_clang_library(clangTidyMiscModule STATIC
NoRecursionCheck.cpp
NonCopyableObjects.cpp
NonPrivateMemberVariablesInClassesCheck.cpp
+ OverrideWithDifferentVisibilityCheck.cpp
RedundantExpressionCheck.cpp
StaticAssertCheck.cpp
ThrowByValueCatchByReferenceCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 6ddebcbc0e152..f675ca70deb9d 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -22,6 +22,7 @@
#include "NoRecursionCheck.h"
#include "NonCopyableObjects.h"
#include "NonPrivateMemberVariablesInClassesCheck.h"
+#include "OverrideWithDifferentVisibilityCheck.h"
#include "RedundantExpressionCheck.h"
#include "StaticAssertCheck.h"
#include "ThrowByValueCatchByReferenceCheck.h"
@@ -81,6 +82,8 @@ class MiscModule : public ClangTidyModule {
"misc-use-anonymous-namespace");
CheckFactories.registerCheck<UseInternalLinkageCheck>(
"misc-use-internal-linkage");
+ CheckFactories.registerCheck<OverrideWithDifferentVisibilityCheck>(
+ "misc-override-with-
diff erent-visibility");
}
};
diff --git a/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp
new file mode 100644
index 0000000000000..12f78affe463e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.cpp
@@ -0,0 +1,150 @@
+//===--- OverrideWithDifferentVisibilityCheck.cpp - clang-tidy ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "OverrideWithDifferentVisibilityCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang;
+
+namespace {
+
+AST_MATCHER(NamedDecl, isOperatorDecl) {
+ DeclarationName::NameKind const NK = Node.getDeclName().getNameKind();
+ return NK != DeclarationName::Identifier &&
+ NK != DeclarationName::CXXConstructorName &&
+ NK != DeclarationName::CXXDestructorName;
+}
+
+} // namespace
+
+namespace clang::tidy {
+
+template <>
+struct OptionEnumMapping<
+ misc::OverrideWithDifferentVisibilityCheck::ChangeKind> {
+ static llvm::ArrayRef<std::pair<
+ misc::OverrideWithDifferentVisibilityCheck::ChangeKind, StringRef>>
+ getEnumMapping() {
+ static constexpr std::pair<
+ misc::OverrideWithDifferentVisibilityCheck::ChangeKind, StringRef>
+ Mapping[] = {
+ {misc::OverrideWithDifferentVisibilityCheck::ChangeKind::Any,
+ "any"},
+ {misc::OverrideWithDifferentVisibilityCheck::ChangeKind::Widening,
+ "widening"},
+ {misc::OverrideWithDifferentVisibilityCheck::ChangeKind::Narrowing,
+ "narrowing"},
+ };
+ return {Mapping};
+ }
+};
+
+namespace misc {
+
+OverrideWithDifferentVisibilityCheck::OverrideWithDifferentVisibilityCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ DetectVisibilityChange(
+ Options.get("DisallowedVisibilityChange", ChangeKind::Any)),
+ CheckDestructors(Options.get("CheckDestructors", false)),
+ CheckOperators(Options.get("CheckOperators", false)),
+ IgnoredFunctions(utils::options::parseStringList(
+ Options.get("IgnoredFunctions", ""))) {}
+
+void OverrideWithDifferentVisibilityCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "DisallowedVisibilityChange", DetectVisibilityChange);
+ Options.store(Opts, "CheckDestructors", CheckDestructors);
+ Options.store(Opts, "CheckOperators", CheckOperators);
+ Options.store(Opts, "IgnoredFunctions",
+ utils::options::serializeStringList(IgnoredFunctions));
+}
+
+void OverrideWithDifferentVisibilityCheck::registerMatchers(
+ MatchFinder *Finder) {
+ const auto IgnoredDecl =
+ namedDecl(matchers::matchesAnyListedName(IgnoredFunctions));
+ const auto FilterDestructors =
+ CheckDestructors ? decl() : decl(unless(cxxDestructorDecl()));
+ const auto FilterOperators =
+ CheckOperators ? namedDecl() : namedDecl(unless(isOperatorDecl()));
+ Finder->addMatcher(
+ cxxMethodDecl(
+ isVirtual(), FilterDestructors, FilterOperators,
+ ofClass(
+ cxxRecordDecl(unless(isExpansionInSystemHeader())).bind("class")),
+ forEachOverridden(cxxMethodDecl(ofClass(cxxRecordDecl().bind("base")),
+ unless(IgnoredDecl))
+ .bind("base_func")))
+ .bind("func"),
+ this);
+}
+
+void OverrideWithDifferentVisibilityCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *const MatchedFunction =
+ Result.Nodes.getNodeAs<FunctionDecl>("func");
+ if (!MatchedFunction->isCanonicalDecl())
+ return;
+
+ const auto *const ParentClass =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("class");
+ const auto *const BaseClass = Result.Nodes.getNodeAs<CXXRecordDecl>("base");
+ CXXBasePaths Paths;
+ if (!ParentClass->isDerivedFrom(BaseClass, Paths))
+ return;
+
+ const auto *const OverriddenFunction =
+ Result.Nodes.getNodeAs<FunctionDecl>("base_func");
+ AccessSpecifier const ActualAccess = MatchedFunction->getAccess();
+ AccessSpecifier OverriddenAccess = OverriddenFunction->getAccess();
+
+ const CXXBaseSpecifier *InheritanceWithStrictVisibility = nullptr;
+ for (const CXXBasePath &Path : Paths) {
+ for (const CXXBasePathElement &Elem : Path) {
+ if (Elem.Base->getAccessSpecifier() > OverriddenAccess) {
+ OverriddenAccess = Elem.Base->getAccessSpecifier();
+ InheritanceWithStrictVisibility = Elem.Base;
+ }
+ }
+ }
+
+ if (ActualAccess != OverriddenAccess) {
+ if (DetectVisibilityChange == ChangeKind::Widening &&
+ ActualAccess > OverriddenAccess)
+ return;
+ if (DetectVisibilityChange == ChangeKind::Narrowing &&
+ ActualAccess < OverriddenAccess)
+ return;
+
+ if (InheritanceWithStrictVisibility) {
+ diag(MatchedFunction->getLocation(),
+ "visibility of function %0 is changed from %1 (through %1 "
+ "inheritance of class %2) to %3")
+ << MatchedFunction << OverriddenAccess
+ << InheritanceWithStrictVisibility->getType() << ActualAccess;
+ diag(InheritanceWithStrictVisibility->getBeginLoc(),
+ "%0 is inherited as %1 here", DiagnosticIDs::Note)
+ << InheritanceWithStrictVisibility->getType() << OverriddenAccess;
+ } else {
+ diag(MatchedFunction->getLocation(),
+ "visibility of function %0 is changed from %1 in class %2 to %3")
+ << MatchedFunction << OverriddenAccess << BaseClass << ActualAccess;
+ }
+ diag(OverriddenFunction->getLocation(), "function declared here as %0",
+ DiagnosticIDs::Note)
+ << OverriddenFunction->getAccess();
+ }
+}
+
+} // namespace misc
+
+} // namespace clang::tidy
diff --git a/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h
new file mode 100644
index 0000000000000..1f5222d99196b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/OverrideWithDifferentVisibilityCheck.h
@@ -0,0 +1,43 @@
+//===--- OverrideWithDifferentVisibilityCheck.h - clang-tidy --*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OVERRIDEWITHDIFFERENTVISIBILITYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OVERRIDEWITHDIFFERENTVISIBILITYCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::misc {
+
+/// Finds virtual function overrides with
diff erent visibility than the function
+/// in the base class.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc/override-with-
diff erent-visibility.html
+class OverrideWithDifferentVisibilityCheck : public ClangTidyCheck {
+public:
+ enum class ChangeKind { Any, Widening, Narrowing };
+
+ OverrideWithDifferentVisibilityCheck(StringRef Name,
+ ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+
+private:
+ ChangeKind DetectVisibilityChange;
+ bool CheckDestructors;
+ bool CheckOperators;
+ std::vector<llvm::StringRef> IgnoredFunctions;
+};
+
+} // namespace clang::tidy::misc
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OVERRIDEWITHDIFFERENTVISIBILITYCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index fd81b0d47e82b..aab76ac24bc05 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -134,6 +134,12 @@ New checks
Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form
and suggests using ``T::create`` instead.
+- New :doc:`misc-override-with-
diff erent-visibility
+ <clang-tidy/checks/misc/override-with-
diff erent-visibility>` check.
+
+ Finds virtual function overrides with
diff erent visibility than the function
+ in the base class.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index b6444eb3c9aec..b0961265345c0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -271,6 +271,7 @@ Clang-Tidy Checks
:doc:`misc-no-recursion <misc/no-recursion>`,
:doc:`misc-non-copyable-objects <misc/non-copyable-objects>`,
:doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
+ :doc:`misc-override-with-
diff erent-visibility <misc/override-with-
diff erent-visibility>`,
:doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
:doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/override-with-
diff erent-visibility.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/override-with-
diff erent-visibility.rst
new file mode 100644
index 0000000000000..310bfe2b01080
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/override-with-
diff erent-visibility.rst
@@ -0,0 +1,87 @@
+.. title:: clang-tidy - misc-override-with-
diff erent-visibility
+
+misc-override-with-
diff erent-visibility
+=======================================
+
+Finds virtual function overrides with
diff erent visibility than the function
+in the base class. This includes for example if a virtual function declared as
+``private`` is overridden and declared as ``public`` in a subclass. The detected
+change is the modification of visibility resulting from keywords ``public``,
+``protected``, ``private`` at overridden virtual functions. The check applies to
+any normal virtual function and optionally to destructors or operators. Use of
+the ``using`` keyword is not considered as visibility change by this check.
+
+
+.. code-block:: c++
+
+ class A {
+ public:
+ virtual void f_pub();
+ private:
+ virtual void f_priv();
+ };
+
+ class B: public A {
+ public:
+ void f_priv(); // warning: changed visibility from private to public
+ private:
+ void f_pub(); // warning: changed visibility from public to private
+ };
+
+ class C: private A {
+ // no warning: f_pub becomes private in this case but this is from the
+ // private inheritance
+ };
+
+ class D: private A {
+ public:
+ void f_pub(); // warning: changed visibility from private to public
+ // 'f_pub' would have private access but is forced to be
+ // public
+ };
+
+If the visibility is changed in this way, it can indicate bad design or
+programming error.
+
+If a virtual function is private in a subclass but public in the base class, it
+can still be accessed from a pointer to the subclass if the pointer is converted
+to the base type. Probably private inheritance can be used instead.
+
+A protected virtual function that is made public in a subclass may have valid
+use cases but similar (not exactly same) effect can be achieved with the
+``using`` keyword.
+
+Options
+-------
+
+.. option:: DisallowedVisibilityChange
+
+ Controls what kind of change to the visibility will be detected by the check.
+ Possible values are `any`, `widening`, `narrowing`. For example the
+ `widening` option will produce warning only if the visibility is changed
+ from more restrictive (``private``) to less restrictive (``public``).
+ Default value is `any`.
+
+.. option:: CheckDestructors
+
+ If `true`, the check does apply to destructors too. Otherwise destructors
+ are ignored by the check.
+ Default value is `false`.
+
+.. option:: CheckOperators
+
+ If `true`, the check does apply to overloaded C++ operators (as virtual
+ member functions) too. This includes other special member functions (like
+ conversions) too. This option is probably useful only in rare cases because
+ operators and conversions are not often virtual functions.
+ Default value is `false`.
+
+.. option:: IgnoredFunctions
+
+ This option can be used to ignore the check at specific functions.
+ To configure this option, a semicolon-separated list of function names
+ should be provided. The list can contain regular expressions, in this way it
+ is possible to select all functions of a specific class (like `MyClass::.*`)
+ or a specific function of any class (like `my_function` or
+ `::.*::my_function`). The function names are matched at the base class.
+ Default value is empty string.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-
diff erent-visibility/test-system-header.h b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-
diff erent-visibility/test-system-header.h
new file mode 100644
index 0000000000000..e64e1924a1708
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/override-with-
diff erent-visibility/test-system-header.h
@@ -0,0 +1,14 @@
+#pragma clang system_header
+
+namespace sys {
+
+struct Base {
+ virtual void publicF();
+};
+
+struct Derived: public Base {
+private:
+ void publicF() override;
+};
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility-ignore.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility-ignore.cpp
new file mode 100644
index 0000000000000..934cfb7bc7082
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility-ignore.cpp
@@ -0,0 +1,60 @@
+// RUN: %check_clang_tidy %s misc-override-with-
diff erent-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-
diff erent-visibility.IgnoredFunctions: 'IgnoreAlways::.*;::a::IgnoreSelected::.*;IgnoreFunctions::f1;ignored_f'}}"
+
+class IgnoreAlways {
+ virtual void f();
+};
+
+class IgnoreSelected {
+ virtual void f();
+};
+
+namespace a {
+class IgnoreAlways {
+ virtual void f();
+};
+class IgnoreSelected {
+ virtual void f();
+};
+}
+
+namespace ignore_always {
+class Test1: public IgnoreAlways {
+public:
+ void f();
+ void ignored_f(int);
+};
+class Test2: public a::IgnoreAlways {
+public:
+ void f();
+};
+}
+
+namespace ignore_selected {
+class Test1: public IgnoreSelected {
+public:
+ void f();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'f'
+ // CHECK-MESSAGES: :9:16: note: function declared here
+ void ignored_f(int);
+};
+class Test2: public a::IgnoreSelected {
+public:
+ void f();
+};
+}
+
+class IgnoreFunctions {
+ virtual void f1();
+ virtual void f2();
+ virtual void ignored_f();
+};
+
+class IgnoreFunctionsTest: public IgnoreFunctions {
+public:
+ void f1();
+ void f2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'f2'
+ // CHECK-MESSAGES: :[[@LINE-9]]:16: note: function declared here
+ void ignored_f();
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility-options.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility-options.cpp
new file mode 100644
index 0000000000000..0a363ddee3806
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility-options.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy -check-suffixes=DTORS,WIDENING,NARROWING %s misc-override-with-
diff erent-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-
diff erent-visibility.CheckDestructors: true}}"
+
+// RUN: %check_clang_tidy -check-suffixes=OPS,WIDENING,NARROWING %s misc-override-with-
diff erent-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-
diff erent-visibility.CheckOperators: true}}"
+
+// RUN: %check_clang_tidy -check-suffixes=WIDENING %s misc-override-with-
diff erent-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-
diff erent-visibility.DisallowedVisibilityChange: 'widening'}}"
+
+// RUN: %check_clang_tidy -check-suffixes=NARROWING %s misc-override-with-
diff erent-visibility %t -- \
+// RUN: -config="{CheckOptions: {misc-override-with-
diff erent-visibility.DisallowedVisibilityChange: 'narrowing'}}"
+
+namespace test_change {
+
+class A {
+protected:
+ virtual void f1();
+ virtual void f2();
+};
+
+class B: public A {
+public:
+ void f1();
+ // CHECK-MESSAGES-WIDENING: :[[@LINE-1]]:8: warning: visibility of function 'f1'
+ // CHECK-MESSAGES-WIDENING: :[[@LINE-8]]:16: note: function declared here
+private:
+ void f2();
+ // CHECK-MESSAGES-NARROWING: :[[@LINE-1]]:8: warning: visibility of function 'f2'
+ // CHECK-MESSAGES-NARROWING: :[[@LINE-11]]:16: note: function declared here
+};
+
+}
+
+namespace test_destructor {
+
+class A {
+public:
+ virtual ~A();
+};
+
+class B: public A {
+protected:
+ ~B();
+ // CHECK-MESSAGES-DTORS: :[[@LINE-1]]:3: warning: visibility of function '~B'
+ // CHECK-MESSAGES-DTORS: :[[@LINE-7]]:11: note: function declared here
+};
+
+}
+
+namespace test_operator {
+
+class A {
+ virtual A& operator=(const A&);
+ virtual A& operator++();
+ virtual int operator()(int);
+ virtual operator double() const;
+};
+
+class B: public A {
+protected:
+ A& operator=(const A&);
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:6: warning: visibility of function 'operator='
+ // CHECK-MESSAGES-OPS: :[[@LINE-10]]:14: note: function declared here
+ A& operator++();
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:6: warning: visibility of function 'operator++'
+ // CHECK-MESSAGES-OPS: :[[@LINE-12]]:14: note: function declared here
+ int operator()(int);
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:7: warning: visibility of function 'operator()'
+ // CHECK-MESSAGES-OPS: :[[@LINE-14]]:15: note: function declared here
+ operator double() const;
+ // CHECK-MESSAGES-OPS: :[[@LINE-1]]:3: warning: visibility of function 'operator double'
+ // CHECK-MESSAGES-OPS: :[[@LINE-16]]:11: note: function declared here
+};
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility.cpp
new file mode 100644
index 0000000000000..fd541a44dc25f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/override-with-
diff erent-visibility.cpp
@@ -0,0 +1,289 @@
+// RUN: %check_clang_tidy %s misc-override-with-
diff erent-visibility %t -- -config="{CheckOptions: {misc-override-with-
diff erent-visibility.CheckDestructors: true,misc-override-with-
diff erent-visibility.CheckOperators: true}}" -- -I %S/Inputs/override-with-
diff erent-visibility
+#include <test-system-header.h>
+class A {
+public:
+ virtual void pub_foo1() {}
+ virtual void pub_foo2() {}
+ virtual void pub_foo3() {}
+protected:
+ virtual void prot_foo1();
+ virtual void prot_foo2();
+ virtual void prot_foo3();
+private:
+ virtual void priv_foo1() {}
+ virtual void priv_foo2() {}
+ virtual void priv_foo3() {}
+};
+
+void A::prot_foo1() {}
+void A::prot_foo2() {}
+void A::prot_foo3() {}
+
+namespace test1 {
+
+class B: public A {
+public:
+ void pub_foo1() override {}
+ void prot_foo1() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from protected in class 'A' to public [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :9:16: note: function declared here as protected
+ void priv_foo1() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo1' is changed from private in class 'A' to public [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :13:16: note: function declared here as private
+protected:
+ void pub_foo2() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo2' is changed from public in class 'A' to protected [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :6:16: note: function declared here as public
+ void prot_foo2() override {}
+ void priv_foo2() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo2' is changed from private in class 'A' to protected [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :14:16: note: function declared here as private
+private:
+ void pub_foo3() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo3' is changed from public in class 'A' to private [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :7:16: note: function declared here as public
+ void prot_foo3() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo3' is changed from protected in class 'A' to private [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :11:16: note: function declared here as protected
+ void priv_foo3() override {}
+};
+
+class C: public B {
+public:
+ void pub_foo1() override;
+protected:
+ void prot_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from public in class 'B' to protected [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :27:8: note: function declared here as public
+private:
+ void priv_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo1' is changed from public in class 'B' to private [misc-override-with-
diff erent-visibility]
+ // CHECK-MESSAGES: :30:8: note: function declared here as public
+};
+
+void C::prot_foo1() {}
+void C::priv_foo1() {}
+
+}
+
+namespace test2 {
+
+class B: public A {
+public:
+ void pub_foo1() override;
+protected:
+ void prot_foo1() override;
+private:
+ void priv_foo1() override;
+};
+
+class C: public B {
+public:
+ void pub_foo1() override;
+ void prot_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from protected in class 'B' to public
+ // CHECK-MESSAGES: :75:8: note: function declared here as protected
+ void priv_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo1' is changed from private in class 'B' to public
+ // CHECK-MESSAGES: :77:8: note: function declared here as private
+
+ void pub_foo2() override;
+ void prot_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo2' is changed from protected in class 'A' to public
+ // CHECK-MESSAGES: :10:16: note: function declared here as protected
+ void priv_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo2' is changed from private in class 'A' to public
+ // CHECK-MESSAGES: :14:16: note: function declared here as private
+};
+
+}
+
+namespace test3 {
+
+class B: private A {
+public:
+ void pub_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo1' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :103:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :5:16: note: function declared here as public
+protected:
+ void prot_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo1' is changed from private (through private inheritance of class 'A') to protected
+ // CHECK-MESSAGES: :103:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :9:16: note: function declared here as protected
+private:
+ void priv_foo1() override;
+
+public:
+ void prot_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'prot_foo2' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :103:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :10:16: note: function declared here as protected
+ void priv_foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'priv_foo2' is changed from private in class 'A' to public
+ // CHECK-MESSAGES: :14:16: note: function declared here as private
+
+private:
+ void pub_foo3() override;
+ void prot_foo3() override;
+};
+
+class C: private A {
+};
+
+class D: public C {
+public:
+ void pub_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo1' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :131:10: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :5:16: note: function declared here as public
+};
+
+
+}
+
+namespace test4 {
+
+struct Base1 {
+public:
+ virtual void foo1();
+private:
+ virtual void foo2();
+};
+
+struct Base2 {
+public:
+ virtual void foo2();
+private:
+ virtual void foo1();
+};
+
+struct A : public Base1, public Base2 {
+protected:
+ void foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'foo1' is changed from private in class 'Base2' to protected
+ // CHECK-MESSAGES: :158:16: note: function declared here as private
+ // CHECK-MESSAGES: :[[@LINE-3]]:8: warning: visibility of function 'foo1' is changed from public in class 'Base1' to protected
+ // CHECK-MESSAGES: :149:16: note: function declared here as public
+private:
+ void foo2() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'foo2' is changed from public in class 'Base2' to private
+ // CHECK-MESSAGES: :156:16: note: function declared here as public
+};
+
+}
+
+namespace test5 {
+
+struct B1: virtual public A {};
+struct B2: virtual private A {};
+struct B: public B1, public B2 {
+public:
+ void pub_foo1() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'pub_foo1' is changed from private (through private inheritance of class 'A') to public
+ // CHECK-MESSAGES: :179:12: note: 'A' is inherited as private here
+ // CHECK-MESSAGES: :5:16: note: function declared here as public
+};
+
+}
+
+namespace test_using {
+
+class A {
+private:
+ A(int);
+protected:
+ virtual void f();
+};
+
+class B: public A {
+public:
+ using A::A;
+ using A::f;
+};
+
+}
+
+namespace test_template {
+
+template <typename T>
+class A {
+protected:
+ virtual T foo();
+};
+
+template <typename T>
+class B: public A<T> {
+private:
+ T foo() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: visibility of function 'foo' is changed from protected in class 'A<int>' to private
+ // CHECK-MESSAGES: :[[@LINE-8]]:13: note: function declared here as protected
+};
+
+template <typename T>
+class C: private A<T> {
+public:
+ T foo() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: visibility of function 'foo' is changed from private (through private inheritance of class 'A<int>') to public
+ // CHECK-MESSAGES: :[[@LINE-4]]:10: note: 'A<int>' is inherited as private here
+ // CHECK-MESSAGES: :[[@LINE-17]]:13: note: function declared here as protected
+};
+
+B<int> fB() {
+ return B<int>{};
+}
+
+C<int> fC() {
+ return C<int>{};
+}
+
+}
+
+namespace test_system_header {
+
+struct SysDerived: public sys::Base {
+private:
+ void publicF();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: visibility of function 'publicF' is changed from public in class 'Base' to private
+};
+
+}
+
+namespace test_destructor {
+
+class A {
+public:
+ virtual ~A();
+};
+
+class B: public A {
+protected:
+ ~B();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: visibility of function '~B'
+ // CHECK-MESSAGES: :[[@LINE-7]]:11: note: function declared here
+};
+
+}
+
+namespace test_operator {
+
+class A {
+ virtual int operator()(int);
+ virtual A& operator++();
+ virtual operator double() const;
+};
+
+class B: public A {
+protected:
+ int operator()(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: visibility of function 'operator()'
+ // CHECK-MESSAGES: :[[@LINE-9]]:15: note: function declared here
+ A& operator++();
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: visibility of function 'operator++'
+ // CHECK-MESSAGES: :[[@LINE-11]]:14: note: function declared here
+ operator double() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: visibility of function 'operator double'
+ // CHECK-MESSAGES: :[[@LINE-13]]:11: note: function declared here
+};
+
+}
More information about the cfe-commits
mailing list