[clang-tools-extra] r369075 - [clang-doc] Serialize inherited attributes and methods
Diego Astiazaran via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 15 17:10:49 PDT 2019
Author: diegoastiazaran
Date: Thu Aug 15 17:10:49 2019
New Revision: 369075
URL: http://llvm.org/viewvc/llvm-project?rev=369075&view=rev
Log:
[clang-doc] Serialize inherited attributes and methods
clang-doc now serializes the inherited attributes and methods, not only the name of the base class.
All inherited are tracked, if B:A and C:B, info of A is included in C.
This data is stored in attribute Bases in a RecordInfo.
Previously tracked inheritance data, stored in Parents and VParents, hasn't been removed to reduce review load.
Differential revision: https://reviews.llvm.org/D66238
Modified:
clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
clang-tools-extra/trunk/clang-doc/Representation.cpp
clang-tools-extra/trunk/clang-doc/Representation.h
clang-tools-extra/trunk/clang-doc/Serialize.cpp
clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp
clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp
clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h
clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp
clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
Modified: clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp Thu Aug 15 17:10:49 2019
@@ -180,6 +180,29 @@ llvm::Error parseRecord(Record R, unsign
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+ BaseRecordInfo *I) {
+ switch (ID) {
+ case BASE_RECORD_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case BASE_RECORD_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case BASE_RECORD_PATH:
+ return decodeRecord(R, I->Path, Blob);
+ case BASE_RECORD_TAG_TYPE:
+ return decodeRecord(R, I->TagType, Blob);
+ case BASE_RECORD_IS_VIRTUAL:
+ return decodeRecord(R, I->IsVirtual, Blob);
+ case BASE_RECORD_ACCESS:
+ return decodeRecord(R, I->Access, Blob);
+ case BASE_RECORD_IS_PARENT:
+ return decodeRecord(R, I->IsParent, Blob);
+ default:
+ return llvm::make_error<llvm::StringError>(
+ "Invalid field for BaseRecordInfo.\n", llvm::inconvertibleErrorCode());
+ }
+}
+
+llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
EnumInfo *I) {
switch (ID) {
case ENUM_USR:
@@ -350,6 +373,11 @@ template <> llvm::Error addTypeInfo(Reco
return llvm::Error::success();
}
+template <> llvm::Error addTypeInfo(BaseRecordInfo *I, MemberTypeInfo &&T) {
+ I->Members.emplace_back(std::move(T));
+ return llvm::Error::success();
+}
+
template <> llvm::Error addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
I->ReturnType = std::move(T);
return llvm::Error::success();
@@ -494,6 +522,14 @@ template <> void addChild(RecordInfo *I,
I->ChildEnums.emplace_back(std::move(R));
}
+template <> void addChild(RecordInfo *I, BaseRecordInfo &&R) {
+ I->Bases.emplace_back(std::move(R));
+}
+
+template <> void addChild(BaseRecordInfo *I, FunctionInfo &&R) {
+ I->ChildFunctions.emplace_back(std::move(R));
+}
+
// Read records from bitcode into a given info.
template <typename T>
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
@@ -598,6 +634,13 @@ llvm::Error ClangDocBitcodeReader::readS
addChild(I, std::move(F));
return llvm::Error::success();
}
+ case BI_BASE_RECORD_BLOCK_ID: {
+ BaseRecordInfo BR;
+ if (auto Err = readBlock(ID, &BR))
+ return Err;
+ addChild(I, std::move(BR));
+ return llvm::Error::success();
+ }
case BI_ENUM_BLOCK_ID: {
EnumInfo E;
if (auto Err = readBlock(ID, &E))
Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp Thu Aug 15 17:10:49 2019
@@ -116,6 +116,7 @@ static const llvm::IndexedMap<llvm::Stri
{BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
{BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
{BI_RECORD_BLOCK_ID, "RecordBlock"},
+ {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"},
{BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
{BI_COMMENT_BLOCK_ID, "CommentBlock"},
{BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}};
@@ -165,6 +166,13 @@ static const llvm::IndexedMap<RecordIdDs
{RECORD_LOCATION, {"Location", &LocationAbbrev}},
{RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
{RECORD_IS_TYPE_DEF, {"IsTypeDef", &BoolAbbrev}},
+ {BASE_RECORD_USR, {"USR", &SymbolIDAbbrev}},
+ {BASE_RECORD_NAME, {"Name", &StringAbbrev}},
+ {BASE_RECORD_PATH, {"Path", &StringAbbrev}},
+ {BASE_RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
+ {BASE_RECORD_IS_VIRTUAL, {"IsVirtual", &BoolAbbrev}},
+ {BASE_RECORD_ACCESS, {"Access", &IntAbbrev}},
+ {BASE_RECORD_IS_PARENT, {"IsParent", &BoolAbbrev}},
{FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
{FUNCTION_NAME, {"Name", &StringAbbrev}},
{FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
@@ -213,6 +221,11 @@ static const std::vector<std::pair<Block
{BI_RECORD_BLOCK_ID,
{RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
+ // BaseRecord Block
+ {BI_BASE_RECORD_BLOCK_ID,
+ {BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,
+ BASE_RECORD_TAG_TYPE, BASE_RECORD_IS_VIRTUAL, BASE_RECORD_ACCESS,
+ BASE_RECORD_IS_PARENT}},
// Function Block
{BI_FUNCTION_BLOCK_ID,
{FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
@@ -494,6 +507,8 @@ void ClangDocBitcodeWriter::emitBlock(co
emitBlock(P, FieldId::F_parent);
for (const auto &P : I.VirtualParents)
emitBlock(P, FieldId::F_vparent);
+ for (const auto &PB : I.Bases)
+ emitBlock(PB);
for (const auto &C : I.ChildRecords)
emitBlock(C, FieldId::F_child_record);
for (const auto &C : I.ChildFunctions)
@@ -502,6 +517,21 @@ void ClangDocBitcodeWriter::emitBlock(co
emitBlock(C);
}
+void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);
+ emitRecord(I.USR, BASE_RECORD_USR);
+ emitRecord(I.Name, BASE_RECORD_NAME);
+ emitRecord(I.Path, BASE_RECORD_PATH);
+ emitRecord(I.TagType, BASE_RECORD_TAG_TYPE);
+ emitRecord(I.IsVirtual, BASE_RECORD_IS_VIRTUAL);
+ emitRecord(I.Access, BASE_RECORD_ACCESS);
+ emitRecord(I.IsParent, BASE_RECORD_IS_PARENT);
+ for (const auto &M : I.Members)
+ emitBlock(M);
+ for (const auto &C : I.ChildFunctions)
+ emitBlock(C);
+}
+
void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
emitRecord(I.USR, FUNCTION_USR);
Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.h?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h Thu Aug 15 17:10:49 2019
@@ -30,7 +30,7 @@ namespace doc {
// Current version number of clang-doc bitcode.
// Should be bumped when removing or changing BlockIds, RecordIds, or
// BitCodeConstants, though they can be added without breaking it.
-static const unsigned VersionNumber = 2;
+static const unsigned VersionNumber = 3;
struct BitCodeConstants {
static constexpr unsigned RecordSize = 32U;
@@ -58,6 +58,7 @@ enum BlockId {
BI_FIELD_TYPE_BLOCK_ID,
BI_MEMBER_TYPE_BLOCK_ID,
BI_RECORD_BLOCK_ID,
+ BI_BASE_RECORD_BLOCK_ID,
BI_FUNCTION_BLOCK_ID,
BI_COMMENT_BLOCK_ID,
BI_REFERENCE_BLOCK_ID,
@@ -105,6 +106,13 @@ enum RecordId {
RECORD_LOCATION,
RECORD_TAG_TYPE,
RECORD_IS_TYPE_DEF,
+ BASE_RECORD_USR,
+ BASE_RECORD_NAME,
+ BASE_RECORD_PATH,
+ BASE_RECORD_TAG_TYPE,
+ BASE_RECORD_IS_VIRTUAL,
+ BASE_RECORD_ACCESS,
+ BASE_RECORD_IS_PARENT,
REFERENCE_USR,
REFERENCE_NAME,
REFERENCE_TYPE,
@@ -143,6 +151,7 @@ public:
// Block emission of different info types.
void emitBlock(const NamespaceInfo &I);
void emitBlock(const RecordInfo &I);
+ void emitBlock(const BaseRecordInfo &I);
void emitBlock(const FunctionInfo &I);
void emitBlock(const EnumInfo &I);
void emitBlock(const TypeInfo &B);
Modified: clang-tools-extra/trunk/clang-doc/Representation.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp Thu Aug 15 17:10:49 2019
@@ -178,6 +178,8 @@ void RecordInfo::merge(RecordInfo &&Othe
TagType = Other.TagType;
if (Members.empty())
Members = std::move(Other.Members);
+ if (Bases.empty())
+ Bases = std::move(Other.Bases);
if (Parents.empty())
Parents = std::move(Other.Parents);
if (VirtualParents.empty())
Modified: clang-tools-extra/trunk/clang-doc/Representation.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.h Thu Aug 15 17:10:49 2019
@@ -32,6 +32,7 @@ using SymbolID = std::array<uint8_t, 20>
struct Info;
struct FunctionInfo;
struct EnumInfo;
+struct BaseRecordInfo;
enum class InfoType {
IT_default,
@@ -345,15 +346,33 @@ struct RecordInfo : public SymbolInfo {
llvm::SmallVector<Reference, 4>
VirtualParents; // List of virtual base/parent records.
- // Records are references because they will be properly
- // documented in their own info, while the entirety of Functions and Enums are
- // included here because they should not have separate documentation from
- // their scope.
+ std::vector<BaseRecordInfo>
+ Bases; // List of base/parent records; this includes inherited methods and
+ // attributes
+
+ // Records are references because they will be properly documented in their
+ // own info, while the entirety of Functions and Enums are included here
+ // because they should not have separate documentation from their scope.
std::vector<Reference> ChildRecords;
std::vector<FunctionInfo> ChildFunctions;
std::vector<EnumInfo> ChildEnums;
};
+struct BaseRecordInfo : public RecordInfo {
+ BaseRecordInfo() : RecordInfo() {}
+ BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, bool IsVirtual,
+ AccessSpecifier Access, bool IsParent)
+ : RecordInfo(USR, Name, Path), IsVirtual(IsVirtual), Access(Access),
+ IsParent(IsParent) {}
+
+ // Indicates if base corresponds to a virtual inheritance
+ bool IsVirtual = false;
+ // Access level associated with this inherited info (public, protected,
+ // private).
+ AccessSpecifier Access = AccessSpecifier::AS_public;
+ bool IsParent = false; // Indicates if this base is a direct parent
+};
+
// TODO: Expand to allow for documenting templating.
// Info for types.
struct EnumInfo : public SymbolInfo {
Modified: clang-tools-extra/trunk/clang-doc/Serialize.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Serialize.cpp Thu Aug 15 17:10:49 2019
@@ -230,27 +230,72 @@ static bool isPublic(const clang::Access
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
}
}
+// 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(Functio
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 Full
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 Full
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 Fu
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 F
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 FullCo
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();
Modified: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp Thu Aug 15 17:10:49 2019
@@ -21,6 +21,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
@@ -124,6 +125,19 @@ static void SymbolInfoMapping(IO &IO, Sy
IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
}
+static void RecordInfoMapping(IO &IO, RecordInfo &I) {
+ SymbolInfoMapping(IO, I);
+ IO.mapOptional("TagType", I.TagType, clang::TagTypeKind::TTK_Struct);
+ IO.mapOptional("Members", I.Members);
+ IO.mapOptional("Bases", I.Bases);
+ IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
+ IO.mapOptional("VirtualParents", I.VirtualParents,
+ llvm::SmallVector<Reference, 4>());
+ IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
+ IO.mapOptional("ChildFunctions", I.ChildFunctions);
+ IO.mapOptional("ChildEnums", I.ChildEnums);
+}
+
static void CommentInfoMapping(IO &IO, CommentInfo &I) {
IO.mapOptional("Kind", I.Kind, SmallString<16>());
IO.mapOptional("Text", I.Text, SmallString<64>());
@@ -193,16 +207,18 @@ template <> struct MappingTraits<Namespa
};
template <> struct MappingTraits<RecordInfo> {
- static void mapping(IO &IO, RecordInfo &I) {
- SymbolInfoMapping(IO, I);
- IO.mapOptional("TagType", I.TagType, clang::TagTypeKind::TTK_Struct);
- IO.mapOptional("Members", I.Members);
- IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
- IO.mapOptional("VirtualParents", I.VirtualParents,
- llvm::SmallVector<Reference, 4>());
- IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
- IO.mapOptional("ChildFunctions", I.ChildFunctions);
- IO.mapOptional("ChildEnums", I.ChildEnums);
+ static void mapping(IO &IO, RecordInfo &I) { RecordInfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<BaseRecordInfo> {
+ static void mapping(IO &IO, BaseRecordInfo &I) {
+ RecordInfoMapping(IO, I);
+ IO.mapOptional("IsVirtual", I.IsVirtual, false);
+ // clang::AccessSpecifier::AS_none is used as the default here because it's
+ // the AS that shouldn't be part of the output. Even though AS_public is the
+ // default in the struct, it should be displayed in the YAML output.
+ IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
+ IO.mapOptional("IsParent", I.IsParent, false);
}
};
Modified: clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp Thu Aug 15 17:10:49 2019
@@ -81,6 +81,10 @@ TEST(BitcodeTest, emitRecordInfoBitcode)
I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
I.TagType = TagTypeKind::TTK_Class;
I.IsTypeDef = true;
+ I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+ AccessSpecifier::AS_public, true);
+ I.Bases.back().ChildFunctions.emplace_back();
+ I.Bases.back().Members.emplace_back("int", "X", AccessSpecifier::AS_private);
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp Thu Aug 15 17:10:49 2019
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "ClangDocTest.h"
#include "Representation.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "gtest/gtest.h"
@@ -168,6 +169,10 @@ void CheckRecordInfo(RecordInfo *Expecte
for (size_t Idx = 0; Idx < Actual->VirtualParents.size(); ++Idx)
CheckReference(Expected->VirtualParents[Idx], Actual->VirtualParents[Idx]);
+ ASSERT_EQ(Expected->Bases.size(), Actual->Bases.size());
+ for (size_t Idx = 0; Idx < Actual->Bases.size(); ++Idx)
+ CheckBaseRecordInfo(&Expected->Bases[Idx], &Actual->Bases[Idx]);
+
ASSERT_EQ(Expected->ChildRecords.size(), Actual->ChildRecords.size());
for (size_t Idx = 0; Idx < Actual->ChildRecords.size(); ++Idx)
CheckReference(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
@@ -182,6 +187,14 @@ void CheckRecordInfo(RecordInfo *Expecte
CheckEnumInfo(&Expected->ChildEnums[Idx], &Actual->ChildEnums[Idx]);
}
+void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual) {
+ CheckRecordInfo(Expected, Actual);
+
+ EXPECT_EQ(Expected->IsVirtual, Actual->IsVirtual);
+ EXPECT_EQ(Expected->Access, Actual->Access);
+ EXPECT_EQ(Expected->IsParent, Actual->IsParent);
+}
+
void CheckIndex(Index &Expected, Index &Actual) {
CheckReference(Expected, Actual);
ASSERT_EQ(Expected.Children.size(), Actual.Children.size());
Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h Thu Aug 15 17:10:49 2019
@@ -43,6 +43,7 @@ void CheckFunctionInfo(FunctionInfo *Exp
void CheckEnumInfo(EnumInfo *Expected, EnumInfo *Actual);
void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual);
void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual);
+void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual);
void CheckIndex(Index &Expected, Index &Actual);
Modified: clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp Thu Aug 15 17:10:49 2019
@@ -87,6 +87,8 @@ TEST(MergeTest, mergeRecordInfos) {
One.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
One.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+ One.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+ AccessSpecifier::AS_protected, true);
One.ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
InfoType::IT_record);
One.ChildFunctions.emplace_back();
@@ -126,6 +128,8 @@ TEST(MergeTest, mergeRecordInfos) {
Expected->TagType = TagTypeKind::TTK_Class;
Expected->Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
Expected->VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+ Expected->Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+ AccessSpecifier::AS_protected, true);
Expected->ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
InfoType::IT_record, "path");
Modified: clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp Thu Aug 15 17:10:49 2019
@@ -321,15 +321,16 @@ TEST(SerializeTest, emitInlinedFunctionI
CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
}
-TEST(SerializeTest, ) {
+TEST(SerializeTest, emitInheritedRecordInfo) {
EmittedInfoList Infos;
- ExtractInfosFromCode(R"raw(class F {};
-class G {} ;
+ ExtractInfosFromCode(R"raw(class F { protected: void set(int N); };
+class G { public: int get() { return 1; } protected: int I; };
class E : public F, virtual private G {};
+class H : private E {};
template <typename T>
-class H {} ;
-class I : public H<int> {} ;)raw",
- 10, /*Public=*/false, Infos);
+class I {} ;
+class J : public I<int> {} ;)raw",
+ 14, /*Public=*/false, Infos);
RecordInfo *F = InfoAsRecord(Infos[0].get());
RecordInfo ExpectedF(EmptySID, "F");
@@ -337,32 +338,91 @@ class I : public H<int> {} ;)raw",
ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
CheckRecordInfo(&ExpectedF, F);
- RecordInfo *G = InfoAsRecord(Infos[2].get());
+ RecordInfo *G = InfoAsRecord(Infos[3].get());
RecordInfo ExpectedG(EmptySID, "G");
ExpectedG.TagType = TagTypeKind::TTK_Class;
ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
+ ExpectedG.Members.emplace_back("int", "I", AccessSpecifier::AS_protected);
CheckRecordInfo(&ExpectedG, G);
- RecordInfo *E = InfoAsRecord(Infos[4].get());
+ RecordInfo *E = InfoAsRecord(Infos[6].get());
RecordInfo ExpectedE(EmptySID, "E");
ExpectedE.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
ExpectedE.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+ ExpectedE.Bases.emplace_back(EmptySID, "F", "", false,
+ AccessSpecifier::AS_public, true);
+ FunctionInfo FunctionSet;
+ FunctionSet.Name = "set";
+ FunctionSet.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
+ FunctionSet.Loc.emplace_back();
+ FunctionSet.Params.emplace_back("int", "N");
+ FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
+ FunctionSet.Access = AccessSpecifier::AS_protected;
+ FunctionSet.IsMethod = true;
+ ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSet));
+ ExpectedE.Bases.emplace_back(EmptySID, "G", "", true,
+ AccessSpecifier::AS_private, true);
+ FunctionInfo FunctionGet;
+ FunctionGet.Name = "get";
+ FunctionGet.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default);
+ FunctionGet.DefLoc = Location();
+ FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
+ FunctionGet.Access = AccessSpecifier::AS_private;
+ FunctionGet.IsMethod = true;
+ ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGet));
+ ExpectedE.Bases.back().Members.emplace_back("int", "I",
+ AccessSpecifier::AS_private);
ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
ExpectedE.TagType = TagTypeKind::TTK_Class;
CheckRecordInfo(&ExpectedE, E);
- RecordInfo *H = InfoAsRecord(Infos[6].get());
+ RecordInfo *H = InfoAsRecord(Infos[8].get());
RecordInfo ExpectedH(EmptySID, "H");
ExpectedH.TagType = TagTypeKind::TTK_Class;
ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
+ ExpectedH.Parents.emplace_back(EmptySID, "E", InfoType::IT_record);
+ ExpectedH.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+ ExpectedH.Bases.emplace_back(EmptySID, "E", "", false,
+ AccessSpecifier::AS_private, true);
+ ExpectedH.Bases.emplace_back(EmptySID, "F", "", false,
+ AccessSpecifier::AS_private, false);
+ FunctionInfo FunctionSetNew;
+ FunctionSetNew.Name = "set";
+ FunctionSetNew.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
+ FunctionSetNew.Loc.emplace_back();
+ FunctionSetNew.Params.emplace_back("int", "N");
+ FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
+ FunctionSetNew.Access = AccessSpecifier::AS_private;
+ FunctionSetNew.IsMethod = true;
+ ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSetNew));
+ ExpectedH.Bases.emplace_back(EmptySID, "G", "", true,
+ AccessSpecifier::AS_private, false);
+ FunctionInfo FunctionGetNew;
+ FunctionGetNew.Name = "get";
+ FunctionGetNew.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default);
+ FunctionGetNew.DefLoc = Location();
+ FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
+ FunctionGetNew.Access = AccessSpecifier::AS_private;
+ FunctionGetNew.IsMethod = true;
+ ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGetNew));
+ ExpectedH.Bases.back().Members.emplace_back("int", "I",
+ AccessSpecifier::AS_private);
CheckRecordInfo(&ExpectedH, H);
- RecordInfo *I = InfoAsRecord(Infos[8].get());
+ RecordInfo *I = InfoAsRecord(Infos[10].get());
RecordInfo ExpectedI(EmptySID, "I");
- ExpectedI.Parents.emplace_back(EmptySID, "H<int>", InfoType::IT_record);
- ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
ExpectedI.TagType = TagTypeKind::TTK_Class;
+ ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
CheckRecordInfo(&ExpectedI, I);
+
+ RecordInfo *J = InfoAsRecord(Infos[12].get());
+ RecordInfo ExpectedJ(EmptySID, "J");
+ ExpectedJ.Parents.emplace_back(EmptySID, "I<int>", InfoType::IT_record);
+ ExpectedJ.Bases.emplace_back(EmptySID, "I<int>", "", false,
+ AccessSpecifier::AS_public, true);
+ ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
+ ExpectedJ.TagType = TagTypeKind::TTK_Class;
+ CheckRecordInfo(&ExpectedJ, J);
}
TEST(SerializeTest, emitModulePublicLFunctions) {
Modified: clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp?rev=369075&r1=369074&r2=369075&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp Thu Aug 15 17:10:49 2019
@@ -84,6 +84,12 @@ TEST(YAMLGeneratorTest, emitRecordYAML)
I.Members.emplace_back("int", "path/to/int", "X",
AccessSpecifier::AS_private);
I.TagType = TagTypeKind::TTK_Class;
+ I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+ AccessSpecifier::AS_public, true);
+ I.Bases.back().ChildFunctions.emplace_back();
+ I.Bases.back().ChildFunctions.back().Name = "InheritedFunctionOne";
+ I.Bases.back().Members.emplace_back("int", "path/to/int", "N",
+ AccessSpecifier::AS_private);
// F is in the global namespace
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "");
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
@@ -123,6 +129,24 @@ Members:
Path: 'path/to/int'
Name: 'X'
Access: Private
+Bases:
+ - USR: '0000000000000000000000000000000000000000'
+ Name: 'F'
+ Path: 'path/to/F'
+ Members:
+ - Type:
+ Name: 'int'
+ Path: 'path/to/int'
+ Name: 'N'
+ Access: Private
+ ChildFunctions:
+ - USR: '0000000000000000000000000000000000000000'
+ Name: 'InheritedFunctionOne'
+ ReturnType: {}
+ Access: Public
+ IsVirtual: true
+ Access: Public
+ IsParent: true
Parents:
- Type: Record
Name: 'F'
More information about the cfe-commits
mailing list