dang updated this revision to Diff 420442.
dang added a comment.

Whitespace changes


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123019/new/

https://reviews.llvm.org/D123019

Files:
  clang/include/clang/ExtractAPI/API.h
  clang/include/clang/ExtractAPI/DeclarationFragments.h
  clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
  clang/lib/ExtractAPI/API.cpp
  clang/lib/ExtractAPI/CMakeLists.txt
  clang/lib/ExtractAPI/DeclarationFragments.cpp
  clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
  clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
  clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
  clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
  clang/test/ExtractAPI/typedef.c
  clang/test/ExtractAPI/typedef_anonymous_record.c
  clang/test/ExtractAPI/typedef_chain.c

Index: clang/test/ExtractAPI/typedef_chain.c
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/typedef_chain.c
@@ -0,0 +1,193 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/reference.output.json.in >> \
+// RUN: %t/reference.output.json
+// RUN: %clang -extract-api --product-name=TypedefChain -target arm64-apple-macosx \
+// RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+typedef int MyInt;
+typedef MyInt MyIntInt;
+typedef MyIntInt MyIntIntInt;
+
+//--- reference.output.json.in
+{
+  "metadata": {
+    "formatVersion": {
+      "major": 0,
+      "minor": 5,
+      "patch": 3
+    },
+    "generator": "?"
+  },
+  "module": {
+    "name": "TypedefChain",
+    "platform": {
+      "architecture": "arm64",
+      "operatingSystem": {
+        "minimumVersion": {
+          "major": 11,
+          "minor": 0,
+          "patch": 0
+        },
+        "name": "macosx"
+      },
+      "vendor": "apple"
+    }
+  },
+  "relationhips": [],
+  "symbols": [
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyInt"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:input.h@T@MyInt"
+      },
+      "kind": {
+        "displayName": "Type Alias",
+        "identifier": "objective-c.typealias"
+      },
+      "location": {
+        "character": 13,
+        "line": 1,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "MyInt"
+          }
+        ],
+        "title": "MyInt"
+      },
+      "type": "c:I"
+    },
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:input.h@T@MyInt",
+          "spelling": "MyInt"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyIntInt"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:input.h@T@MyIntInt"
+      },
+      "kind": {
+        "displayName": "Type Alias",
+        "identifier": "objective-c.typealias"
+      },
+      "location": {
+        "character": 15,
+        "line": 2,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "MyIntInt"
+          }
+        ],
+        "title": "MyIntInt"
+      },
+      "type": "c:input.h@T@MyInt"
+    },
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:input.h@T@MyIntInt",
+          "spelling": "MyIntInt"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyIntIntInt"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:input.h@T@MyIntIntInt"
+      },
+      "kind": {
+        "displayName": "Type Alias",
+        "identifier": "objective-c.typealias"
+      },
+      "location": {
+        "character": 18,
+        "line": 3,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "MyIntIntInt"
+          }
+        ],
+        "title": "MyIntIntInt"
+      },
+      "type": "c:input.h@T@MyIntInt"
+    }
+  ]
+}
Index: clang/test/ExtractAPI/typedef_anonymous_record.c
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/typedef_anonymous_record.c
@@ -0,0 +1,185 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/reference.output.json.in >> \
+// RUN: %t/reference.output.json
+// RUN: %clang -extract-api --product-name=TypedefChain -target arm64-apple-macosx \
+// RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+typedef struct { } MyStruct;
+typedef MyStruct MyStructStruct;
+typedef MyStructStruct MyStructStructStruct;
+
+//--- reference.output.json.in
+{
+  "metadata": {
+    "formatVersion": {
+      "major": 0,
+      "minor": 5,
+      "patch": 3
+    },
+    "generator": "?"
+  },
+  "module": {
+    "name": "TypedefChain",
+    "platform": {
+      "architecture": "arm64",
+      "operatingSystem": {
+        "minimumVersion": {
+          "major": 11,
+          "minor": 0,
+          "patch": 0
+        },
+        "name": "macosx"
+      },
+      "vendor": "apple"
+    }
+  },
+  "relationhips": [],
+  "symbols": [
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "keyword",
+          "spelling": "struct"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyStruct"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:@SA@MyStruct"
+      },
+      "kind": {
+        "displayName": "Structure",
+        "identifier": "objective-c.struct"
+      },
+      "location": {
+        "character": 9,
+        "line": 1,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "title": "MyStruct"
+      }
+    },
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:@SA@MyStruct",
+          "spelling": "MyStruct"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyStructStruct"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:input.h@T@MyStructStruct"
+      },
+      "kind": {
+        "displayName": "Type Alias",
+        "identifier": "objective-c.typealias"
+      },
+      "location": {
+        "character": 18,
+        "line": 2,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "MyStructStruct"
+          }
+        ],
+        "title": "MyStructStruct"
+      },
+      "type": "c:@SA@MyStruct"
+    },
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:input.h@T@MyStructStruct",
+          "spelling": "MyStructStruct"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyStructStructStruct"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:input.h@T@MyStructStructStruct"
+      },
+      "kind": {
+        "displayName": "Type Alias",
+        "identifier": "objective-c.typealias"
+      },
+      "location": {
+        "character": 24,
+        "line": 3,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "MyStructStructStruct"
+          }
+        ],
+        "title": "MyStructStructStruct"
+      },
+      "type": "c:input.h@T@MyStructStruct"
+    }
+  ]
+}
Index: clang/test/ExtractAPI/typedef.c
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/typedef.c
@@ -0,0 +1,95 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/reference.output.json.in >> \
+// RUN: %t/reference.output.json
+// RUN: %clang -extract-api --product-name=Typedef -target arm64-apple-macosx \
+// RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+typedef int MyInt;
+
+//--- reference.output.json.in
+{
+  "metadata": {
+    "formatVersion": {
+      "major": 0,
+      "minor": 5,
+      "patch": 3
+    },
+    "generator": "?"
+  },
+  "module": {
+    "name": "Typedef",
+    "platform": {
+      "architecture": "arm64",
+      "operatingSystem": {
+        "minimumVersion": {
+          "major": 11,
+          "minor": 0,
+          "patch": 0
+        },
+        "name": "macosx"
+      },
+      "vendor": "apple"
+    }
+  },
+  "relationhips": [],
+  "symbols": [
+    {
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "typedef"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "MyInt"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:input.h@T@MyInt"
+      },
+      "kind": {
+        "displayName": "Type Alias",
+        "identifier": "objective-c.typealias"
+      },
+      "location": {
+        "character": 13,
+        "line": 1,
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "MyInt"
+          }
+        ],
+        "title": "MyInt"
+      },
+      "type": "c:I"
+    }
+  ]
+}
Index: clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
===================================================================
--- /dev/null
+++ clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
@@ -0,0 +1,45 @@
+//===- ExtractAPI/TypedefUnderlyingTypeResolver.h ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the UnderlyingTypeResolver which is a helper type for
+/// resolving the undelrying type for a given QualType and exposing that
+/// information in various forms.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNDERLYING_TYPE_RESOLVER_H
+#define LLVM_CLANG_UNDERLYING_TYPE_RESOLVER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ExtractAPI/API.h"
+
+#include <string>
+
+namespace clang {
+namespace extractapi {
+
+struct TypedefUnderlyingTypeResolver {
+
+  /// Get a SymbolReference for the given type.
+  SymbolReference getSymbolReferenceForType(QualType Type, APISet &API);
+
+  /// Get a USR for the given type.
+  std::string getUSRForType(QualType Type);
+
+  TypedefUnderlyingTypeResolver(ASTContext &Context) : Context(Context) {}
+
+private:
+  ASTContext &Context;
+};
+
+} // namespace extractapi
+} // namespace clang
+
+#endif // LLVM_CLANG_UNDERLYING_TYPE_RESOLVER_H
Index: clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
===================================================================
--- /dev/null
+++ clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
@@ -0,0 +1,80 @@
+//===- ExtractAPI/TypedefUnderlyingTypeResolver.cpp -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements UnderlyingTypeResolver.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TypedefUnderlyingTypeResolver.h"
+
+#include "clang/Index/USRGeneration.h"
+
+using namespace clang;
+using namespace extractapi;
+
+namespace {
+
+const NamedDecl *getUnderlyingTypeDecl(QualType Type) {
+  const NamedDecl *TypeDecl = nullptr;
+
+  const TypedefType *TypedefTy = Type->getAs<TypedefType>();
+  if (TypedefTy)
+    TypeDecl = TypedefTy->getDecl();
+  if (const TagType *TagTy = Type->getAs<TagType>()) {
+    TypeDecl = TagTy->getDecl();
+  } else if (const ObjCInterfaceType *ObjCITy =
+                 Type->getAs<ObjCInterfaceType>()) {
+    TypeDecl = ObjCITy->getDecl();
+  }
+
+  if (TypeDecl && TypedefTy) {
+    // if this is a typedef to another typedef, use the typedef's decl for the
+    // USR - this will actually be in the output, unlike a typedef to an
+    // anonymous decl
+    const TypedefNameDecl *TypedefDecl = TypedefTy->getDecl();
+    if (TypedefDecl->getUnderlyingType()->isTypedefNameType())
+      TypeDecl = TypedefDecl;
+  }
+
+  return TypeDecl;
+}
+
+} // namespace
+
+SymbolReference
+TypedefUnderlyingTypeResolver::getSymbolReferenceForType(QualType Type,
+                                                         APISet &API) {
+  std::string TypeName = Type.getAsString();
+  SmallString<128> TypeUSR;
+  const NamedDecl *TypeDecl = getUnderlyingTypeDecl(Type);
+  const TypedefType *TypedefTy = Type->getAs<TypedefType>();
+
+  if (TypeDecl) {
+    if (!TypedefTy)
+      TypeName = TypeDecl->getName().str();
+
+    clang::index::generateUSRForDecl(TypeDecl, TypeUSR);
+  } else {
+    clang::index::generateUSRForType(Type, Context, TypeUSR);
+  }
+
+  return {API.copyString(TypeName), API.copyString(TypeUSR)};
+}
+
+std::string TypedefUnderlyingTypeResolver::getUSRForType(QualType Type) {
+  SmallString<128> TypeUSR;
+  const NamedDecl *TypeDecl = getUnderlyingTypeDecl(Type);
+
+  if (TypeDecl)
+    clang::index::generateUSRForDecl(TypeDecl, TypeUSR);
+  else
+    clang::index::generateUSRForType(Type, Context, TypeUSR);
+
+  return std::string(TypeUSR);
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -400,6 +400,11 @@
   case APIRecord::RK_MacroDefinition:
     Kind["identifier"] = AddLangPrefix("macro");
     Kind["displayName"] = "Macro";
+    break;
+  case APIRecord::RK_Typedef:
+    Kind["identifier"] = AddLangPrefix("typealias");
+    Kind["displayName"] = "Type Alias";
+    break;
   }
 
   return Kind;
