[PATCH] D50318: Support Swift in platform availability attribute

2018-11-11 Thread Michael Wu via Phabricator via cfe-commits
michaelwu updated this revision to Diff 173607.
michaelwu added a comment.

Thanks for the review! All requested changes have been made, and I also had to 
fix a test due to https://reviews.llvm.org/D50214


https://reviews.llvm.org/D50318

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/Features.def
  lib/Parse/ParseDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/Index/availability.c
  test/Sema/attr-availability-swift.c

Index: test/Sema/attr-availability-swift.c
===
--- test/Sema/attr-availability-swift.c
+++ test/Sema/attr-availability-swift.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -ast-dump %s | FileCheck %s
+//
+
+#if !__has_feature(attribute_availability_with_message)
+# error "Missing __has_feature"
+#endif
+
+#if __has_feature(attribute_availability_swift)
+# warning "okay"
+// expected-warning@-1{{okay}}
+#else
+# error "Missing __has_feature"
+#endif
+
+extern int noSwiftGlobal1 __attribute__((availability(swift, unavailable)));
+// CHECK: AvailabilityAttr {{.*}}swift 0 0 0 Unavailable "" ""
+extern int noSwiftGlobal1 __attribute__((availability(macosx, introduced=10.1))); // okay
+// CHECK: AvailabilityAttr {{.*}}Inherited swift 0 0 0 Unavailable "" ""
+// CHECK: AvailabilityAttr {{.*}}macos 10.1 0 0 "" ""
+extern int noSwiftGlobal1 __attribute__((availability(swift, unavailable, message="and this one has a message"))); // okay
+// CHECK: AvailabilityAttr {{.*}}Inherited macos 10.1 0 0 "" ""
+// CHECK: AvailabilityAttr {{.*}}swift 0 0 0 Unavailable "and this one has a message" ""
+extern int noSwiftGlobal2 __attribute__((availability(swift, introduced=5))); // expected-warning{{only 'unavailable' and 'deprecated' are supported for Swift availability}}
+// CHECK: VarDecl
+// CHECK-NOT: AvailabilityAttr
+extern int noSwiftGlobal3 __attribute__((availability(swift, deprecated, message="t")));
+// CHECK: VarDecl
+// CHECK: AvailabilityAttr {{.*}}swift 0 1 0 "t" ""
Index: test/Index/availability.c
===
--- test/Index/availability.c
+++ test/Index/availability.c
@@ -14,9 +14,14 @@
 
 void bar2(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0))) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0)));
 
+void foo2(void) __attribute__((availability(swift,unavailable)));
+void foo3(void) __attribute__((availability(swift,deprecated)));
+
 // RUN: c-index-test -test-load-source all %s | FileCheck %s
 // CHECK: FunctionDecl=foo:3:6{{.*}}(ios, introduced=3.2, deprecated=4.1) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
 // CHECK: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
 // CHECK: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
 // CHECK: FunctionDecl=bar:13:6{{.*}}(ios, introduced=3.2) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.6, message="use foobar")
 // CHECK: FunctionDecl=bar2:15:6{{.*}}(ios, introduced=3.2, deprecated=10.0) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+// CHECK: FunctionDecl=foo2:17:6{{.*}}(swift, unavailable)
+// CHECK: FunctionDecl=foo3:18:6{{.*}}(swift, deprecated=1)
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2410,6 +2410,15 @@
   if (const auto *SE = dyn_cast_or_null(AL.getReplacementExpr()))
 Replacement = SE->getString();
 
+  if (II->isStr("swift")) {
+if (Introduced.isValid() || Obsoleted.isValid() ||
+(!IsUnavailable && !Deprecated.isValid())) {
+  S.Diag(AL.getLoc(),
+ diag::warn_availability_swift_unavailable_deprecated_only);
+  return;
+}
+  }
+
   AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II,
   false/*Implicit*/,
   Introduced.Version,
Index: lib/Parse/ParseDecl.cpp
===
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -1001,6 +1001,21 @@
   continue;
 }
 
+if (Keyword == Ident_deprecated && Platform->Ident &&
+Platform->Ident->isStr("swift")) {
+  // For swift, we deprecate for all versions.
+  if (Changes[Deprecated].KeywordLoc.isValid()) {
+Diag(KeywordLoc, diag::err_availability_redundant)
+  << Keyword
+  << SourceRange(Changes[Deprecated].KeywordLoc);
+  }
+
+  Changes[Deprecated].KeywordLoc = KeywordLoc;
+  // Use a fake version here.
+ 

[PATCH] D51281: [libclang] Return the proper pointee type for 'auto' deduced to pointer

2018-09-06 Thread Michael Wu via Phabricator via cfe-commits
michaelwu accepted this revision.
michaelwu added a comment.
This revision is now accepted and ready to land.

LGTM


https://reviews.llvm.org/D51281



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51281: [libclang] Return the proper pointee type for 'auto' deduced to pointer

2018-08-28 Thread Michael Wu via Phabricator via cfe-commits
michaelwu added a comment.

It shouldn't be too hard to make a test using `c-index-test`. 
`-test-print-type` will print out the pointee type if it's valid.




Comment at: tools/libclang/CXType.cpp:448
   break;
+case Type::Auto:
+  TP = cast(TP)->getDeducedType().getTypePtrOrNull();

Seems like this might make sense for `Type::DeducedTemplateSpecialization` too.


https://reviews.llvm.org/D51281



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50318: Support Swift in platform availability attribute

2018-08-23 Thread Michael Wu via Phabricator via cfe-commits
michaelwu added a comment.

Review ping


Repository:
  rC Clang

https://reviews.llvm.org/D50318



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50318: Support Swift in platform availability attribute

2018-08-05 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.
michaelwu added reviewers: manmanren, friss, doug.gregor.

This adds support for Swift platform availability attributes. It's largely a 
port of the changes made to https://github.com/apple/swift-clang/ for Swift 
availability attributes. Specifically, 
https://github.com/apple/swift-clang/commit/84b5a21c31cb5b0d7d958a478bc01964939b6952
 and 
https://github.com/apple/swift-clang/commit/e5b87f265aede41c8381094bbf54e2715c8293b0
 . The implementation of attribute_availability_swift is a little different and 
additional tests in test/Index/availability.c were added.


Repository:
  rC Clang

https://reviews.llvm.org/D50318

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/Features.def
  lib/Parse/ParseDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/Index/availability.c
  test/Sema/attr-availability-swift.c

Index: test/Sema/attr-availability-swift.c
===
--- /dev/null
+++ test/Sema/attr-availability-swift.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -ast-dump %s | FileCheck %s
+//
+
+#if !__has_feature(attribute_availability_with_message)
+# error "Missing __has_feature"
+#endif
+
+#if __has_feature(attribute_availability_swift)
+# warning "okay"
+// expected-warning@-1{{okay}}
+#else
+# error "Missing __has_feature"
+#endif
+
+extern int noSwiftGlobal1 __attribute__((availability(swift, unavailable)));
+// CHECK: AvailabilityAttr {{.*}}swift 0 0 0 Unavailable "" ""
+extern int noSwiftGlobal1 __attribute__((availability(macosx, introduced=10.1))); // okay
+// CHECK: AvailabilityAttr {{.*}}macos 10.1 0 0 "" ""
+// CHECK: AvailabilityAttr {{.*}}Inherited swift 0 0 0 Unavailable "" ""
+extern int noSwiftGlobal1 __attribute__((availability(swift, unavailable, message="and this one has a message"))); // okay
+// CHECK: AvailabilityAttr {{.*}}swift 0 0 0 Unavailable "and this one has a message" ""
+// CHECK: AvailabilityAttr {{.*}}Inherited macos 10.1 0 0 "" ""
+extern int noSwiftGlobal2 __attribute__((availability(swift, introduced=5))); // expected-warning{{only 'unavailable' and 'deprecated' are supported for Swift availability}}
+// CHECK: VarDecl
+// CHECK-NOT: AvailabilityAttr
+extern int noSwiftGlobal3 __attribute__((availability(swift, deprecated, message="t")));
+// CHECK: VarDecl
+// CHECK: AvailabilityAttr {{.*}}swift 0 1 0 "t" ""
Index: test/Index/availability.c
===
--- test/Index/availability.c
+++ test/Index/availability.c
@@ -14,9 +14,14 @@
 
 void bar2(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0))) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0)));
 
+void foo2(void) __attribute__((availability(swift,unavailable)));
+void foo3(void) __attribute__((availability(swift,deprecated)));
+
 // RUN: c-index-test -test-load-source all %s | FileCheck %s
 // CHECK: FunctionDecl=foo:3:6{{.*}}(ios, introduced=3.2, deprecated=4.1) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
 // CHECK: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
 // CHECK: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
 // CHECK: FunctionDecl=bar:13:6{{.*}}(ios, introduced=3.2) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.6, message="use foobar")
 // CHECK: FunctionDecl=bar2:15:6{{.*}}(ios, introduced=3.2, deprecated=10.0) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+// CHECK: FunctionDecl=foo2:17:6{{.*}}(swift, unavailable)
+// CHECK: FunctionDecl=foo3:18:6{{.*}}(swift, deprecated=1)
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2365,6 +2365,15 @@
   if (const auto *SE = dyn_cast_or_null(AL.getReplacementExpr()))
 Replacement = SE->getString();
 
+  if (II->getName() == "swift") {
+if (Introduced.isValid() || Obsoleted.isValid() ||
+(!IsUnavailable && !Deprecated.isValid())) {
+  S.Diag(AL.getLoc(),
+ diag::warn_availability_swift_unavailable_deprecated_only);
+  return;
+}
+  }
+
   AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II,
   false/*Implicit*/,
   Introduced.Version,
Index: lib/Parse/ParseDecl.cpp
===
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -1001,6 +1001,21 @@
   continue;
 }
 
+if (Keyword == Ident_deprecated && Platform->Ident

[PATCH] D49635: [libclang 8/8] Add support for the flag_enum attribute

2018-08-02 Thread Michael Wu via Phabricator via cfe-commits
michaelwu added a comment.

Thanks for the reviews!


Repository:
  rC Clang

https://reviews.llvm.org/D49635



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49634: [libclang 7/8] Add support for getting property setter and getter names

2018-08-02 Thread Michael Wu via Phabricator via cfe-commits
michaelwu added a comment.

The patch will be adjusted slightly to replace a // comment with a /* */ 
comment.


Repository:
  rC Clang

https://reviews.llvm.org/D49634



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49127: [libclang 5/8] Add support for ObjC attributes without args

2018-08-02 Thread Michael Wu via Phabricator via cfe-commits
michaelwu added a comment.

Some of the CHECKs in the test will be reordered to pass, but it's still the 
same test.


Repository:
  rC Clang

https://reviews.llvm.org/D49127



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49063: [libclang 1/8] Add support for ObjCObjectType

2018-07-21 Thread Michael Wu via Phabricator via cfe-commits
michaelwu updated this revision to Diff 156692.
michaelwu added a comment.

`clang_Type_getNumObjCTypeArgs` and `clang_Type_getNumObjCProtocolRefs` now 
return unsigned.

I've bumped `CINDEX_VERSION_MINOR` in https://reviews.llvm.org/D49635 , which 
is the last in this patch series.


https://reviews.llvm.org/D49063

Files:
  include/clang-c/Index.h
  test/Index/objc-typeargs-protocols.m
  test/Index/print-type.m
  tools/c-index-test/c-index-test.c
  tools/libclang/CXType.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -98,6 +98,11 @@
 clang_Type_visitFields
 clang_Type_getNamedType
 clang_Type_isTransparentTagTypedef
+clang_Type_getObjCObjectBaseType
+clang_Type_getNumObjCProtocolRefs
+clang_Type_getObjCProtocolDecl
+clang_Type_getNumObjCTypeArgs
+clang_Type_getObjCTypeArg
 clang_VerbatimBlockLineComment_getText
 clang_VerbatimLineComment_getText
 clang_HTMLTagComment_getAsString
Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -98,6 +98,7 @@
 TKCASE(Enum);
 TKCASE(Typedef);
 TKCASE(ObjCInterface);
+TKCASE(ObjCObject);
 TKCASE(ObjCObjectPointer);
 TKCASE(FunctionNoProto);
 TKCASE(FunctionProto);
@@ -575,6 +576,7 @@
 TKIND(Enum);
 TKIND(Typedef);
 TKIND(ObjCInterface);
+TKIND(ObjCObject);
 TKIND(ObjCObjectPointer);
 TKIND(FunctionNoProto);
 TKIND(FunctionProto);
@@ -1098,6 +1100,74 @@
   return MakeCXType(QT.getValueOr(QualType()), GetTU(CT));
 }
 
+CXType clang_Type_getObjCObjectBaseType(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return MakeCXType(QualType(), GetTU(CT));
+
+  return MakeCXType(OT->getBaseType(), GetTU(CT));
+}
+
+unsigned clang_Type_getNumObjCProtocolRefs(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return 0;
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return 0;
+
+  return OT->getNumProtocols();
+}
+
+CXCursor clang_Type_getObjCProtocolDecl(CXType CT, unsigned i) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const ObjCProtocolDecl *PD = OT->getProtocol(i);
+  if (!PD)
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  return cxcursor::MakeCXCursor(PD, GetTU(CT));
+}
+
+unsigned clang_Type_getNumObjCTypeArgs(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return 0;
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return 0;
+
+  return OT->getTypeArgs().size();
+}
+
+CXType clang_Type_getObjCTypeArg(CXType CT, unsigned i) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ArrayRef TA = OT->getTypeArgs();
+  if ((size_t)i >= TA.size())
+return MakeCXType(QualType(), GetTU(CT));
+
+  return MakeCXType(TA[i], GetTU(CT));
+}
+
 unsigned clang_Type_visitFields(CXType PT,
 CXFieldVisitor visitor,
 CXClientData client_data){
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -1500,6 +1500,7 @@
  CXClientData d) {
   if (!clang_isInvalid(clang_getCursorKind(cursor))) {
 CXType T = clang_getCursorType(cursor);
+CXType PT = clang_getPointeeType(T);
 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
 PrintCursor(cursor, NULL);
 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
@@ -1545,11 +1546,45 @@
 printf("]");
   }
 }
