r298392 - [index/AST] Determine if a typedef shares a name and spelling location with its underlying tag type

Argyrios Kyrtzidis via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 21 09:56:03 PDT 2017


Author: akirtzidis
Date: Tue Mar 21 11:56:02 2017
New Revision: 298392

URL: http://llvm.org/viewvc/llvm-project?rev=298392&view=rev
Log:
[index/AST] Determine if a typedef shares a name and spelling location with its underlying tag type

In such a case, as when using the NS_ENUM macro, for indexing purposes treat the typedef as 'transparent',
meaning we treat its references as symbols of the underlying tag symbol.
Also provide a libclang API to check for such typedefs.

Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Index/IndexDecl.cpp
    cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp
    cfe/trunk/test/Index/Core/index-source.m
    cfe/trunk/test/Index/get-cursor.m
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/CXType.cpp
    cfe/trunk/tools/libclang/libclang.exports

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Tue Mar 21 11:56:02 2017
@@ -3437,6 +3437,16 @@ CINDEX_LINKAGE long long clang_getArrayS
 CINDEX_LINKAGE CXType clang_Type_getNamedType(CXType T);
 
 /**
+ * \brief Determine if a typedef is 'transparent' tag.
+ *
+ * A typedef is considered 'transparent' if it shares a name and spelling
+ * location with its underlying tag type, as is the case with the NS_ENUM macro.
+ *
+ * \returns non-zero if transparent and zero otherwise.
+ */
+CINDEX_LINKAGE unsigned clang_Type_isTransparentTagTypedef(CXType T);
+
+/**
  * \brief List the possible error codes for \c clang_Type_getSizeOf,
  *   \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and
  *   \c clang_Cursor_getOffsetOf.

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Mar 21 11:56:02 2017
@@ -2641,12 +2641,17 @@ class TypedefNameDecl : public TypeDecl,
   typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
   llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
 
+  // FIXME: This can be packed into the bitfields in Decl.
+  /// If 0, we have not computed IsTransparentTag.
+  /// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1).
+  mutable unsigned CacheIsTransparentTag : 2;
+
 protected:
   TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC,
                   SourceLocation StartLoc, SourceLocation IdLoc,
                   IdentifierInfo *Id, TypeSourceInfo *TInfo)
       : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C),
-        MaybeModedTInfo(TInfo) {}
+        MaybeModedTInfo(TInfo), CacheIsTransparentTag(0) {}
 
   typedef Redeclarable<TypedefNameDecl> redeclarable_base;
   TypedefNameDecl *getNextRedeclarationImpl() override {
@@ -2699,11 +2704,22 @@ public:
   /// this typedef declaration.
   TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const;
 
+  /// Determines if this typedef shares a name and spelling location with its
+  /// underlying tag type, as is the case with the NS_ENUM macro.
+  bool isTransparentTag() const {
+    if (CacheIsTransparentTag)
+      return CacheIsTransparentTag & 0x2;
+    return isTransparentTagSlow();
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) {
     return K >= firstTypedefName && K <= lastTypedefName;
   }
+
+private:
+  bool isTransparentTagSlow() const;
 };
 
 /// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef'

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Tue Mar 21 11:56:02 2017
@@ -4242,6 +4242,30 @@ TagDecl *TypedefNameDecl::getAnonDeclWit
   return nullptr;
 }
 
+bool TypedefNameDecl::isTransparentTagSlow() const {
+  auto determineIsTransparent = [&]() {
+    if (auto *TT = getUnderlyingType()->getAs<TagType>()) {
+      if (auto *TD = TT->getDecl()) {
+        if (TD->getName() != getName())
+          return false;
+        SourceLocation TTLoc = getLocation();
+        SourceLocation TDLoc = TD->getLocation();
+        if (!TTLoc.isMacroID() || !TDLoc.isMacroID())
+          return false;
+        SourceManager &SM = getASTContext().getSourceManager();
+        return SM.getSpellingLoc(TTLoc) == SM.getSpellingLoc(TDLoc);
+      }
+    }
+    return false;
+  };
+
+  bool isTransparent = determineIsTransparent();
+  CacheIsTransparentTag = 1;
+  if (isTransparent)
+    CacheIsTransparentTag |= 0x2;
+  return isTransparent;
+}
+
 TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(),
                                  nullptr, nullptr);

Modified: cfe/trunk/lib/Index/IndexDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexDecl.cpp?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexDecl.cpp (original)
+++ cfe/trunk/lib/Index/IndexDecl.cpp Tue Mar 21 11:56:02 2017
@@ -231,8 +231,9 @@ public:
   }
 
   bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
-    if (!IndexCtx.handleDecl(D))
-      return false;
+    if (!D->isTransparentTag())
+      if (!IndexCtx.handleDecl(D))
+        return false;
     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
     return true;
   }

Modified: cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp (original)
+++ cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp Tue Mar 21 11:56:02 2017
@@ -47,9 +47,15 @@ public:
   } while (0)
 
   bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+    SourceLocation Loc = TL.getNameLoc();
+    TypedefNameDecl *ND = TL.getTypedefNameDecl();
+    if (ND->isTransparentTag()) {
+      TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl();
+      return IndexCtx.handleReference(Underlying, Loc, Parent,
+                                      ParentDC, SymbolRoleSet(), Relations);
+    }
     if (IsBase) {
-      SourceLocation Loc = TL.getNameLoc();
-      TRY_TO(IndexCtx.handleReference(TL.getTypedefNameDecl(), Loc,
+      TRY_TO(IndexCtx.handleReference(ND, Loc,
                                       Parent, ParentDC, SymbolRoleSet()));
       if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
         TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
@@ -57,7 +63,7 @@ public:
                                         Relations));
       }
     } else {
-      TRY_TO(IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(),
+      TRY_TO(IndexCtx.handleReference(ND, Loc,
                                       Parent, ParentDC, SymbolRoleSet(),
                                       Relations));
     }

Modified: cfe/trunk/test/Index/Core/index-source.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/Core/index-source.m?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/test/Index/Core/index-source.m (original)
+++ cfe/trunk/test/Index/Core/index-source.m Tue Mar 21 11:56:02 2017
@@ -348,3 +348,39 @@ typedef MyGenCls<Base *><MyEnumerating>
 // CHECK: [[@LINE-1]]:3 | field/ObjC | _foo | c:objc(cs)I7 at _foo | <no-cgname> | Ref,Writ,RelCont | rel: 1
 }
 @end
+
+#define NS_ENUM(_name, _type) enum _name:_type _name; enum _name : _type
+
+typedef NS_ENUM(AnotherEnum, int) {
+// CHECK-NOT: [[@LINE-1]]:17 | type-alias/C | AnotherEnum |
+// CHECK: [[@LINE-2]]:17 | enum/C | AnotherEnum | [[AnotherEnum_USR:.*]] | {{.*}} | Ref,RelCont | rel: 1
+  AnotherEnumFirst = 0,
+  AnotherEnumSecond = 1,
+  AnotherEnumThird = 2,
+};
+
+AnotherEnum anotherT;
+// CHECK: [[@LINE-1]]:1 | enum/C | AnotherEnum | [[AnotherEnum_USR]] | {{.*}} | Ref,RelCont | rel: 1
+enum AnotherEnum anotherE;
+// CHECK: [[@LINE-1]]:6 | enum/C | AnotherEnum | [[AnotherEnum_USR]] | {{.*}} | Ref,RelCont | rel: 1
+
+#define TRANSPARENT(_name) struct _name _name; struct _name
+#define OPAQUE(_name) struct _name *_name; struct _name
+
+typedef TRANSPARENT(AStruct) {
+  int x;
+};
+
+AStruct aStructT;
+// CHECK: [[@LINE-1]]:1 | struct/C | AStruct | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
+struct AStruct aStructS;
+// CHECK: [[@LINE-1]]:8 | struct/C | AStruct | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
+
+typedef OPAQUE(Separate) {
+  int x;
+};
+
+Separate separateT;
+// CHECK: [[@LINE-1]]:1 | type-alias/C | Separate | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
+struct Separate separateE;
+// CHECK: [[@LINE-1]]:8 | struct/C | Separate | {{.*}} | {{.*}} | Ref,RelCont | rel: 1

Modified: cfe/trunk/test/Index/get-cursor.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/get-cursor.m?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/test/Index/get-cursor.m (original)
+++ cfe/trunk/test/Index/get-cursor.m Tue Mar 21 11:56:02 2017
@@ -129,6 +129,31 @@ void foo3(Test3 *test3) {
 }
 @end
 
+#define NS_ENUM(_name, _type) enum _name : _type _name; enum _name : _type
+typedef NS_ENUM(TestTransparent, int) {
+  TestTransparentFirst = 0,
+  TestTransparentSecond = 1,
+};
+typedef enum TestTransparent NotTransparent;
+
+TestTransparent transparentTypedef;
+enum TestTransparent transparentUnderlying;
+NotTransparent opaqueTypedef;
+
+#define MY_ENUM(_name, _type) enum _name : _type _name##_t; enum _name : _type
+typedef MY_ENUM(TokenPaste, int) {
+  TokenPasteFirst = 0,
+};
+TokenPaste_t opaqueTypedef2;
+
+#define MY_TYPE(_name) struct _name _name; struct _name
+typedef MY_TYPE(SomeT) { int x; };
+SomeT someVar;
+
+#define MY_TYPE2(_name) struct _name *_name; struct _name
+typedef MY_TYPE2(SomeT2) { int x; };
+SomeT2 someVar2;
+
 
 // RUN: c-index-test -cursor-at=%s:4:28 -cursor-at=%s:5:28 %s | FileCheck -check-prefix=CHECK-PROP %s
 // CHECK-PROP: ObjCPropertyDecl=foo1:4:26
@@ -193,3 +218,11 @@ void foo3(Test3 *test3) {
 // RUN: c-index-test -cursor-at=%s:127:8 %s | FileCheck -check-prefix=CHECK-RECEIVER-WITH-NULLABILITY %s
 // RUN: c-index-test -cursor-at=%s:128:8 %s | FileCheck -check-prefix=CHECK-RECEIVER-WITH-NULLABILITY %s
 // CHECK-RECEIVER-WITH-NULLABILITY: Receiver-type=ObjCId
+
+// RUN: c-index-test -cursor-at=%s:139:1 -cursor-at=%s:140:6 -cursor-at=%s:141:1 -cursor-at=%s:147:1 -cursor-at=%s:151:1 -cursor-at=%s:155:1 %s | FileCheck -check-prefix=CHECK-TRANSPARENT %s
+// CHECK-TRANSPARENT: 139:1 TypeRef=TestTransparent:133:17 (Transparent: enum TestTransparent) Extent=[139:1 - 139:16] Spelling=TestTransparent ([139:1 - 139:16])
+// CHECK-TRANSPARENT: 140:6 TypeRef=enum TestTransparent:133:17 Extent=[140:6 - 140:21] Spelling=enum TestTransparent ([140:6 - 140:21])
+// CHECK-TRANSPARENT: 141:1 TypeRef=NotTransparent:137:30 Extent=[141:1 - 141:15] Spelling=NotTransparent ([141:1 - 141:15])
+// CHECK-TRANSPARENT: 147:1 TypeRef=TokenPaste_t:144:9 Extent=[147:1 - 147:13] Spelling=TokenPaste_t ([147:1 - 147:13])
+// CHECK-TRANSPARENT: 151:1 TypeRef=SomeT:150:17 (Transparent: struct SomeT) Extent=[151:1 - 151:6] Spelling=SomeT ([151:1 - 151:6])
+// CHECK-TRANSPARENT: 155:1 TypeRef=SomeT2:154:18 Extent=[155:1 - 155:7] Spelling=SomeT2 ([155:1 - 155:7])

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Tue Mar 21 11:56:02 2017
@@ -710,6 +710,15 @@ static void PrintCursor(CXCursor Cursor,
         clang_getSpellingLocation(Loc, 0, &line, &column, 0);
         printf(":%d:%d", line, column);
       }
+
+      if (clang_getCursorKind(Referenced) == CXCursor_TypedefDecl) {
+        CXType T = clang_getCursorType(Referenced);
+        if (clang_Type_isTransparentTagTypedef(T)) {
+          CXType Underlying = clang_getTypedefDeclUnderlyingType(Referenced);
+          CXString S = clang_getTypeSpelling(Underlying);
+          printf(" (Transparent: %s)", clang_getCString(S));
+        }
+      }
     }
 
     if (clang_isCursorDefinition(Cursor))

Modified: cfe/trunk/tools/libclang/CXType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXType.cpp (original)
+++ cfe/trunk/tools/libclang/CXType.cpp Tue Mar 21 11:56:02 2017
@@ -1039,3 +1039,12 @@ CXType clang_Type_getNamedType(CXType CT
 
   return MakeCXType(QualType(), GetTU(CT));
 }
+
+unsigned clang_Type_isTransparentTagTypedef(CXType TT){
+  QualType T = GetQualType(TT);
+  if (auto *TT = dyn_cast_or_null<TypedefType>(T.getTypePtrOrNull())) {
+    if (auto *D = TT->getDecl())
+      return D->isTransparentTag();
+  }
+  return false;
+}

Modified: cfe/trunk/tools/libclang/libclang.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=298392&r1=298391&r2=298392&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.exports (original)
+++ cfe/trunk/tools/libclang/libclang.exports Tue Mar 21 11:56:02 2017
@@ -88,6 +88,7 @@ clang_Type_getTemplateArgumentAsType
 clang_Type_getCXXRefQualifier
 clang_Type_visitFields
 clang_Type_getNamedType
+clang_Type_isTransparentTagTypedef
 clang_VerbatimBlockLineComment_getText
 clang_VerbatimLineComment_getText
 clang_HTMLTagComment_getAsString




More information about the cfe-commits mailing list