[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