forked from OSchip/llvm-project
Introduce a new libclang API to determine the platform availability of
a given entity, so that we can tell when the entity was introduced/deprecated/obsoleted on each platform for which we have an annotation. Addresses <rdar://problem/11365715>. llvm-svn: 156347
This commit is contained in:
parent
ececf9f0ae
commit
d6225d304e
|
@ -133,6 +133,29 @@ enum CXAvailabilityKind {
|
|||
CXAvailability_NotAccessible
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describes a version number of the form major.minor.subminor.
|
||||
*/
|
||||
typedef struct CXVersion {
|
||||
/**
|
||||
* \brief The major version number, e.g., the '10' in '10.7.3'. A negative
|
||||
* value indicates that there is no version number at all.
|
||||
*/
|
||||
int Major;
|
||||
/**
|
||||
* \brief The minor version number, e.g., the '7' in '10.7.3'. This value
|
||||
* will be negative if no minor version number was provided, e.g., for
|
||||
* version '10'.
|
||||
*/
|
||||
int Minor;
|
||||
/**
|
||||
* \brief The subminor version number, e.g., the '3' in '10.7.3'. This value
|
||||
* will be negative if no minor or subminor version number was provided,
|
||||
* e.g., in version '10' or '10.7'.
|
||||
*/
|
||||
int Subminor;
|
||||
} CXVersion;
|
||||
|
||||
/**
|
||||
* \defgroup CINDEX_STRING String manipulation routines
|
||||
*
|
||||
|
@ -2165,7 +2188,8 @@ enum CXLinkageKind {
|
|||
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Determine the availability of the entity that this cursor refers to.
|
||||
* \brief Determine the availability of the entity that this cursor refers to,
|
||||
* taking the current target platform into account.
|
||||
*
|
||||
* \param cursor The cursor to query.
|
||||
*
|
||||
|
@ -2174,6 +2198,94 @@ CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
|
|||
CINDEX_LINKAGE enum CXAvailabilityKind
|
||||
clang_getCursorAvailability(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* Describes the availability of a given entity on a particular platform, e.g.,
|
||||
* a particular class might only be available on Mac OS 10.7 or newer.
|
||||
*/
|
||||
typedef struct CXPlatformAvailability {
|
||||
/**
|
||||
* \brief A string that describes the platform for which this structure
|
||||
* provides availability information.
|
||||
*
|
||||
* Possible values are "ios" or "macosx".
|
||||
*/
|
||||
CXString Platform;
|
||||
/**
|
||||
* \brief The version number in which this entity was introduced.
|
||||
*/
|
||||
CXVersion Introduced;
|
||||
/**
|
||||
* \brief The version number in which this entity was deprecated (but is
|
||||
* still available).
|
||||
*/
|
||||
CXVersion Deprecated;
|
||||
/**
|
||||
* \brief The version number in which this entity was obsoleted, and therefore
|
||||
* is no longer available.
|
||||
*/
|
||||
CXVersion Obsoleted;
|
||||
/**
|
||||
* \brief Whether the entity is unconditionally unavailable on this platform.
|
||||
*/
|
||||
int Unavailable;
|
||||
/**
|
||||
* \brief An optional message to provide to a user of this API, e.g., to
|
||||
* suggest replacement APIs.
|
||||
*/
|
||||
CXString Message;
|
||||
} CXPlatformAvailability;
|
||||
|
||||
/**
|
||||
* \brief Determine the availability of the entity that this cursor refers to
|
||||
* on any platforms for which availability information is known.
|
||||
*
|
||||
* \param cursor The cursor to query.
|
||||
*
|
||||
* \param always_deprecated If non-NULL, will be set to indicate whether the
|
||||
* entity is deprecated on all platforms.
|
||||
*
|
||||
* \param deprecated_message If non-NULL, will be set to the message text
|
||||
* provided along with the unconditional deprecation of this entity. The client
|
||||
* is responsible for deallocating this string.
|
||||
*
|
||||
* \param always_unavailabile If non-NULL, will be set to indicate whether the
|
||||
* entity is unavailable on all platforms.
|
||||
*
|
||||
* \param unavailable_message If non-NULL, will be set to the message text
|
||||
* provided along with the unconditional unavailability of this entity. The
|
||||
* client is responsible for deallocating this string.
|
||||
*
|
||||
* \param availability If non-NULL, an array of CXPlatformAvailability instances
|
||||
* that will be populated with platform availability information, up to either
|
||||
* the number of platforms for which availability information is available (as
|
||||
* returned by this function) or \c availability_size, whichever is smaller.
|
||||
*
|
||||
* \param availability_size The number of elements available in the
|
||||
* \c availability array.
|
||||
*
|
||||
* \returns The number of platforms (N) for which availability information is
|
||||
* available (which is unrelated to \c availability_size).
|
||||
*
|
||||
* Note that the client is responsible for calling
|
||||
* \c clang_disposeCXPlatformAvailability to free each of the
|
||||
* platform-availability structures returned. There are
|
||||
* \c min(N, availability_size) such structures.
|
||||
*/
|
||||
CINDEX_LINKAGE int
|
||||
clang_getCursorPlatformAvailability(CXCursor cursor,
|
||||
int *always_deprecated,
|
||||
CXString *deprecated_message,
|
||||
int *always_unavailable,
|
||||
CXString *unavailable_message,
|
||||
CXPlatformAvailability *availability,
|
||||
int availability_size);
|
||||
|
||||
/**
|
||||
* \brief Free the memory associated with a \c CXPlatformAvailability structure.
|
||||
*/
|
||||
CINDEX_LINKAGE void
|
||||
clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability);
|
||||
|
||||
/**
|
||||
* \brief Describe the "language" of the entity referred to by a cursor.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// Run lines below; this test is line- and column-sensitive.
|
||||
|
||||
void foo(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7), availability(ios,introduced=3.2,deprecated=4.1)));
|
||||
|
||||
// RUN: c-index-test -test-load-source all %s | FileCheck %s
|
||||
// CHECK: (ios, introduced=3.2, deprecated=4.1) (macosx, introduced=10.4, deprecated=10.5, obsoleted=10.7)
|
|
@ -83,7 +83,7 @@ struct X0 {};
|
|||
// CHECK: <invalid loc>:0:0: attribute(ibaction)=
|
||||
// CHECK: c-index-api-loadTU-test.m:8:50: ParmDecl=msg:8:50 (Definition) Extent=[8:47 - 8:53]
|
||||
// CHECK: c-index-api-loadTU-test.m:8:47: TypeRef=id:0:0 Extent=[8:47 - 8:49]
|
||||
// CHECK: c-index-api-loadTU-test.m:9:3: ObjCInstanceMethodDecl=foo:9:3 (deprecated) Extent=[9:1 - 9:35]
|
||||
// CHECK: c-index-api-loadTU-test.m:9:3: ObjCInstanceMethodDecl=foo:9:3 (deprecated) (always deprecated: "") Extent=[9:1 - 9:35]
|
||||
// CHECK: c-index-api-loadTU-test.m:10:3: ObjCClassMethodDecl=fooC:10:3 Extent=[10:1 - 10:8]
|
||||
// CHECK: c-index-api-loadTU-test.m:14:12: ObjCInterfaceDecl=Bar:14:12 Extent=[14:1 - 18:5]
|
||||
// CHECK: c-index-api-loadTU-test.m:14:18: ObjCSuperClassRef=Foo:4:12 Extent=[14:18 - 14:21]
|
||||
|
|
|
@ -180,6 +180,20 @@ static void PrintRange(CXSourceRange R, const char *str) {
|
|||
|
||||
int want_display_name = 0;
|
||||
|
||||
static void printVersion(const char *Prefix, CXVersion Version) {
|
||||
if (Version.Major < 0)
|
||||
return;
|
||||
printf("%s%d", Prefix, Version.Major);
|
||||
|
||||
if (Version.Minor < 0)
|
||||
return;
|
||||
printf(".%d", Version.Minor);
|
||||
|
||||
if (Version.Subminor < 0)
|
||||
return;
|
||||
printf(".%d", Version.Subminor);
|
||||
}
|
||||
|
||||
static void PrintCursor(CXCursor Cursor) {
|
||||
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
|
||||
if (clang_isInvalid(Cursor.kind)) {
|
||||
|
@ -197,6 +211,13 @@ static void PrintCursor(CXCursor Cursor) {
|
|||
unsigned RefNameRangeNr;
|
||||
CXSourceRange CursorExtent;
|
||||
CXSourceRange RefNameRange;
|
||||
int AlwaysUnavailable;
|
||||
int AlwaysDeprecated;
|
||||
CXString UnavailableMessage;
|
||||
CXString DeprecatedMessage;
|
||||
CXPlatformAvailability PlatformAvailability[2];
|
||||
int NumPlatformAvailability;
|
||||
int I;
|
||||
|
||||
ks = clang_getCursorKindSpelling(Cursor.kind);
|
||||
string = want_display_name? clang_getCursorDisplayName(Cursor)
|
||||
|
@ -249,6 +270,47 @@ static void PrintCursor(CXCursor Cursor) {
|
|||
break;
|
||||
}
|
||||
|
||||
NumPlatformAvailability
|
||||
= clang_getCursorPlatformAvailability(Cursor,
|
||||
&AlwaysDeprecated,
|
||||
&DeprecatedMessage,
|
||||
&AlwaysUnavailable,
|
||||
&UnavailableMessage,
|
||||
PlatformAvailability, 2);
|
||||
if (AlwaysUnavailable) {
|
||||
printf(" (always unavailable: \"%s\")",
|
||||
clang_getCString(UnavailableMessage));
|
||||
} else if (AlwaysDeprecated) {
|
||||
printf(" (always deprecated: \"%s\")",
|
||||
clang_getCString(DeprecatedMessage));
|
||||
} else {
|
||||
for (I = 0; I != NumPlatformAvailability; ++I) {
|
||||
if (I >= 2)
|
||||
break;
|
||||
|
||||
printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
|
||||
if (PlatformAvailability[I].Unavailable)
|
||||
printf(", unavailable");
|
||||
else {
|
||||
printVersion(", introduced=", PlatformAvailability[I].Introduced);
|
||||
printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
|
||||
printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
|
||||
}
|
||||
if (clang_getCString(PlatformAvailability[I].Message)[0])
|
||||
printf(", message=\"%s\"",
|
||||
clang_getCString(PlatformAvailability[I].Message));
|
||||
printf(")");
|
||||
}
|
||||
}
|
||||
for (I = 0; I != NumPlatformAvailability; ++I) {
|
||||
if (I >= 2)
|
||||
break;
|
||||
clang_disposeCXPlatformAvailability(PlatformAvailability + I);
|
||||
}
|
||||
|
||||
clang_disposeString(DeprecatedMessage);
|
||||
clang_disposeString(UnavailableMessage);
|
||||
|
||||
if (clang_CXXMethod_isStatic(Cursor))
|
||||
printf(" (static)");
|
||||
if (clang_CXXMethod_isVirtual(Cursor))
|
||||
|
|
|
@ -5489,6 +5489,90 @@ enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
|
|||
return CXAvailability_Available;
|
||||
}
|
||||
|
||||
static CXVersion convertVersion(VersionTuple In) {
|
||||
CXVersion Out = { -1, -1, -1 };
|
||||
if (In.empty())
|
||||
return Out;
|
||||
|
||||
Out.Major = In.getMajor();
|
||||
|
||||
if (llvm::Optional<unsigned> Minor = In.getMinor())
|
||||
Out.Minor = *Minor;
|
||||
else
|
||||
return Out;
|
||||
|
||||
if (llvm::Optional<unsigned> Subminor = In.getSubminor())
|
||||
Out.Subminor = *Subminor;
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
int clang_getCursorPlatformAvailability(CXCursor cursor,
|
||||
int *always_deprecated,
|
||||
CXString *deprecated_message,
|
||||
int *always_unavailable,
|
||||
CXString *unavailable_message,
|
||||
CXPlatformAvailability *availability,
|
||||
int availability_size) {
|
||||
if (always_deprecated)
|
||||
*always_deprecated = 0;
|
||||
if (deprecated_message)
|
||||
*deprecated_message = cxstring::createCXString("", /*DupString=*/false);
|
||||
if (always_unavailable)
|
||||
*always_unavailable = 0;
|
||||
if (unavailable_message)
|
||||
*unavailable_message = cxstring::createCXString("", /*DupString=*/false);
|
||||
|
||||
if (!clang_isDeclaration(cursor.kind))
|
||||
return 0;
|
||||
|
||||
Decl *D = cxcursor::getCursorDecl(cursor);
|
||||
if (!D)
|
||||
return 0;
|
||||
|
||||
int N = 0;
|
||||
for (Decl::attr_iterator A = D->attr_begin(), AEnd = D->attr_end(); A != AEnd;
|
||||
++A) {
|
||||
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
|
||||
if (always_deprecated)
|
||||
*always_deprecated = 1;
|
||||
if (deprecated_message)
|
||||
*deprecated_message = cxstring::createCXString(Deprecated->getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
|
||||
if (always_unavailable)
|
||||
*always_unavailable = 1;
|
||||
if (unavailable_message) {
|
||||
*unavailable_message
|
||||
= cxstring::createCXString(Unavailable->getMessage());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) {
|
||||
if (N < availability_size) {
|
||||
availability[N].Platform
|
||||
= cxstring::createCXString(Avail->getPlatform()->getName());
|
||||
availability[N].Introduced = convertVersion(Avail->getIntroduced());
|
||||
availability[N].Deprecated = convertVersion(Avail->getDeprecated());
|
||||
availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
|
||||
availability[N].Unavailable = Avail->getUnavailable();
|
||||
availability[N].Message = cxstring::createCXString(Avail->getMessage());
|
||||
}
|
||||
++N;
|
||||
}
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
|
||||
clang_disposeString(availability->Platform);
|
||||
clang_disposeString(availability->Message);
|
||||
}
|
||||
|
||||
CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
|
||||
if (clang_isDeclaration(cursor.kind))
|
||||
return getDeclLanguage(cxcursor::getCursorDecl(cursor));
|
||||
|
|
|
@ -43,6 +43,7 @@ clang_disposeDiagnostic
|
|||
clang_disposeDiagnosticSet
|
||||
clang_disposeIndex
|
||||
clang_disposeOverriddenCursors
|
||||
clang_disposeCXPlatformAvailability
|
||||
clang_disposeString
|
||||
clang_disposeTokens
|
||||
clang_disposeTranslationUnit
|
||||
|
@ -85,6 +86,7 @@ clang_getCursorLanguage
|
|||
clang_getCursorLexicalParent
|
||||
clang_getCursorLinkage
|
||||
clang_getCursorLocation
|
||||
clang_getCursorPlatformAvailability
|
||||
clang_getCursorReferenceNameRange
|
||||
clang_getCursorReferenced
|
||||
clang_getCursorResultType
|
||||
|
|
Loading…
Reference in New Issue