+/* Print ObjC base types, type arguments, and protocol list if available. */
+{
+  CXType BT = clang_Type_getObjCObjectBaseType(PT);
+  if (BT.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]");
+  }
+}
+{
+  unsigned NumTypeArgs = clang_Type_getNumObjCTypeArgs(PT);
+  if (NumTypeArgs > 0) {
+unsigned i;
+printf(" [typeargs=");
+for (i = 0; i < NumTypeArgs; ++i) {
+  CXType TA = clang_Type_getObjCTypeArg(PT, i);
+  if (TA.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(TA, " [%s] [%s]");
+  }
+}
+printf("]");
+  }
+}
+{
+  unsigned NumProtocols = clang_Type_getNumObjCProtocolRefs(PT);
+  if (NumProtoco

[PATCH] D49634: [libclang 7/8] Add support for getting property setter and getter names

2018-07-21 Thread Michael Wu via Phabricator via cfe-commits
michaelwu updated this revision to Diff 156691.
michaelwu added a comment.

Fix test


https://reviews.llvm.org/D49634

Files:
  include/clang-c/Index.h
  test/Index/property-getter-setter.m
  tools/c-index-test/c-index-test.c
  tools/libclang/CIndex.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -31,6 +31,8 @@
 clang_Cursor_getNumArguments
 clang_Cursor_getObjCDeclQualifiers
 clang_Cursor_getObjCPropertyAttributes
+clang_Cursor_getObjCPropertyGetterName
+clang_Cursor_getObjCPropertySetterName
 clang_Cursor_getObjCSelectorIndex
 clang_Cursor_getOffsetOfField
 clang_Cursor_getSpellingNameRange
Index: tools/libclang/CIndex.cpp
===
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -7913,6 +7913,30 @@
   return Result;
 }
 
+CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C) {
+  if (C.kind != CXCursor_ObjCPropertyDecl)
+return cxstring::createNull();
+
+  const ObjCPropertyDecl *PD = dyn_cast(getCursorDecl(C));
+  Selector sel = PD->getGetterName();
+  if (sel.isNull())
+return cxstring::createNull();
+
+  return cxstring::createDup(sel.getAsString());
+}
+
+CXString clang_Cursor_getObjCPropertySetterName(CXCursor C) {
+  if (C.kind != CXCursor_ObjCPropertyDecl)
+return cxstring::createNull();
+
+  const ObjCPropertyDecl *PD = dyn_cast(getCursorDecl(C));
+  Selector sel = PD->getSetterName();
+  if (sel.isNull())
+return cxstring::createNull();
+
+  return cxstring::createDup(sel.getAsString());
+}
+
 unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C) {
   if (!clang_isDeclaration(C.kind))
 return CXObjCDeclQualifier_None;
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -1103,6 +1103,34 @@
   }
 }
 
+if (Cursor.kind == CXCursor_ObjCPropertyDecl) {
+  CXString Name = clang_Cursor_getObjCPropertyGetterName(Cursor);
+  CXString Spelling = clang_getCursorSpelling(Cursor);
+  const char *CName = clang_getCString(Name);
+  const char *CSpelling = clang_getCString(Spelling);
+  if (CName && strcmp(CName, CSpelling)) {
+printf(" (getter=%s)", CName);
+  }
+  clang_disposeString(Spelling);
+  clang_disposeString(Name);
+}
+
+if (Cursor.kind == CXCursor_ObjCPropertyDecl) {
+  CXString Name = clang_Cursor_getObjCPropertySetterName(Cursor);
+  CXString Spelling = clang_getCursorSpelling(Cursor);
+  const char *CName = clang_getCString(Name);
+  const char *CSpelling = clang_getCString(Spelling);
+  char *DefaultSetter = malloc(strlen(CSpelling) + 5);
+  sprintf(DefaultSetter, "set%s:", CSpelling);
+  DefaultSetter[3] &= ~(1 << 5); // Make uppercase
+  if (CName && strcmp(CName, DefaultSetter)) {
+printf(" (setter=%s)", CName);
+  }
+  free(DefaultSetter);
+  clang_disposeString(Spelling);
+  clang_disposeString(Name);
+}
+
 {
   unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
   if (QT != CXObjCDeclQualifier_None) {
Index: test/Index/property-getter-setter.m
===
--- /dev/null
+++ test/Index/property-getter-setter.m
@@ -0,0 +1,10 @@
+@interface Foo
+@property (assign,readwrite,getter=b,setter=c:) id a;
+@property (assign,readonly,getter=e) id d;
+@property (assign,readwrite) id f;
+@end
+
+// RUN: c-index-test -test-print-type-declaration %s | FileCheck %s
+// CHECK: ObjCPropertyDecl=a:2:52 [getter,assign,readwrite,setter,] (getter=b) (setter=c:) [typedeclaration=id] [typekind=ObjCId]
+// CHECK: ObjCPropertyDecl=d:3:41 [readonly,getter,assign,] (getter=e) [typedeclaration=id] [typekind=ObjCId]
+// CHECK: ObjCPropertyDecl=f:4:33 [assign,readwrite,] [typedeclaration=id] [typekind=ObjCId]
Index: include/clang-c/Index.h
===
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -4449,6 +4449,18 @@
 CINDEX_LINKAGE unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C,
  unsigned reserved);
 
+/**
+ * Given a cursor that represents a property declaration, return the
+ * name of the method that implements the getter.
+ */
+CINDEX_LINKAGE CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C);
+
+/**
+ * Given a cursor that represents a property declaration, return the
+ * name of the method that implements the setter, if any.
+ */
+CINDEX_LINKAGE CXString clang_Cursor_getObjCPropertySetterName(CXCursor C);
+
 /**
  * 'Qualifiers' written next to the return and parameter types in
  * Objective-C method declarations.
___
cfe-commits 

[PATCH] D49635: [libclang 8/8] Add support for the flag_enum attribute

2018-07-21 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This adds support to libclang for reading the flag_enum attribute.

This also bumps CINDEX_VERSION_MINOR for this patch series.


Repository:
  rC Clang

https://reviews.llvm.org/D49635

Files:
  include/clang-c/Index.h
  test/Index/attributes.c
  tools/libclang/CIndex.cpp
  tools/libclang/CXCursor.cpp


Index: tools/libclang/CXCursor.cpp
===
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -78,6 +78,7 @@
 case attr::ObjCDesignatedInitializer: return 
CXCursor_ObjCDesignatedInitializer;
 case attr::ObjCRuntimeVisible: return CXCursor_ObjCRuntimeVisible;
 case attr::ObjCBoxable: return CXCursor_ObjCBoxable;
+case attr::FlagEnum: return CXCursor_FlagEnum;
   }
 
   return CXCursor_UnexposedAttr;
Index: tools/libclang/CIndex.cpp
===
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -5313,6 +5313,8 @@
 return cxstring::createRef("attribute(objc_runtime_visible)");
   case CXCursor_ObjCBoxable:
 return cxstring::createRef("attribute(objc_boxable)");
+  case CXCursor_FlagEnum:
+return cxstring::createRef("attribute(flag_enum)");
   case CXCursor_PreprocessingDirective:
 return cxstring::createRef("preprocessing directive");
   case CXCursor_MacroDefinition:
Index: test/Index/attributes.c
===
--- test/Index/attributes.c
+++ test/Index/attributes.c
@@ -8,6 +8,10 @@
 void const_fn() __attribute__((const));
 void noduplicate_fn() __attribute__((noduplicate));
 
+enum __attribute((flag_enum)) FlagEnum {
+  Foo
+};
+
 // CHECK: attributes.c:3:32: StructDecl=Test2:3:32 (Definition) Extent=[3:1 - 
5:2]
 // CHECK: attributes.c:3:23: attribute(packed)=packed Extent=[3:23 - 3:29]
 // CHECK: attributes.c:4:8: FieldDecl=a:4:8 (Definition) Extent=[4:3 - 4:9] 
[access=public]
@@ -18,3 +22,5 @@
 // CHECK: attributes.c:8:32: attribute(const)= Extent=[8:32 - 8:37]
 // CHECK: attributes.c:9:6: FunctionDecl=noduplicate_fn:9:6 Extent=[9:1 - 9:51]
 // CHECK: attributes.c:9:38: attribute(noduplicate)= Extent=[9:38 - 9:49]
+// CHECK: attributes.c:11:31: EnumDecl=FlagEnum:11:31 (Definition) 
Extent=[11:1 - 13:2]
+// CHECK: attributes.c:11:19: attribute(flag_enum)= Extent=[11:19 - 11:28]
Index: include/clang-c/Index.h
===
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -32,7 +32,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 49
+#define CINDEX_VERSION_MINOR 50
 
 #define CINDEX_VERSION_ENCODE(major, minor) ( \
   ((major) * 1)   \
@@ -2586,7 +2586,8 @@
   CXCursor_ObjCDesignatedInitializer = 434,
   CXCursor_ObjCRuntimeVisible= 435,
   CXCursor_ObjCBoxable   = 436,
-  CXCursor_LastAttr  = CXCursor_ObjCBoxable,
+  CXCursor_FlagEnum  = 437,
+  CXCursor_LastAttr  = CXCursor_FlagEnum,
 
   /* Preprocessing */
   CXCursor_PreprocessingDirective= 500,