@@ -588,6 +593,26 @@
   Symbols.emplace_back(std::move(*Macro));
 }
 
+void SymbolGraphSerializer::serializeTypedefRecord(
+    const TypedefRecord &Record) {
+  // Typedefs of anonymous types have their entries unified with the underlying
+  // type.
+  bool ShouldDrop = Record.UnderlyingType.Name.empty();
+  // enums declared with `NS_OPTION` have a named enum and a named typedef, with
+  // the same name
+  ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
+  if (ShouldDrop)
+    return;
+
+  auto Typedef = serializeAPIRecord(Record);
+  if (!Typedef)
+    return;
+
+  (*Typedef)["type"] = Record.UnderlyingType.USR;
+
+  Symbols.emplace_back(std::move(*Typedef));
+}
+
 Object SymbolGraphSerializer::serialize() {
   Object Root;
   serializeObject(Root, "metadata", serializeMetadata());
@@ -616,6 +641,9 @@
   for (const auto &Macro : API.getMacros())
     serializeMacroDefinitionRecord(*Macro.second);
 
+  for (const auto &Typedef : API.getTypedefs())
+    serializeTypedefRecord(*Typedef.second);
+
   Root["symbols"] = std::move(Symbols);
   Root["relationhips"] = std::move(Relationships);
 
Index: clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
===================================================================
--- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -12,6 +12,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "TypedefUnderlyingTypeResolver.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
@@ -41,6 +42,13 @@
 
 namespace {
 
+StringRef getTypedefName(const TagDecl *Decl) {
+  if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
+    return TypedefDecl->getName();
+
+  return {};
+}
+
 /// The RecursiveASTVisitor to traverse symbol declarations and collect API
 /// information.
 class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
@@ -161,6 +169,8 @@
 
     // Collect symbol information.
     StringRef Name = Decl->getName();
+    if (Name.empty())
+      Name = getTypedefName(Decl);
     StringRef USR = API.recordUSR(Decl);
     PresumedLoc Loc =
         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
@@ -196,6 +206,8 @@
 
     // Collect symbol information.
     StringRef Name = Decl->getName();
+    if (Name.empty())
+      Name = getTypedefName(Decl);
     StringRef USR = API.recordUSR(Decl);
     PresumedLoc Loc =
         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
@@ -296,6 +308,36 @@
     return true;
   }
 
+  bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
+    // Skip ObjC Type Parameter for now.
+    if (isa<ObjCTypeParamDecl>(Decl))
+      return true;
+
+    if (!Decl->isDefinedOutsideFunctionOrMethod())
+      return true;
+
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+    StringRef Name = Decl->getName();
+    AvailabilityInfo Availability = getAvailability(Decl);
+    StringRef USR = API.recordUSR(Decl);
+    DocComment Comment;
+    if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    QualType Type = Decl->getUnderlyingType();
+    SymbolReference SymRef =
+        TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
+                                                                         API);
+
+    API.addTypedef(Name, USR, Loc, Availability, Comment,
+                   DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
+                   DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
+
+    return true;
+  }
+
 private:
   /// Get availability information of the declaration \p D.
   AvailabilityInfo getAvailability(const Decl *D) const {
Index: clang/lib/ExtractAPI/DeclarationFragments.cpp
===================================================================
--- clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/ExtractAPI/DeclarationFragments.h"
+#include "TypedefUnderlyingTypeResolver.h"
 #include "clang/Index/USRGeneration.h"
 #include "llvm/ADT/StringSwitch.h"
 
@@ -250,6 +251,31 @@
     return Fragments.append(Base.getAsString(),
                             DeclarationFragments::FragmentKind::Keyword);
 
+  // If the type is a typedefed type, get the underlying TypedefNameDecl for a
+  // direct reference to the typedef instead of the wrapped type.
+  if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
+    const TypedefNameDecl *Decl = TypedefTy->getDecl();
+    std::string USR =
+        TypedefUnderlyingTypeResolver(Context).getUSRForType(QualType(T, 0));
+    return Fragments.append(Decl->getName(),
+                            DeclarationFragments::FragmentKind::TypeIdentifier,
+                            USR);
+  }
+
+  // If the base type is a TagType (struct/interface/union/class/enum), let's
+  // get the underlying Decl for better names and USRs.
+  if (const TagType *TagTy = dyn_cast<TagType>(Base)) {
+    const TagDecl *Decl = TagTy->getDecl();
+    // Anonymous decl, skip this fragment.
+    if (Decl->getName().empty())
+      return Fragments;
+    SmallString<128> TagUSR;
+    clang::index::generateUSRForDecl(Decl, TagUSR);
+    return Fragments.append(Decl->getName(),
+                            DeclarationFragments::FragmentKind::TypeIdentifier,
+                            TagUSR);
+  }
+
   // If the base type is an ObjCInterfaceType, use the underlying
   // ObjCInterfaceDecl for the true USR.
   if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) {
@@ -426,8 +452,8 @@
 
 DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) {
-  // TODO: After we support typedef records, if there's a typedef for this enum
-  // just use the declaration fragments of the typedef decl.
+  if (const auto *TypedefNameDecl = EnumDecl->getTypedefNameForAnonDecl())
+    return getFragmentsForTypedef(TypedefNameDecl);
 
   DeclarationFragments Fragments, After;
   Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword);
