[clang-tidy] Added check 'misc-override-with-different-visibility' (#140086)

This commit is contained in:
Balázs Kéri 2025-08-18 11:00:42 +02:00 committed by GitHub
parent 87e6fd161a
commit a0f325bd41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 729 additions and 0 deletions

View File

@ -32,6 +32,7 @@ add_clang_library(clangTidyMiscModule STATIC
NoRecursionCheck.cpp NoRecursionCheck.cpp
NonCopyableObjects.cpp NonCopyableObjects.cpp
NonPrivateMemberVariablesInClassesCheck.cpp NonPrivateMemberVariablesInClassesCheck.cpp
OverrideWithDifferentVisibilityCheck.cpp
RedundantExpressionCheck.cpp RedundantExpressionCheck.cpp
StaticAssertCheck.cpp StaticAssertCheck.cpp
ThrowByValueCatchByReferenceCheck.cpp ThrowByValueCatchByReferenceCheck.cpp

View File

@ -22,6 +22,7 @@
#include "NoRecursionCheck.h" #include "NoRecursionCheck.h"
#include "NonCopyableObjects.h" #include "NonCopyableObjects.h"
#include "NonPrivateMemberVariablesInClassesCheck.h" #include "NonPrivateMemberVariablesInClassesCheck.h"
#include "OverrideWithDifferentVisibilityCheck.h"
#include "RedundantExpressionCheck.h" #include "RedundantExpressionCheck.h"
#include "StaticAssertCheck.h" #include "StaticAssertCheck.h"
#include "ThrowByValueCatchByReferenceCheck.h" #include "ThrowByValueCatchByReferenceCheck.h"
@ -81,6 +82,8 @@ public:
"misc-use-anonymous-namespace"); "misc-use-anonymous-namespace");
CheckFactories.registerCheck<UseInternalLinkageCheck>( CheckFactories.registerCheck<UseInternalLinkageCheck>(
"misc-use-internal-linkage"); "misc-use-internal-linkage");
CheckFactories.registerCheck<OverrideWithDifferentVisibilityCheck>(
"misc-override-with-different-visibility");
} }
}; };

View File

@ -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

View File

@ -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 different 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-different-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

View File

@ -134,6 +134,12 @@ New checks
Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form
and suggests using ``T::create`` instead. and suggests using ``T::create`` instead.
- New :doc:`misc-override-with-different-visibility
<clang-tidy/checks/misc/override-with-different-visibility>` check.
Finds virtual function overrides with different visibility than the function
in the base class.
New check aliases New check aliases
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^

View File

@ -271,6 +271,7 @@ Clang-Tidy Checks
:doc:`misc-no-recursion <misc/no-recursion>`, :doc:`misc-no-recursion <misc/no-recursion>`,
:doc:`misc-non-copyable-objects <misc/non-copyable-objects>`, :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-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
:doc:`misc-override-with-different-visibility <misc/override-with-different-visibility>`,
:doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes" :doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
:doc:`misc-static-assert <misc/static-assert>`, "Yes" :doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`, :doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,

View File

@ -0,0 +1,87 @@
.. title:: clang-tidy - misc-override-with-different-visibility
misc-override-with-different-visibility
=======================================
Finds virtual function overrides with different 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.

View File

@ -0,0 +1,14 @@
#pragma clang system_header
namespace sys {
struct Base {
virtual void publicF();
};
struct Derived: public Base {
private:
void publicF() override;
};
}

View File

@ -0,0 +1,60 @@
// RUN: %check_clang_tidy %s misc-override-with-different-visibility %t -- \
// RUN: -config="{CheckOptions: {misc-override-with-different-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();
};

View File

@ -0,0 +1,75 @@
// RUN: %check_clang_tidy -check-suffixes=DTORS,WIDENING,NARROWING %s misc-override-with-different-visibility %t -- \
// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.CheckDestructors: true}}"
// RUN: %check_clang_tidy -check-suffixes=OPS,WIDENING,NARROWING %s misc-override-with-different-visibility %t -- \
// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.CheckOperators: true}}"
// RUN: %check_clang_tidy -check-suffixes=WIDENING %s misc-override-with-different-visibility %t -- \
// RUN: -config="{CheckOptions: {misc-override-with-different-visibility.DisallowedVisibilityChange: 'widening'}}"
// RUN: %check_clang_tidy -check-suffixes=NARROWING %s misc-override-with-different-visibility %t -- \
// RUN: -config="{CheckOptions: {misc-override-with-different-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
};
}

View File

@ -0,0 +1,289 @@
// RUN: %check_clang_tidy %s misc-override-with-different-visibility %t -- -config="{CheckOptions: {misc-override-with-different-visibility.CheckDestructors: true,misc-override-with-different-visibility.CheckOperators: true}}" -- -I %S/Inputs/override-with-different-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-different-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-different-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-different-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-different-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-different-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-different-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-different-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-different-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
};
}