Index: tools/libclang/CXCursor.cpp
===
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -78,6 +78,7 @@
 case attr::ObjCDesignatedInitializer: return CXCursor_ObjCDesignatedInitializer;
 case attr::ObjCRuntimeVisible: return CXCursor_ObjCRuntimeVisible;
 case attr::ObjCBoxable: return CXCursor_ObjCBoxable;
+case attr::FlagEnum: return CXCursor_FlagEnum;
   }
 
   return CXCursor_UnexposedAttr;
Index: tools/libclang/CIndex.cpp
===
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -5313,6 +5313,8 @@
 return cxstring::createRef("attribute(objc_runtime_visible)");
   case CXCursor_ObjCBoxable:
 return cxstring::createRef("attribute(objc_boxable)");
+  case CXCursor_FlagEnum:
+return cxstring::createRef("attribute(flag_enum)");
   case CXCursor_PreprocessingDirective:
 return cxstring::createRef("preprocessing directive");
   case CXCursor_MacroDefinition:
Index: test/Index/attributes.c
===
--- test/Index/attributes.c
+++ test/Index/attributes.c
@@ -8,6 +8,10 @@
 void const_fn() __attribute__((const));
 void noduplicate_fn() __attribute__((noduplicate));
 
+enum __attribute((flag_enum)) FlagEnum {
+  Foo
+};
+
 // CHECK: attributes.c:3:32: StructDecl=Test2:3:32 (Definition) Extent=[3:1 - 5:2]
 // CHECK: attributes.c:3:23: attribute(packed)=packed Extent=[3:23 - 3:29]
 // CHECK: attributes.c:4:8: FieldDecl=a:4:8 (Definition) Extent=[4:3 - 4:9] [access=public]
@@ -18,3 +22,5 @@
 // CHECK: attributes.c:8:32: attribute(const)= Extent=[8:32 - 8:37]
 // CHECK: attributes.c:9:6: 

[PATCH] D49634: [libclang] Add support for getting property setter and getter names

2018-07-21 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This allows libclang to access the actual names of property setters and getters 
without needing to go through the indexer API. Usually default names are used, 
but the property can specify a different name.


Repository:
  rC Clang

https://reviews.llvm.org/D49634

Files:
  include/clang-c/Index.h
  test/Index/property-getter-setter.m
  tools/c-index-test/c-index-test.c
  tools/libclang/CIndex.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -31,6 +31,8 @@
 clang_Cursor_getNumArguments
 clang_Cursor_getObjCDeclQualifiers
 clang_Cursor_getObjCPropertyAttributes
+clang_Cursor_getObjCPropertyGetterName
+clang_Cursor_getObjCPropertySetterName
 clang_Cursor_getObjCSelectorIndex
 clang_Cursor_getOffsetOfField
 clang_Cursor_getSpellingNameRange
Index: tools/libclang/CIndex.cpp
===
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -7913,6 +7913,30 @@
   return Result;
 }
 
+CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C) {
+  if (C.kind != CXCursor_ObjCPropertyDecl)
+return cxstring::createNull();
+
+  const ObjCPropertyDecl *PD = dyn_cast(getCursorDecl(C));
+  Selector sel = PD->getGetterName();
+  if (sel.isNull())
+return cxstring::createNull();
+
+  return cxstring::createDup(sel.getAsString());
+}
+
+CXString clang_Cursor_getObjCPropertySetterName(CXCursor C) {
+  if (C.kind != CXCursor_ObjCPropertyDecl)
+return cxstring::createNull();
+
+  const ObjCPropertyDecl *PD = dyn_cast(getCursorDecl(C));
+  Selector sel = PD->getSetterName();
+  if (sel.isNull())
+return cxstring::createNull();
+
+  return cxstring::createDup(sel.getAsString());
+}
+
 unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C) {
   if (!clang_isDeclaration(C.kind))
 return CXObjCDeclQualifier_None;
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -1103,6 +1103,34 @@
   }
 }
 
+if (Cursor.kind == CXCursor_ObjCPropertyDecl) {
+  CXString Name = clang_Cursor_getObjCPropertyGetterName(Cursor);
+  CXString Spelling = clang_getCursorSpelling(Cursor);
+  const char *CName = clang_getCString(Name);
+  const char *CSpelling = clang_getCString(Spelling);
+  if (CName && strcmp(CName, CSpelling)) {
+printf(" (getter=%s)", CName);
+  }
+  clang_disposeString(Spelling);
+  clang_disposeString(Name);
+}
+
+if (Cursor.kind == CXCursor_ObjCPropertyDecl) {
+  CXString Name = clang_Cursor_getObjCPropertySetterName(Cursor);
+  CXString Spelling = clang_getCursorSpelling(Cursor);
+  const char *CName = clang_getCString(Name);
+  const char *CSpelling = clang_getCString(Spelling);
+  char *DefaultSetter = malloc(strlen(CSpelling) + 5);
+  sprintf(DefaultSetter, "set%s:", CSpelling);
+  DefaultSetter[3] &= ~(1 << 5); // Make uppercase
+  if (CName && strcmp(CName, DefaultSetter)) {
+printf(" (setter=%s)", CName);
+  }
+  free(DefaultSetter);
+  clang_disposeString(Spelling);
+  clang_disposeString(Name);
+}
+
 {
   unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
   if (QT != CXObjCDeclQualifier_None) {
Index: test/Index/property-getter-setter.m
===
--- /dev/null
+++ test/Index/property-getter-setter.m
@@ -0,0 +1,10 @@
+@interface Foo
+@property (assign,readwrite,getter=b,setter=c:) id a;
+@property (assign,readonly,getter=e) id d;
+@property (assign,readwrite) id f;
+@end
+
+// RUN: c-index-test -test-print-type-declaration
+// CHECK: ObjCPropertyDecl=a:2:52 [getter,assign,readwrite,setter,] (getter=b) (setter=c:) [typedeclaration=id] [typekind=ObjCId]
+// CHECK: ObjCPropertyDecl=d:3:41 [readonly,getter,assign,] (getter=e) [typedeclaration=id] [typekind=ObjCId]
+// CHECK: ObjCPropertyDecl=f:4:33 [assign,readwrite,] [typedeclaration=id] [typekind=ObjCId]
Index: include/clang-c/Index.h
===
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -4449,6 +4449,18 @@
 CINDEX_LINKAGE unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C,
  unsigned reserved);
 
+/**
+ * Given a cursor that represents a property declaration, return the
+ * name of the method that implements the getter.
+ */
+CINDEX_LINKAGE CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C);
+
+/**
+ * Given a cursor that represents a property declaration, return the
+ * name of the method that implements the setter, if any.
+ */
+CINDEX_LINKAGE CXString clang_Cursor_getObjCPropertySetterName(CXCursor C);
+
 /**
 

[PATCH] D49063: [libclang] Add support for ObjCObjectType

2018-07-12 Thread Michael Wu via Phabricator via cfe-commits
michaelwu added inline comments.



Comment at: include/clang-c/Index.h:35
 #define CINDEX_VERSION_MAJOR 0
 #define CINDEX_VERSION_MINOR 49
 

yvvan wrote:
> Please, increment the minor version (you are adding new functions)
This is one in a series of patches that add features to libclang - would you be 
ok with incrementing at the end of the series?



Comment at: include/clang-c/Index.h:3644
+ */
+CINDEX_LINKAGE int clang_Type_getNumObjCProtocolRefs(CXType T);
+

