summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-doc/Serialize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-doc/Serialize.cpp')
-rw-r--r--clang-tools-extra/clang-doc/Serialize.cpp141
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();
OpenPOWER on IntegriCloud