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
+};
+
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to