yvvan wrote:
> Other similar calls usually return unsigned int because they can't be below 
> zero.
I was mimicking `clang_Type_getNumTemplateArguments` for this, which appears to 
be the most similar API. It uses 0 to n for the number of template arguments 
and -1 to indicate that it was called on the wrong type.  If you're ok with the 
inconsistency, I'll make this unsigned. I also prefer having this unsigned.


https://reviews.llvm.org/D49063



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49127: [libclang] Add support for ObjC attributes without args

2018-07-10 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This adds support to libclang for identifying ObjC related attributes that 
don't take arguments.

All attributes but NSObject and NSConsumed are tested.


Repository:
  rC Clang

https://reviews.llvm.org/D49127

Files:
  include/clang-c/Index.h
  test/Index/index-attrs.m
  tools/libclang/CIndex.cpp
  tools/libclang/CXCursor.cpp

Index: tools/libclang/CXCursor.cpp
===
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -61,6 +61,23 @@
 case attr::Visibility: return CXCursor_VisibilityAttr;
 case attr::DLLExport: return CXCursor_DLLExport;
 case attr::DLLImport: return CXCursor_DLLImport;
+case attr::NSReturnsRetained: return CXCursor_NSReturnsRetained;
+case attr::NSReturnsNotRetained: return CXCursor_NSReturnsNotRetained;
+case attr::NSReturnsAutoreleased: return CXCursor_NSReturnsAutoreleased;
+case attr::NSConsumesSelf: return CXCursor_NSConsumesSelf;
+case attr::NSConsumed: return CXCursor_NSConsumed;
+case attr::ObjCException: return CXCursor_ObjCException;
+case attr::ObjCNSObject: return CXCursor_ObjCNSObject;
+case attr::ObjCIndependentClass: return CXCursor_ObjCIndependentClass;
+case attr::ObjCPreciseLifetime: return CXCursor_ObjCPreciseLifetime;
+case attr::ObjCReturnsInnerPointer: return CXCursor_ObjCReturnsInnerPointer;
+case attr::ObjCRequiresSuper: return CXCursor_ObjCRequiresSuper;
+case attr::ObjCRootClass: return CXCursor_ObjCRootClass;
+case attr::ObjCSubclassingRestricted: return CXCursor_ObjCSubclassingRestricted;
+case attr::ObjCExplicitProtocolImpl: return CXCursor_ObjCExplicitProtocolImpl;
+case attr::ObjCDesignatedInitializer: return CXCursor_ObjCDesignatedInitializer;
+case attr::ObjCRuntimeVisible: return CXCursor_ObjCRuntimeVisible;
+case attr::ObjCBoxable: return CXCursor_ObjCBoxable;
   }
 
   return CXCursor_UnexposedAttr;
Index: tools/libclang/CIndex.cpp
===
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -5276,6 +5276,40 @@
 return cxstring::createRef("attribute(dllexport)");
   case CXCursor_DLLImport:
 return cxstring::createRef("attribute(dllimport)");
+  case CXCursor_NSReturnsRetained:
+return cxstring::createRef("attribute(ns_returns_retained)");
+  case CXCursor_NSReturnsNotRetained:
+return cxstring::createRef("attribute(ns_returns_not_retained)");
+  case CXCursor_NSReturnsAutoreleased:
+return cxstring::createRef("attribute(ns_returns_autoreleased)");
+  case CXCursor_NSConsumesSelf:
+return cxstring::createRef("attribute(ns_consumes_self)");
+  case CXCursor_NSConsumed:
+return cxstring::createRef("attribute(ns_consumed)");
+  case CXCursor_ObjCException:
+return cxstring::createRef("attribute(objc_exception)");
+  case CXCursor_ObjCNSObject:
+return cxstring::createRef("attribute(NSObject)");
+  case CXCursor_ObjCIndependentClass:
+return cxstring::createRef("attribute(objc_independent_class)");
+  case CXCursor_ObjCPreciseLifetime:
+return cxstring::createRef("attribute(objc_precise_lifetime)");
+  case CXCursor_ObjCReturnsInnerPointer:
+return cxstring::createRef("attribute(objc_returns_inner_pointer)");
+  case CXCursor_ObjCRequiresSuper:
+return cxstring::createRef("attribute(objc_requires_super)");
+  case CXCursor_ObjCRootClass:
+return cxstring::createRef("attribute(objc_root_class)");
+  case CXCursor_ObjCSubclassingRestricted:
+return cxstring::createRef("attribute(objc_subclassing_restricted)");
+  case CXCursor_ObjCExplicitProtocolImpl:
+return cxstring::createRef("attribute(objc_protocol_requires_explicit_implementation)");
+  case CXCursor_ObjCDesignatedInitializer:
+return cxstring::createRef("attribute(objc_designated_initializer)");
+  case CXCursor_ObjCRuntimeVisible:
+return cxstring::createRef("attribute(objc_runtime_visible)");
+  case CXCursor_ObjCBoxable:
+return cxstring::createRef("attribute(objc_boxable)");
   case CXCursor_PreprocessingDirective:
 return cxstring::createRef("preprocessing directive");
   case CXCursor_MacroDefinition:
Index: test/Index/index-attrs.m
===
--- test/Index/index-attrs.m
+++ test/Index/index-attrs.m
@@ -9,9 +9,48 @@
 @property (assign) id prop __attribute__((annotate("anno")));
 @end
 
+__attribute__((objc_protocol_requires_explicit_implementation))
+@protocol P
+@end
+
+typedef id __attribute__((objc_independent_class)) T2;
+id __attribute__((objc_precise_lifetime)) x;
+struct __attribute__((objc_boxable)) S {
+  int x;
+};
+
+__attribute__((objc_exception))
+__attribute__((objc_root_class))
+__attribute__((objc_subclassing_restricted))
+__attribute__((objc_runtime_visible))
+@interface J
+-(id)a __attribute__((ns_returns_retained));
+-(id)b __attribute__((ns_returns_not_retained));
+-(id)c __attribu

[PATCH] D49082: [libclang] Add the clang_Type_getNullability() API

2018-07-09 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This patch adds a clang-c API for querying the nullability of an AttributedType.

