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