@@ -457,8 +483,8 @@
 
 DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
-  // TODO: After we support typedef records, if there's a typedef for this
-  // struct just use the declaration fragments of the typedef decl.
+  if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
+    return getFragmentsForTypedef(TypedefNameDecl);
 
   DeclarationFragments Fragments;
   Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
@@ -680,6 +706,20 @@
   return Fragments;
 }
 
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef(
+    const TypedefNameDecl *Decl) {
+  DeclarationFragments Fragments, After;
+  Fragments.append("typedef", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
+      .append(getFragmentsForType(Decl->getUnderlyingType(),
+                                  Decl->getASTContext(), After))
+      .append(std::move(After))
+      .appendSpace()
+      .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+  return Fragments;
+}
+
 template <typename FunctionT>
 FunctionSignature
 DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
Index: clang/lib/ExtractAPI/CMakeLists.txt
===================================================================
--- clang/lib/ExtractAPI/CMakeLists.txt
+++ clang/lib/ExtractAPI/CMakeLists.txt
@@ -8,6 +8,7 @@
   DeclarationFragments.cpp
   Serialization/SerializerBase.cpp
   Serialization/SymbolGraphSerializer.cpp
+  TypedefUnderlyingTypeResolver.cpp
 
   LINK_LIBS
   clangAST
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -170,6 +170,17 @@
   return addTopLevelRecord(Macros, Name, USR, Loc, Declaration, SubHeading);
 }
 
+TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
+                                  PresumedLoc Loc,
+                                  const AvailabilityInfo &Availability,
+                                  const DocComment &Comment,
+                                  DeclarationFragments Declaration,
+                                  DeclarationFragments SubHeading,
+                                  SymbolReference UnderlyingType) {
+  return addTopLevelRecord(Typedefs, Name, USR, Loc, Availability, Comment,
+                           Declaration, SubHeading, UnderlyingType);
+}
+
 StringRef APISet::recordUSR(const Decl *D) {
   SmallString<128> USR;
   index::generateUSRForDecl(D, USR);
@@ -211,3 +222,4 @@
 void ObjCInterfaceRecord::anchor() {}
 void ObjCProtocolRecord::anchor() {}
 void MacroDefinitionRecord::anchor() {}
+void TypedefRecord::anchor() {}
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -126,6 +126,8 @@
   /// Serialize a macro defintion record.
   void serializeMacroDefinitionRecord(const MacroDefinitionRecord &Record);
 
+  void serializeTypedefRecord(const TypedefRecord &Record);
+
 public:
   SymbolGraphSerializer(const APISet &API, StringRef ProductName,
                         APISerializerOption Options = {})
Index: clang/include/clang/ExtractAPI/DeclarationFragments.h
===================================================================
--- clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -230,6 +230,10 @@
   static DeclarationFragments getFragmentsForMacro(StringRef Name,
                                                    const MacroDirective *MD);
 
+  /// Build DeclarationFragments for a typedef \p TypedefNameDecl.
+  static DeclarationFragments
+  getFragmentsForTypedef(const TypedefNameDecl *Decl);
+
   /// Build sub-heading fragments for a NamedDecl.
   static DeclarationFragments getSubHeading(const NamedDecl *);
 
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -88,6 +88,7 @@
     RK_ObjCInterface,
     RK_ObjCProtocol,
     RK_MacroDefinition,
+    RK_Typedef,
   };
 
 private:
@@ -395,6 +396,30 @@
   virtual void anchor();
 };
 
+/// This holds information associated with typedefs.
+///
+/// Note: Typedefs for anonymous enums and structs typically don't get emitted
+/// by the serializers but still get a TypedefRecord. Instead we use the
+/// typedef name as a name for the underlying anonymous struct or enum.
+struct TypedefRecord : APIRecord {
+  SymbolReference UnderlyingType;
+
+  TypedefRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
+                const AvailabilityInfo &Availability, const DocComment &Comment,
+                DeclarationFragments Declaration,
+                DeclarationFragments SubHeading, SymbolReference UnderlyingType)
+      : APIRecord(RK_Typedef, Name, USR, Loc, Availability, LinkageInfo(),
+                  Comment, Declaration, SubHeading),
+        UnderlyingType(UnderlyingType) {}
+
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_Typedef;
+  }
+
+private:
+  virtual void anchor();
+};
+
 /// APISet holds the set of API records collected from given inputs.
 class APISet {
 public:
@@ -563,6 +588,19 @@
                                             DeclarationFragments Declaration,
                                             DeclarationFragments SubHeading);
 
+  /// Create a typedef record into the API set.
+  ///
+  /// Note: the caller is responsible for keeping the StringRef \p Name and
+  /// \p USR alive. APISet::copyString provides a way to copy strings into
+  /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
+  /// to generate the USR for \c D and keep it alive in APISet.
+  TypedefRecord *addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc,
+                            const AvailabilityInfo &Availability,
+                            const DocComment &Comment,
+                            DeclarationFragments Declaration,
+                            DeclarationFragments SubHeading,
+                            SymbolReference UnderlyingType);
+
   /// A mapping type to store a set of APIRecord%s with the declaration name as
   /// the key.
   template <typename RecordTy,
@@ -586,6 +624,7 @@
     return ObjCProtocols;
   }
   const RecordMap<MacroDefinitionRecord> &getMacros() const { return Macros; }
+  const RecordMap<TypedefRecord> &getTypedefs() const { return Typedefs; }
 
   /// Generate and store the USR of declaration \p D.
   ///
@@ -625,6 +664,7 @@
   RecordMap<ObjCInterfaceRecord> ObjCInterfaces;
   RecordMap<ObjCProtocolRecord> ObjCProtocols;
   RecordMap<MacroDefinitionRecord> Macros;
+  RecordMap<TypedefRecord> Typedefs;
 };
 
 } // namespace extractapi
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to