The test here also tests https://reviews.llvm.org/D49081


Repository:
  rC Clang

https://reviews.llvm.org/D49082

Files:
  include/clang-c/Index.h
  test/Index/nullability.c
  tools/c-index-test/c-index-test.c
  tools/libclang/CXType.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -104,6 +104,7 @@
 clang_Type_getNumObjCTypeArgs
 clang_Type_getObjCTypeArg
 clang_Type_getModifiedType
+clang_Type_getNullability
 clang_VerbatimBlockLineComment_getText
 clang_VerbatimLineComment_getText
 clang_HTMLTagComment_getAsString
Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -1240,3 +1240,22 @@
   }
   return false;
 }
+
+enum CXTypeNullabilityKind clang_Type_getNullability(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return CXTypeNullability_Invalid;
+
+  ASTContext &Ctx = cxtu::getASTUnit(GetTU(CT))->getASTContext();
+  if (auto nullability = T->getNullability(Ctx)) {
+switch (*nullability) {
+  case NullabilityKind::NonNull:
+return CXTypeNullability_NonNull;
+  case NullabilityKind::Nullable:
+return CXTypeNullability_Nullable;
+  case NullabilityKind::Unspecified:
+return CXTypeNullability_Unspecified;
+}
+  }
+  return CXTypeNullability_Invalid;
+}
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -84,6 +84,8 @@
 options |= CXTranslationUnit_KeepGoing;
   if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE"))
 options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble;
+  if (getenv("CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES"))
+options |= CXTranslationUnit_IncludeAttributedTypes;
 
   return options;
 }
@@ -1496,14 +1498,31 @@
   }
 }
 
+static void PrintNullabilityKind(CXType T, const char *Format) {
+  enum CXTypeNullabilityKind N = clang_Type_getNullability(T);
+
+  const char *nullability = 0;
+  switch (N) {
+case CXTypeNullability_NonNull: nullability = "nonnull"; break;
+case CXTypeNullability_Nullable: nullability = "nullable"; break;
+case CXTypeNullability_Unspecified: nullability = "unspecified"; break;
+case CXTypeNullability_Invalid: break;
+  }
+
+  if (nullability) {
+printf(Format, nullability);
+  }
+}
+
 static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
  CXClientData d) {
   if (!clang_isInvalid(clang_getCursorKind(cursor))) {
 CXType T = clang_getCursorType(cursor);
 CXType PT = clang_getPointeeType(T);
 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
 PrintCursor(cursor, NULL);
 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
+PrintNullabilityKind(T, " [nullability=%s]");
 if (clang_isConstQualifiedType(T))
   printf(" const");
 if (clang_isVolatileQualifiedType(T))
@@ -1524,12 +1543,20 @@
 PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d=");
   }
 }
+/* Print the modified type if it exists. */
+{
+  CXType MT = clang_Type_getModifiedType(T);
+  if (MT.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(MT, " [modifiedtype=%s] [modifiedtypekind=%s]");
+  }
+}
 /* Print the return type if it exists. */
 {
   CXType RT = clang_getCursorResultType(cursor);
   if (RT.kind != CXType_Invalid) {
 PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
   }
+  PrintNullabilityKind(RT, " [resultnullability=%s]");
 }
 /* Print the argument types if they exist. */
 {
@@ -1541,6 +1568,7 @@
   CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
   if (T.kind != CXType_Invalid) {
 PrintTypeAndTypeKind(T, " [%s] [%s]");
+PrintNullabilityKind(T, " [%s]");
   }
 }
 printf("]");
Index: test/Index/nullability.c
===
--- /dev/null
+++ test/Index/nullability.c
@@ -0,0 +1,10 @@
+int *a;
+int * _Nonnull b;
+int * _Nullable c;
+int * _Null_unspecified d;
+
+// RUN: env CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES=1 c-index-test -test-print-type %s | FileCheck %s
+// CHECK: VarDecl=a:1:6 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: VarDecl=b:2:16 [type=int * _Nonnull] [typekind=Attributed] [nullability=nonnull] [canonicaltype=int *] [canonicaltypekind=Pointer] [modifiedtype=int *] [modifiedtypekind=Pointer] [isPOD=1]
+// CHECK: VarDecl=c:3:17 [type=int * _Nullable] [typekind=Attribute

[PATCH] D49081: [libclang] Add support for AttributedType

2018-07-09 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This patch adds support to the libclang API for identifying AttributedTypes in 
CXTypes and reading the modified type that the type points to. Currently 
AttributedTypes are skipped. This patch continues to skip AttributedTypes by 
default, but adds a parsing option to CXTranslationUnit to include 
AttributedTypes.

This patch depends on https://reviews.llvm.org/D49066 since it also adds a 
CXType.

Testing will be added in another patch which depends on this one.


Repository:
  rC Clang

https://reviews.llvm.org/D49081

Files:
  include/clang-c/Index.h
  tools/libclang/CXType.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -103,6 +103,7 @@
 clang_Type_getObjCProtocolDecl
 clang_Type_getNumObjCTypeArgs
 clang_Type_getObjCTypeArg
+clang_Type_getModifiedType
 clang_VerbatimBlockLineComment_getText
 clang_VerbatimLineComment_getText
 clang_HTMLTagComment_getAsString
Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -112,6 +112,7 @@
 TKCASE(Auto);
 TKCASE(Elaborated);
 TKCASE(Pipe);
+TKCASE(Attributed);
 default:
   return CXType_Unexposed;
   }
@@ -125,7 +126,9 @@
   if (TU && !T.isNull()) {
 // Handle attributed types as the original type
 if (auto *ATT = T->getAs()) {
-  return MakeCXType(ATT->getModifiedType(), TU);
+  if (!(TU->ParsingOptions & CXTranslationUnit_IncludeAttributedTypes)) {
+return MakeCXType(ATT->getModifiedType(), TU);
+  }
 }
 // Handle paren types as the original type
 if (auto *PTT = T->getAs()) {
@@ -591,6 +594,7 @@
 TKIND(Auto);
 TKIND(Elaborated);
 TKIND(Pipe);
+TKIND(Attributed);
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id);
 #include "clang/Basic/OpenCLImageTypes.def"
 #undef IMAGE_TYPE
@@ -996,6 +1000,17 @@
   return CXTypeLayoutError_InvalidFieldName;
 }
 
