Skip to content

Commit

Permalink
Recommit r305117: [libclang] Merge multiple availability clauses when
Browse files Browse the repository at this point in the history
getting the platform's availability

Patch by Ronald Wampler!

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

llvm-svn: 305221
  • Loading branch information
hyp committed Jun 12, 2017
1 parent cc0d13a commit 1345ea2
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 46 deletions.
18 changes: 10 additions & 8 deletions clang/test/Index/availability.c
Expand Up @@ -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)
120 changes: 82 additions & 38 deletions clang/tools/libclang/CIndex.cpp
Expand Up @@ -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;
Expand All @@ -7236,7 +7232,7 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
continue;
}

if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(A)) {
HadAvailAttr = true;
if (always_unavailable)
Expand All @@ -7247,38 +7243,71 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
continue;
}

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);

return N;
cast<Decl>(EnumConst->getDeclContext()), always_deprecated,
deprecated_message, always_unavailable, unavailable_message,
AvailabilityAttrs);

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,
Expand All @@ -7300,14 +7329,29 @@ 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) {
clang_disposeString(availability->Platform);
clang_disposeString(availability->Message);
Expand Down

0 comments on commit 1345ea2

Please sign in to comment.