|
16 | 16 | #ifndef SWIFT_CLANG_IMPORTER_H
|
17 | 17 | #define SWIFT_CLANG_IMPORTER_H
|
18 | 18 |
|
| 19 | +#include "swift/AST/Attr.h" |
19 | 20 | #include "swift/AST/AttrKind.h"
|
20 | 21 | #include "swift/AST/ClangModuleLoader.h"
|
21 | 22 | #include "clang/Basic/Specifiers.h"
|
@@ -72,6 +73,7 @@ namespace swift {
|
72 | 73 | class ASTContext;
|
73 | 74 | class CompilerInvocation;
|
74 | 75 | class ClangImporterOptions;
|
| 76 | +class ClangInheritanceInfo; |
75 | 77 | class ClangModuleUnit;
|
76 | 78 | class ClangNode;
|
77 | 79 | class ConcreteDeclRef;
|
@@ -660,8 +662,8 @@ class ClangImporter final : public ClangModuleLoader {
|
660 | 662 | /// Imports a clang decl directly, rather than looking up it's name.
|
661 | 663 | Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
|
662 | 664 |
|
663 |
| - ValueDecl *importBaseMemberDecl(ValueDecl *decl, |
664 |
| - DeclContext *newContext) override; |
| 665 | + ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext, |
| 666 | + ClangInheritanceInfo inheritance) override; |
665 | 667 |
|
666 | 668 | /// Emits diagnostics for any declarations named name
|
667 | 669 | /// whose direct declaration context is a TU.
|
@@ -779,6 +781,117 @@ ClangInvocationFileMapping getClangInvocationFileMapping(
|
779 | 781 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr,
|
780 | 782 | bool suppressDiagnostic = false);
|
781 | 783 |
|
| 784 | +/// Information used to compute the access level of inherited C++ members. |
| 785 | +class ClangInheritanceInfo { |
| 786 | + /// The cumulative inheritance access specifier, that is used to compute the |
| 787 | + /// effective access level of a particular inherited member. |
| 788 | + /// |
| 789 | + /// When constructing ClangInheritanceInfo for nested inheritance, this field |
| 790 | + /// gets clamped to the least permissive level between its current value and |
| 791 | + /// the inheritance access specifier. |
| 792 | + /// |
| 793 | + /// If we encounter \e nested private inheritance in the class hierarchy |
| 794 | + /// (i.e., private inheritance beyond the first level of inheritance), we set |
| 795 | + /// the access level to nullopt to indicate that none of the members from |
| 796 | + /// classes beyond that point in the hierarchy should be accessible. This case |
| 797 | + /// must be treated separately from non-nested private inheritance, where |
| 798 | + /// inherited members are private but accessible from extensions. |
| 799 | + /// |
| 800 | + /// See ClangInheritanceInfo::cumulativeInheritedAccess() for an example. |
| 801 | + std::optional<clang::AccessSpecifier> access; |
| 802 | + |
| 803 | +public: |
| 804 | + /// Default constructor for this class that is used as the base case when |
| 805 | + /// recursively walking up a class inheritance hierarchy. |
| 806 | + ClangInheritanceInfo() : access(clang::AS_none) {} |
| 807 | + |
| 808 | + /// Inductive case for this class that is used to accumulate inheritance |
| 809 | + /// metadata for cases of (nested) inheritance. |
| 810 | + ClangInheritanceInfo(ClangInheritanceInfo prev, clang::CXXBaseSpecifier base) |
| 811 | + : access(computeAccess(prev, base)) {} |
| 812 | + |
| 813 | + /// Whether this info represents a case of nested private inheritance. |
| 814 | + bool isNestedPrivate() const { return !access.has_value(); } |
| 815 | + |
| 816 | + /// Whether this info represents a case of C++ inheritance. |
| 817 | + /// |
| 818 | + /// Returns \c false for the default instance of this class. |
| 819 | + bool isInheriting() const { |
| 820 | + return isNestedPrivate() || *access != clang::AS_none; |
| 821 | + } |
| 822 | + |
| 823 | + /// Whether this is info represents a case of C++ inheritance. |
| 824 | + operator bool() const { return isInheriting(); } |
| 825 | + |
| 826 | + /// Compute the (Swift) access level for inherited base member \param decl, |
| 827 | + /// for when its inherited (cloned) member in the derived class. |
| 828 | + /// |
| 829 | + /// This access level is determined by whichever is more restrictive: what the |
| 830 | + /// \param decl was declared with (in its base class), or what it is being |
| 831 | + /// inherited with (ClangInheritanceInfo::access). |
| 832 | + /// |
| 833 | + /// Always returns swift::AccessLevel::Public (i.e., corresponding to |
| 834 | + /// clang::AS_none) if this ClangInheritanceInfo::isInheriting() is \c false. |
| 835 | + AccessLevel accessForBaseDecl(const ValueDecl *baseDecl) const; |
| 836 | + |
| 837 | + /// Marks \param clonedDecl as unavailable (using \c @available) if it |
| 838 | + /// cannot be accessed from the derived class, either because \param baseDecl |
| 839 | + /// was declared as private in the base class, or because \param clonedDecl |
| 840 | + /// was inherited with private inheritance. |
| 841 | + /// |
| 842 | + /// Does nothing if this ClangInheritanceInfo::isInheriting() is \c false. |
| 843 | + void setUnavailableIfNecessary(const ValueDecl *baseDecl, |
| 844 | + ValueDecl *clonedDecl) const; |
| 845 | + |
| 846 | + friend llvm::hash_code hash_value(const ClangInheritanceInfo &info) { |
| 847 | + return llvm::hash_combine(info.access); |
| 848 | + } |
| 849 | + |
| 850 | +private: |
| 851 | + /// An example of how ClangInheritanceInfo:access is accumulated while |
| 852 | + /// recursively traversing the class hierarchy starting from \c E: |
| 853 | + /// |
| 854 | + /// \code{.cpp} |
| 855 | + /// struct A { ... }; // access = nullopt (nested private) |
| 856 | + /// struct B : private A { ... }; // access = protected |
| 857 | + /// struct C : public B { ... }; // access = protected |
| 858 | + /// struct D : protected C { ... }; // access = public |
| 859 | + /// struct E : public D { ... }; // access = none [base case] |
| 860 | + /// \endcode |
| 861 | + /// |
| 862 | + /// Another example, this time with non-nested private inheritance: |
| 863 | + /// |
| 864 | + /// \code{.cpp} |
| 865 | + /// struct A { ... }; // access = nullopt |
| 866 | + /// struct B : public A { ... }; // access = nullopt |
| 867 | + /// struct C : private B { ... }; // access = private |
| 868 | + /// struct D : public C { ... }; // access = private |
| 869 | + /// struct E : private D { ... }; // access = none [base case] |
| 870 | + /// \endcode |
| 871 | + static std::optional<clang::AccessSpecifier> |
| 872 | + computeAccess(ClangInheritanceInfo prev, clang::CXXBaseSpecifier base) { |
| 873 | + auto baseAccess = base.getAccessSpecifier(); |
| 874 | + assert(baseAccess != clang::AS_none && |
| 875 | + "this should always be public, protected, or private"); |
| 876 | + |
| 877 | + if (!prev.isInheriting()) |
| 878 | + // This is the first level of inheritance, so we just take the access |
| 879 | + // specifier from CXXBaseSpecifier. Note that this is the only scenario |
| 880 | + // where we can have access = private. |
| 881 | + return {baseAccess}; |
| 882 | + |
| 883 | + if (prev.isNestedPrivate() || baseAccess == clang::AS_private) |
| 884 | + // This is a case of nested inheritance, and either we encountered nested |
| 885 | + // private inheritance before, or this is our first time encountering it. |
| 886 | + return std::nullopt; |
| 887 | + |
| 888 | + static_assert(clang::AS_private > clang::AS_protected && |
| 889 | + clang::AS_protected > clang::AS_public && |
| 890 | + "using std::max() relies on this ordering"); |
| 891 | + return {std::max(*prev.access, baseAccess)}; |
| 892 | + } |
| 893 | +}; |
| 894 | + |
782 | 895 | } // end namespace swift
|
783 | 896 |
|
784 | 897 | #endif
|
0 commit comments