+CXType clang_Type_getModifiedType(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  if (auto *ATT = T->getAs())
+return MakeCXType(ATT->getModifiedType(), GetTU(CT));
+
+  return MakeCXType(QualType(), GetTU(CT));
+}
+
 long long clang_Cursor_getOffsetOfField(CXCursor C) {
   if (clang_isDeclaration(C.kind)) {
 // we need to validate the parent type
Index: include/clang-c/Index.h
===
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -1332,7 +1332,12 @@
*
* The function bodies of the main file are not skipped.
*/
-  CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 0x800
+  CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 0x800,
+
+  /**
+   * Used to indicate that attributed types should be included in CXType.
+   */
+  CXTranslationUnit_IncludeAttributedTypes = 0x1000
 };
 
 /**
@@ -3269,7 +3274,8 @@
   CXType_OCLReserveID = 160,
 
   CXType_ObjCObject = 161,
-  CXType_ObjCTypeParam = 162
+  CXType_ObjCTypeParam = 162,
+  CXType_Attributed = 163
 };
 
 /**
@@ -3818,6 +3824,13 @@
  */
 CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
 
+/**
+ * Return the type that was modified by this attributed type.
+ *
+ * If the type is not an attributed type, an invalid type is returned.
+ */
+CINDEX_LINKAGE CXType clang_Type_getModifiedType(CXType T);
+
 /**
  * Return the offset of the field represented by the Cursor.
  *
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49066: [libclang] Add support for ObjCTypeParam

2018-07-09 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This patch adds support to the libclang API for identifying ObjCTypeParams in 
CXTypes.

This patch depends on https://reviews.llvm.org/D49063 since both patches add 
new values to CXTypeKind.


Repository:
  rC Clang

https://reviews.llvm.org/D49066

Files:
  include/clang-c/Index.h
  test/Index/print-type.m
  tools/libclang/CXType.cpp


Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -100,6 +100,7 @@
 TKCASE(ObjCInterface);
 TKCASE(ObjCObject);
 TKCASE(ObjCObjectPointer);
+TKCASE(ObjCTypeParam);
 TKCASE(FunctionNoProto);
 TKCASE(FunctionProto);
 TKCASE(ConstantArray);
@@ -578,6 +579,7 @@
 TKIND(ObjCInterface);
 TKIND(ObjCObject);
 TKIND(ObjCObjectPointer);
+TKIND(ObjCTypeParam);
 TKIND(FunctionNoProto);
 TKIND(FunctionProto);
 TKIND(ConstantArray);
Index: test/Index/print-type.m
===
--- test/Index/print-type.m
+++ test/Index/print-type.m
@@ -7,6 +7,10 @@
 @property (class) int classProp;
 @end
 
+@interface Bar : Foo
+-(SomeType)generic;
+@end
+
 // RUN: c-index-test -test-print-type %s | FileCheck %s
 // CHECK: ObjCPropertyDecl=x:2:25 [readonly,] [type=id] [typekind=ObjCId] 
[canonicaltype=id] [canonicaltypekind=ObjCObjectPointer] [isPOD=1]
 // CHECK: ObjCInstanceMethodDecl=mymethod:3:8 [type=] [typekind=Invalid] 
[resulttype=int] [resulttypekind=Int] [isPOD=0]
@@ -17,3 +21,4 @@
 // CHECK: ParmDecl=j:5:49 (Definition) [Out,] [type=short *] 
[typekind=Pointer] [isPOD=1] [pointeetype=short] [pointeekind=Short]
 // CHECK: ParmDecl=p:6:36 (Definition) [type=__kindof Foo *] 
[typekind=ObjCObjectPointer] [canonicaltype=__kindof Foo *] 
[canonicaltypekind=ObjCObjectPointer] [basetype=Foo] [basekind=ObjCInterface] 
[isPOD=1] [pointeetype=Foo] [pointeekind=ObjCInterface]
 // CHECK: ObjCPropertyDecl=classProp:7:23 [class,] [type=int] [typekind=Int] 
[isPOD=1]
+// CHECK: ObjCInstanceMethodDecl=generic:11:12 [type=] [typekind=Invalid] 
[resulttype=SomeType] [resulttypekind=ObjCTypeParam] [isPOD=0]
Index: include/clang-c/Index.h
===
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -3268,7 +3268,8 @@
   CXType_OCLQueue = 159,
   CXType_OCLReserveID = 160,
 
-  CXType_ObjCObject = 161
+  CXType_ObjCObject = 161,
+  CXType_ObjCTypeParam = 162
 };
 
 /**


Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -100,6 +100,7 @@
 TKCASE(ObjCInterface);
 TKCASE(ObjCObject);
 TKCASE(ObjCObjectPointer);
+TKCASE(ObjCTypeParam);
 TKCASE(FunctionNoProto);
 TKCASE(FunctionProto);
 TKCASE(ConstantArray);
@@ -578,6 +579,7 @@
 TKIND(ObjCInterface);
 TKIND(ObjCObject);
 TKIND(ObjCObjectPointer);
+TKIND(ObjCTypeParam);
 TKIND(FunctionNoProto);
 TKIND(FunctionProto);
 TKIND(ConstantArray);
Index: test/Index/print-type.m
===
--- test/Index/print-type.m
+++ test/Index/print-type.m
@@ -7,6 +7,10 @@
 @property (class) int classProp;
 @end
 
+@interface Bar : Foo
+-(SomeType)generic;
+@end
+
 // RUN: c-index-test -test-print-type %s | FileCheck %s
 // CHECK: ObjCPropertyDecl=x:2:25 [readonly,] [type=id] [typekind=ObjCId] [canonicaltype=id] [canonicaltypekind=ObjCObjectPointer] [isPOD=1]
 // CHECK: ObjCInstanceMethodDecl=mymethod:3:8 [type=] [typekind=Invalid] [resulttype=int] [resulttypekind=Int] [isPOD=0]
@@ -17,3 +21,4 @@
 // CHECK: ParmDecl=j:5:49 (Definition) [Out,] [type=short *] [typekind=Pointer] [isPOD=1] [pointeetype=short] [pointeekind=Short]
 // CHECK: ParmDecl=p:6:36 (Definition) [type=__kindof Foo *] [typekind=ObjCObjectPointer] [canonicaltype=__kindof Foo *] [canonicaltypekind=ObjCObjectPointer] [basetype=Foo] [basekind=ObjCInterface] [isPOD=1] [pointeetype=Foo] [pointeekind=ObjCInterface]
 // CHECK: ObjCPropertyDecl=classProp:7:23 [class,] [type=int] [typekind=Int] [isPOD=1]
+// CHECK: ObjCInstanceMethodDecl=generic:11:12 [type=] [typekind=Invalid] [resulttype=SomeType] [resulttypekind=ObjCTypeParam] [isPOD=0]
Index: include/clang-c/Index.h
===
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -3268,7 +3268,8 @@
   CXType_OCLQueue = 159,
   CXType_OCLReserveID = 160,
 
-  CXType_ObjCObject = 161
+  CXType_ObjCObject = 161,
+  CXType_ObjCTypeParam = 162
 };
 
 /**
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49063: [libclang] Add support for ObjCObjectType

2018-07-09 Thread Michael Wu via Phabricator via cfe-commits
michaelwu updated this revision to Diff 154540.
michaelwu added a comment.

Replaced tabs with spaces.


https://reviews.llvm.org/D49063

Files:
  include/clang-c/Index.h
  test/Index/objc-typeargs-protocols.m
  test/Index/print-type.m
  tools/c-index-test/c-index-test.c
  tools/libclang/CXType.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -98,6 +98,11 @@
 clang_Type_visitFields
 clang_Type_getNamedType
 clang_Type_isTransparentTagTypedef
+clang_Type_getObjCObjectBaseType
+clang_Type_getNumObjCProtocolRefs
+clang_Type_getObjCProtocolDecl
+clang_Type_getNumObjCTypeArgs
+clang_Type_getObjCTypeArg
 clang_VerbatimBlockLineComment_getText
 clang_VerbatimLineComment_getText
 clang_HTMLTagComment_getAsString
Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -98,6 +98,7 @@
 TKCASE(Enum);
 TKCASE(Typedef);
 TKCASE(ObjCInterface);
+TKCASE(ObjCObject);
 TKCASE(ObjCObjectPointer);
 TKCASE(FunctionNoProto);
 TKCASE(FunctionProto);
@@ -575,6 +576,7 @@
 TKIND(Enum);
 TKIND(Typedef);
 TKIND(ObjCInterface);
+TKIND(ObjCObject);
 TKIND(ObjCObjectPointer);
 TKIND(FunctionNoProto);
 TKIND(FunctionProto);
@@ -1098,6 +1100,74 @@
   return MakeCXType(QT.getValueOr(QualType()), GetTU(CT));
 }
 
+CXType clang_Type_getObjCObjectBaseType(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return MakeCXType(QualType(), GetTU(CT));
+
+  return MakeCXType(OT->getBaseType(), GetTU(CT));
+}
+
+int clang_Type_getNumObjCProtocolRefs(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return -1;
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return -1;
+
+  return OT->getNumProtocols();
+}
+
+CXCursor clang_Type_getObjCProtocolDecl(CXType CT, unsigned i) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const ObjCProtocolDecl *PD = OT->getProtocol(i);
+  if (!PD)
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  return cxcursor::MakeCXCursor(PD, GetTU(CT));
+}
+
+int clang_Type_getNumObjCTypeArgs(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return -1;
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return -1;
+
+  return OT->getTypeArgs().size();
+}
+
+CXType clang_Type_getObjCTypeArg(CXType CT, unsigned i) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ArrayRef TA = OT->getTypeArgs();
+  if ((size_t)i >= TA.size())
+return MakeCXType(QualType(), GetTU(CT));
+
+  return MakeCXType(TA[i], GetTU(CT));
+}
+
 unsigned clang_Type_visitFields(CXType PT,
 CXFieldVisitor visitor,
 CXClientData client_data){
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -1500,6 +1500,7 @@
  CXClientData d) {
   if (!clang_isInvalid(clang_getCursorKind(cursor))) {
 CXType T = clang_getCursorType(cursor);
+CXType PT = clang_getPointeeType(T);
 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
 PrintCursor(cursor, NULL);
 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
@@ -1545,11 +1546,45 @@
 printf("]");
   }
 }
+/* Print ObjC base types, type arguments, and protocol list if available. */
+{
+  CXType BT = clang_Type_getObjCObjectBaseType(PT);
+  if (BT.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]");
+  }
+}
+{
+  int NumTypeArgs = clang_Type_getNumObjCTypeArgs(PT);
+  if (NumTypeArgs > 0) {
+int i;
+printf(" [typeargs=");
+for (i = 0; i < NumTypeArgs; ++i) {
+  CXType TA = clang_Type_getObjCTypeArg(PT, i);
+  if (TA.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(TA, " [%s] [%s]");
+  }
+}
+printf("]");
+  }
+}
+{
+  int NumProtocols = clang_Type_getNumObjCProtocolRefs(PT);
+  if (NumProtocols > 0) {
+int i;
+printf(" [protocols=");
+for (i = 0; i < NumProtocols; ++i) {
+  CXCursor P = clang_Type_getObjCProtocolDecl(PT, i);
+  if (!clang_isInvalid(cl

[PATCH] D49063: [libclang] Add support for ObjCObjectType

2018-07-09 Thread Michael Wu via Phabricator via cfe-commits
michaelwu created this revision.

This patch adds support to the clang-c API for identifying ObjCObjects in 
CXTypes, enumerating type args and protocols on ObjCObjectTypes, and retrieving 
the base type of ObjCObjectTypes. Currently only ObjCInterfaceTypes are 
exposed, which do not have type args or protocols.


Repository:
  rC Clang

https://reviews.llvm.org/D49063

Files:
  include/clang-c/Index.h
  test/Index/objc-typeargs-protocols.m
  test/Index/print-type.m
  tools/c-index-test/c-index-test.c
  tools/libclang/CXType.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -98,6 +98,11 @@
 clang_Type_visitFields
 clang_Type_getNamedType
 clang_Type_isTransparentTagTypedef
+clang_Type_getObjCObjectBaseType
+clang_Type_getNumObjCProtocolRefs
+clang_Type_getObjCProtocolDecl
+clang_Type_getNumObjCTypeArgs
+clang_Type_getObjCTypeArg
 clang_VerbatimBlockLineComment_getText
 clang_VerbatimLineComment_getText
 clang_HTMLTagComment_getAsString
Index: tools/libclang/CXType.cpp
===
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -98,6 +98,7 @@
 TKCASE(Enum);
 TKCASE(Typedef);
 TKCASE(ObjCInterface);
+TKCASE(ObjCObject);
 TKCASE(ObjCObjectPointer);
 TKCASE(FunctionNoProto);
 TKCASE(FunctionProto);
@@ -575,6 +576,7 @@
 TKIND(Enum);
 TKIND(Typedef);
 TKIND(ObjCInterface);
+TKIND(ObjCObject);
 TKIND(ObjCObjectPointer);
 TKIND(FunctionNoProto);
 TKIND(FunctionProto);
@@ -1098,6 +1100,74 @@
   return MakeCXType(QT.getValueOr(QualType()), GetTU(CT));
 }
 
+CXType clang_Type_getObjCObjectBaseType(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return MakeCXType(QualType(), GetTU(CT));
+
+  return MakeCXType(OT->getBaseType(), GetTU(CT));
+}
+
+int clang_Type_getNumObjCProtocolRefs(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return -1;
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return -1;
+
+  return OT->getNumProtocols();
+}
+
+CXCursor clang_Type_getObjCProtocolDecl(CXType CT, unsigned i) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const ObjCProtocolDecl *PD = OT->getProtocol(i);
+  if (!PD)
+return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  return cxcursor::MakeCXCursor(PD, GetTU(CT));
+}
+
+int clang_Type_getNumObjCTypeArgs(CXType CT) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return -1;
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return -1;
+
+  return OT->getTypeArgs().size();
+}
+
+CXType clang_Type_getObjCTypeArg(CXType CT, unsigned i) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ObjCObjectType *OT = dyn_cast(T);
+  if (!OT)
+return MakeCXType(QualType(), GetTU(CT));
+
+  const ArrayRef TA = OT->getTypeArgs();
+  if ((size_t)i >= TA.size())
+return MakeCXType(QualType(), GetTU(CT));
+
+  return MakeCXType(TA[i], GetTU(CT));
+}
+
 unsigned clang_Type_visitFields(CXType PT,
 CXFieldVisitor visitor,
 CXClientData client_data){
Index: tools/c-index-test/c-index-test.c
===
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -1500,6 +1500,7 @@
  CXClientData d) {
   if (!clang_isInvalid(clang_getCursorKind(cursor))) {
 CXType T = clang_getCursorType(cursor);
+CXType PT = clang_getPointeeType(T);
 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
 PrintCursor(cursor, NULL);
 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
@@ -1545,11 +1546,45 @@
 printf("]");
   }
 }
+/* Print ObjC base types, type arguments, and protocol list if available. */
+{
+  CXType BT = clang_Type_getObjCObjectBaseType(PT);
+  if (BT.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]");
+  }
+}
+{
+  int NumTypeArgs = clang_Type_getNumObjCTypeArgs(PT);
+  if (NumTypeArgs > 0) {
+int i;
+	printf(" [typeargs=");
+	for (i = 0; i < NumTypeArgs; ++i) {
+	  CXType TA = clang_Type_getObjCTypeArg(PT, i);
+	  if (TA.kind != CXType_Invalid) {
+PrintTypeAndTypeKind(TA, " [%s] [%s]");
+	  }
+	}
+	printf("]");
+  }
+}
+{
+  int NumProtocols = clang_Type_getNumObjCProtocolRefs(PT);
+  if (NumProtocols > 0) {
+