[libclang] Merge multiple availability clauses when getting the platform's

availability

Patch by Ronald Wampler!

Differential Revision: https://reviews.llvm.org/D33478

llvm-svn: 305117
This commit is contained in:
Alex Lorenz 2017-06-09 21:29:45 +00:00
parent 86a3ef5b03
commit 2e34be23a2
2 changed files with 92 additions and 46 deletions

View File

@ -8,13 +8,15 @@ enum {
enum {
old_enum_plat
} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7)
} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7)));
// RUN: c-index-test -test-load-source all %s > %t
// RUN: FileCheck -check-prefix=CHECK-1 %s < %t
// RUN: FileCheck -check-prefix=CHECK-2 %s < %t
// CHECK-1: (ios, introduced=3.2, deprecated=4.1)
// CHECK-2: (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
void bar(void) __attribute__((availability(macosx,introduced=10.4))) __attribute__((availability(macosx,obsoleted=10.6))) __attribute__((availability(ios,introduced=3.2))) __attribute__((availability(macosx,deprecated=10.5,message="use foobar")));
// CHECK-2: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
// CHECK-2: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
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)));
// 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)

View File

@ -7216,15 +7216,11 @@ static CXVersion convertVersion(VersionTuple In) {
return Out;
}
static int getCursorPlatformAvailabilityForDecl(const Decl *D,
int *always_deprecated,
CXString *deprecated_message,
int *always_unavailable,
CXString *unavailable_message,
CXPlatformAvailability *availability,
int availability_size) {
static void getCursorPlatformAvailabilityForDecl(
const Decl *D, int *always_deprecated, CXString *deprecated_message,
int *always_unavailable, CXString *unavailable_message,
SmallVectorImpl<AvailabilityAttr *> &AvailabilityAttrs) {
bool HadAvailAttr = false;
int N = 0;
for (auto A : D->attrs()) {
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(A)) {
HadAvailAttr = true;
@ -7249,36 +7245,69 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(A)) {
AvailabilityAttrs.push_back(Avail);
HadAvailAttr = true;
if (N < availability_size) {
availability[N].Platform
= cxstring::createDup(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::createDup(Avail->getMessage());
}
++N;
}
}
if (!HadAvailAttr)
if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
return getCursorPlatformAvailabilityForDecl(
cast<Decl>(EnumConst->getDeclContext()),
always_deprecated,
deprecated_message,
always_unavailable,
unavailable_message,
availability,
availability_size);
cast<Decl>(EnumConst->getDeclContext()), always_deprecated,
deprecated_message, always_unavailable, unavailable_message,
AvailabilityAttrs);
return N;
if (AvailabilityAttrs.empty())
return;
std::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
[](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
return LHS->getPlatform() > RHS->getPlatform();
});
ASTContext &Ctx = D->getASTContext();
auto It = std::unique(
AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
[&Ctx](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
if (LHS->getPlatform() != RHS->getPlatform())
return false;
if (LHS->getIntroduced() == RHS->getIntroduced() &&
LHS->getDeprecated() == RHS->getDeprecated() &&
LHS->getObsoleted() == RHS->getObsoleted() &&
LHS->getMessage() == RHS->getMessage() &&
LHS->getReplacement() == RHS->getReplacement())
return true;
if ((!LHS->getIntroduced().empty() && !RHS->getIntroduced().empty()) ||
(!LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) ||
(!LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()))
return false;
if (LHS->getIntroduced().empty() && !RHS->getIntroduced().empty())
LHS->setIntroduced(Ctx, RHS->getIntroduced());
if (LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) {
LHS->setDeprecated(Ctx, RHS->getDeprecated());
if (LHS->getMessage().empty())
LHS->setMessage(Ctx, RHS->getMessage());
if (LHS->getReplacement().empty())
LHS->setReplacement(Ctx, RHS->getReplacement());
}
if (LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()) {
LHS->setObsoleted(Ctx, RHS->getObsoleted());
if (LHS->getMessage().empty())
LHS->setMessage(Ctx, RHS->getMessage());
if (LHS->getReplacement().empty())
LHS->setReplacement(Ctx, RHS->getReplacement());
}
return true;
});
AvailabilityAttrs.erase(It, AvailabilityAttrs.end());
}
int clang_getCursorPlatformAvailability(CXCursor cursor,
int *always_deprecated,
int clang_getCursorPlatformAvailability(CXCursor cursor, int *always_deprecated,
CXString *deprecated_message,
int *always_unavailable,
CXString *unavailable_message,
@ -7300,12 +7329,27 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (!D)
return 0;
return getCursorPlatformAvailabilityForDecl(D, always_deprecated,
deprecated_message,
always_unavailable,
unavailable_message,
availability,
availability_size);
SmallVector<AvailabilityAttr *, 8> AvailabilityAttrs;
getCursorPlatformAvailabilityForDecl(D, always_deprecated, deprecated_message,
always_unavailable, unavailable_message,
AvailabilityAttrs);
for (const auto &Avail :
llvm::enumerate(llvm::makeArrayRef(AvailabilityAttrs)
.take_front(availability_size))) {
availability[Avail.index()].Platform =
cxstring::createDup(Avail.value()->getPlatform()->getName());
availability[Avail.index()].Introduced =
convertVersion(Avail.value()->getIntroduced());
availability[Avail.index()].Deprecated =
convertVersion(Avail.value()->getDeprecated());
availability[Avail.index()].Obsoleted =
convertVersion(Avail.value()->getObsoleted());
availability[Avail.index()].Unavailable = Avail.value()->getUnavailable();
availability[Avail.index()].Message =
cxstring::createDup(Avail.value()->getMessage());
}
return AvailabilityAttrs.size();
}
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {