diff options
Diffstat (limited to 'clang-tools-extra/clang-doc/Serialize.cpp')
| -rw-r--r-- | clang-tools-extra/clang-doc/Serialize.cpp | 141 |
1 files changed, 121 insertions, 20 deletions
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 140f40fe0a8..559bc1285e9 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -230,27 +230,72 @@ static bool isPublic(const clang::AccessSpecifier AS, return false; // otherwise, linkage is some form of internal linkage } -static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) { +static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace, + const NamedDecl *D) { + bool IsAnonymousNamespace = false; + if (const auto *N = dyn_cast<NamespaceDecl>(D)) + IsAnonymousNamespace = N->isAnonymousNamespace(); + return !PublicOnly || + (!IsInAnonymousNamespace && !IsAnonymousNamespace && + isPublic(D->getAccessUnsafe(), D->getLinkageInternal())); +} + +// There are two uses for this function. +// 1) Getting the resulting mode of inheritance of a record. +// Example: class A {}; class B : private A {}; class C : public B {}; +// It's explicit that C is publicly inherited from C and B is privately +// inherited from A. It's not explicit but C is also privately inherited from +// A. This is the AS that this function calculates. FirstAS is the +// inheritance mode of `class C : B` and SecondAS is the inheritance mode of +// `class B : A`. +// 2) Getting the inheritance mode of an inherited attribute / method. +// Example : class A { public: int M; }; class B : private A {}; +// Class B is inherited from class A, which has a public attribute. This +// attribute is now part of the derived class B but it's not public. This +// will be private because the inheritance is private. This is the AS that +// this function calculates. FirstAS is the inheritance mode and SecondAS is +// the AS of the attribute / method. +static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS, + AccessSpecifier SecondAS) { + if (FirstAS == AccessSpecifier::AS_none || + SecondAS == AccessSpecifier::AS_none) + return AccessSpecifier::AS_none; + if (FirstAS == AccessSpecifier::AS_private || + SecondAS == AccessSpecifier::AS_private) + return AccessSpecifier::AS_private; + if (FirstAS == AccessSpecifier::AS_protected || + SecondAS == AccessSpecifier::AS_protected) + return AccessSpecifier::AS_protected; + return AccessSpecifier::AS_public; +} + +// The Access parameter is only provided when parsing the field of an inherited +// record, the access specification of the field depends on the inheritance mode +static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly, + AccessSpecifier Access = AccessSpecifier::AS_public) { for (const FieldDecl *F : D->fields()) { - if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal())) + if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F)) continue; if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) { // Use getAccessUnsafe so that we just get the default AS_none if it's not // valid, as opposed to an assert. if (const auto *N = dyn_cast<EnumDecl>(T)) { - I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(), - InfoType::IT_enum, getInfoRelativePath(N), - F->getNameAsString(), N->getAccessUnsafe()); + I.Members.emplace_back( + getUSRForDecl(T), N->getNameAsString(), InfoType::IT_enum, + getInfoRelativePath(N), F->getNameAsString(), + getFinalAccessSpecifier(Access, N->getAccessUnsafe())); continue; } else if (const auto *N = dyn_cast<RecordDecl>(T)) { - I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(), - InfoType::IT_record, getInfoRelativePath(N), - F->getNameAsString(), N->getAccessUnsafe()); + I.Members.emplace_back( + getUSRForDecl(T), N->getNameAsString(), InfoType::IT_record, + getInfoRelativePath(N), F->getNameAsString(), + getFinalAccessSpecifier(Access, N->getAccessUnsafe())); continue; } } - I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(), - F->getNameAsString(), F->getAccessUnsafe()); + I.Members.emplace_back( + F->getTypeSourceInfo()->getType().getAsString(), F->getNameAsString(), + getFinalAccessSpecifier(Access, F->getAccessUnsafe())); } } @@ -279,6 +324,8 @@ static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { } } +// TODO: Remove the serialization of Parents and VirtualParents, this +// information is also extracted in the other definition of parseBases. static void parseBases(RecordInfo &I, const CXXRecordDecl *D) { // Don't parse bases if this isn't a definition. if (!D->isThisDeclarationADefinition()) @@ -376,15 +423,71 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, parseParameters(I, D); } +static void +parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, + bool PublicOnly, bool IsParent, + AccessSpecifier ParentAccess = AccessSpecifier::AS_public) { + // Don't parse bases if this isn't a definition. + if (!D->isThisDeclarationADefinition()) + return; + for (const CXXBaseSpecifier &B : D->bases()) { + if (const RecordType *Ty = B.getType()->getAs<RecordType>()) { + if (const CXXRecordDecl *Base = + cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) { + // Initialized without USR and name, this will be set in the following + // if-else stmt. + BaseRecordInfo BI( + {}, "", getInfoRelativePath(Base), B.isVirtual(), + getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()), + IsParent); + if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) { + const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl(); + BI.USR = getUSRForDecl(D); + BI.Name = B.getType().getAsString(); + } else { + BI.USR = getUSRForDecl(Base); + BI.Name = Base->getNameAsString(); + } + parseFields(BI, Base, PublicOnly, BI.Access); + for (const auto &Decl : Base->decls()) + if (const auto *MD = dyn_cast<CXXMethodDecl>(Decl)) { + // Don't serialize private methods + if (MD->getAccessUnsafe() == AccessSpecifier::AS_private || + !MD->isUserProvided()) + continue; + FunctionInfo FI; + FI.IsMethod = true; + // The seventh arg in populateFunctionInfo is a boolean passed by + // reference, its value is not relevant in here so it's not used + // anywhere besides the function call. + bool IsInAnonymousNamespace; + populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{}, + /*FileName=*/{}, IsFileInRootDir, + IsInAnonymousNamespace); + FI.Access = + getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe()); + BI.ChildFunctions.emplace_back(std::move(FI)); + } + I.Bases.emplace_back(std::move(BI)); + // Call this function recursively to get the inherited classes of + // this base; these new bases will also get stored in the original + // RecordInfo: I. + parseBases(I, Base, IsFileInRootDir, PublicOnly, false, + I.Bases.back().Access); + } + } + } +} + std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { auto I = std::make_unique<NamespaceInfo>(); bool IsInAnonymousNamespace = false; populateInfo(*I, D, FC, IsInAnonymousNamespace); - if (PublicOnly && ((IsInAnonymousNamespace || D->isAnonymousNamespace()) || - !isPublic(D->getAccess(), D->getLinkageInternal()))) + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; + I->Name = D->isAnonymousNamespace() ? llvm::SmallString<16>("@nonymous_namespace") : I->Name; @@ -409,8 +512,7 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, bool IsInAnonymousNamespace = false; populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir, IsInAnonymousNamespace); - if (PublicOnly && ((IsInAnonymousNamespace || - !isPublic(D->getAccess(), D->getLinkageInternal())))) + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; I->TagType = D->getTagKind(); @@ -420,7 +522,9 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, I->Name = TD->getNameAsString(); I->IsTypeDef = true; } + // TODO: remove first call to parseBases, that function should be deleted parseBases(*I, C); + parseBases(*I, C, IsFileInRootDir, PublicOnly, true); } I->Path = getInfoRelativePath(I->Namespace); @@ -464,8 +568,7 @@ emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber, populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, IsInAnonymousNamespace); Func.Access = clang::AccessSpecifier::AS_none; - if (PublicOnly && ((IsInAnonymousNamespace || - !isPublic(D->getAccess(), D->getLinkageInternal())))) + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; // Wrap in enclosing scope @@ -488,8 +591,7 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, bool IsInAnonymousNamespace = false; populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, IsInAnonymousNamespace); - if (PublicOnly && ((IsInAnonymousNamespace || - !isPublic(D->getAccess(), D->getLinkageInternal())))) + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; Func.IsMethod = true; @@ -523,8 +625,7 @@ emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber, bool IsInAnonymousNamespace = false; populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir, IsInAnonymousNamespace); - if (PublicOnly && ((IsInAnonymousNamespace || - !isPublic(D->getAccess(), D->getLinkageInternal())))) + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; Enum.Scoped = D->isScoped(); |

