Introduce new libclang API functions that determine the availability

of a cursor or code-completion result, e.g., whether that result
refers to an unavailable, deleted, or deprecated declaration.

llvm-svn: 111858
This commit is contained in:
Douglas Gregor 2010-08-23 23:00:57 +00:00
parent 616d3e71c2
commit f757a12dfc
12 changed files with 147 additions and 25 deletions

View File

@ -97,6 +97,19 @@ struct CXUnsavedFile {
unsigned long Length;
};
/// \brief Describes the availability of a particular entity, which indicates
/// whether the use of this entity will result in a warning or error due to
/// it being deprecated or unavailable.
enum CXAvailabilityKind {
/// \brief The entity is available.
CXAvailability_Available,
/// \brief The entity is available, but has been deprecated (and its use is
/// not recommended).
CXAvailability_Deprecated,
/// \brief The entity is not available; any use of it will be an error.
CXAvailability_NotAvailable
};
/**
* \defgroup CINDEX_STRING String manipulation routines
*
@ -1198,6 +1211,16 @@ enum CXLinkageKind {
*/
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
/**
* \brief Determine the availability of the entity that this cursor refers to.
*
* \param cursor The cursor to query.
*
* \returns The availability of the cursor.
*/
CINDEX_LINKAGE enum CXAvailabilityKind
clang_getCursorAvailability(CXCursor cursor);
/**
* \brief Describe the "language" of the entity referred to by a cursor.
*/
@ -2072,6 +2095,17 @@ clang_getNumCompletionChunks(CXCompletionString completion_string);
CINDEX_LINKAGE unsigned
clang_getCompletionPriority(CXCompletionString completion_string);
/**
* \brief Determine the availability of the entity that this code-completion
* string refers to.
*
* \param completion_string The completion string to query.
*
* \returns The availability of the completion string.
*/
CINDEX_LINKAGE enum CXAvailabilityKind
clang_getCompletionAvailability(CXCompletionString completion_string);
/**
* \brief Contains the results of code-completion.
*
@ -2294,7 +2328,7 @@ CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
*/
CINDEX_LINKAGE
void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results);
/**
* \brief Determine the number of diagnostics produced prior to the
* location where code completion was performed.

View File

@ -239,6 +239,9 @@ public:
/// result.
CXCursorKind Kind;
/// \brief The availability of this code-completion result.
CXAvailabilityKind Availability;
/// \brief The simplified type class for a non-macro completion result.
SimplifiedTypeClass TypeClass;

View File

@ -476,6 +476,9 @@ public:
/// \brief The cursor kind that describes this result.
CXCursorKind CursorKind;
/// \brief The availability of this result.
CXAvailabilityKind Availability;
/// \brief Specifies which parameter (of a function, Objective-C method,
/// macro, etc.) we should start with when formatting the result.
unsigned StartParameter;
@ -508,39 +511,43 @@ public:
NestedNameSpecifier *Qualifier = 0,
bool QualifierIsInformative = false)
: Kind(RK_Declaration), Declaration(Declaration),
Priority(getPriorityFromDecl(Declaration)), StartParameter(0),
Priority(getPriorityFromDecl(Declaration)),
Availability(CXAvailability_Available), StartParameter(0),
Hidden(false), QualifierIsInformative(QualifierIsInformative),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(Qualifier) {
computeCursorKind();
computeCursorKindAndAvailability();
}
/// \brief Build a result that refers to a keyword or symbol.
Result(const char *Keyword, unsigned Priority = CCP_Keyword)
: Kind(RK_Keyword), Keyword(Keyword), Priority(Priority),
Availability(CXAvailability_Available),
StartParameter(0), Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(0) {
computeCursorKind();
computeCursorKindAndAvailability();
}
/// \brief Build a result that refers to a macro.
Result(IdentifierInfo *Macro, unsigned Priority = CCP_Macro)
: Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0),
: Kind(RK_Macro), Macro(Macro), Priority(Priority),
Availability(CXAvailability_Available), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(0) {
computeCursorKind();
computeCursorKindAndAvailability();
}
/// \brief Build a result that refers to a pattern.
Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern,
CXCursorKind CursorKind = CXCursor_NotImplemented)
CXCursorKind CursorKind = CXCursor_NotImplemented,
CXAvailabilityKind Availability = CXAvailability_Available)
: Kind(RK_Pattern), Pattern(Pattern), Priority(Priority),
CursorKind(CursorKind), StartParameter(0), Hidden(false),
QualifierIsInformative(0), StartsNestedNameSpecifier(false),
AllParametersAreInformative(false), DeclaringEntity(false),
Qualifier(0)
CursorKind(CursorKind), Availability(Availability), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(0)
{
}
@ -573,7 +580,7 @@ public:
static unsigned getPriorityFromDecl(NamedDecl *ND);
private:
void computeCursorKind();
void computeCursorKindAndAvailability();
};
class OverloadCandidate {

View File

@ -194,6 +194,7 @@ void ASTUnit::CacheCodeCompletionResults() {
IsNestedNameSpecifier);
CachedResult.Priority = Results[I].Priority;
CachedResult.Kind = Results[I].CursorKind;
CachedResult.Availability = Results[I].Availability;
// Keep track of the type of this completion in an ASTContext-agnostic
// way.
@ -280,6 +281,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedResult.Priority = Results[I].Priority;
CachedResult.Kind = Results[I].CursorKind;
CachedResult.Availability = Results[I].Availability;
CachedResult.TypeClass = STC_Void;
CachedResult.Type = 0;
CachedCompletionResults.push_back(CachedResult);
@ -1644,7 +1646,8 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
}
}
AllResults.push_back(Result(C->Completion, Priority, C->Kind));
AllResults.push_back(Result(C->Completion, Priority, C->Kind,
C->Availability));
}
// If we did not add any cached completion results, just forward the

View File

@ -496,9 +496,16 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
}
}
void CodeCompleteConsumer::Result::computeCursorKind() {
void CodeCompleteConsumer::Result::computeCursorKindAndAvailability() {
switch (Kind) {
case RK_Declaration:
// Set the availability based on attributes.
Availability = CXAvailability_Available;
if (Declaration->getAttr<UnavailableAttr>())
Availability = CXAvailability_NotAvailable;
else if (Declaration->getAttr<DeprecatedAttr>())
Availability = CXAvailability_Deprecated;
switch (Declaration->getKind()) {
case Decl::Record:
case Decl::CXXRecord:
@ -544,6 +551,8 @@ void CodeCompleteConsumer::Result::computeCursorKind() {
case Decl::CXXDestructor:
case Decl::CXXConversion:
CursorKind = CXCursor_FunctionDecl;
if (cast<FunctionDecl>(Declaration)->isDeleted())
Availability = CXAvailability_NotAvailable;
break;
case Decl::Var:
@ -589,10 +598,12 @@ void CodeCompleteConsumer::Result::computeCursorKind() {
break;
case Result::RK_Macro:
Availability = CXAvailability_Available;
CursorKind = CXCursor_MacroDefinition;
break;
case Result::RK_Keyword:
Availability = CXAvailability_Available;
CursorKind = CXCursor_NotImplemented;
break;
@ -611,6 +622,7 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
for (unsigned I = 0; I != NumResults; ++I) {
WriteUnsigned(OS, Results[I].CursorKind);
WriteUnsigned(OS, Results[I].Priority);
WriteUnsigned(OS, Results[I].Availability);
CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
assert(CCS && "No code-completion string?");
CCS->Serialize(OS);
@ -626,6 +638,7 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
for (unsigned I = 0; I != NumCandidates; ++I) {
WriteUnsigned(OS, CXCursor_NotImplemented);
WriteUnsigned(OS, /*Priority=*/0);
WriteUnsigned(OS, /*Availability=*/CXAvailability_Available);
CodeCompletionString *CCS
= Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
assert(CCS && "No code-completion string?");

View File

@ -6,7 +6,7 @@
__attribute__((iboutlet)) id myoutlet;
}
- (void) __attribute__((ibaction)) myMessage:(id)msg;
- foo;
- foo __attribute__((deprecated));
+ fooC;
@end
@ -78,7 +78,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:1: ObjCInstanceMethodDecl=foo:9:1 Extent=[9:1 - 9:7]
// CHECK: c-index-api-loadTU-test.m:9:1: ObjCInstanceMethodDecl=foo:9:1 (deprecated) Extent=[9:1 - 9:35]
// CHECK: c-index-api-loadTU-test.m:10:1: ObjCClassMethodDecl=fooC:10:1 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]

View File

@ -1,13 +1,13 @@
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
int f(int);
int f(int) __attribute__((unavailable));
int test(int i, int j, int k, int l) {
return i | j | k & l;
}
struct X f1 = { 17 };
struct X __attribute__((deprecated)) f1 = { 17 };
void f2() { f1(17); }
const char *str = "Hello, \nWorld";
@ -16,7 +16,7 @@ const char *str = "Hello, \nWorld";
// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: NotImplemented:{TypedText __PRETTY_FUNCTION__} (60)
// CHECK-CC1: macro definition:{TypedText __VERSION__} (70)
// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12)
// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12) (unavailable)
// CHECK-CC1-NOT: NotImplemented:{TypedText float} (40)
// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (2)
// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
@ -44,7 +44,7 @@ const char *str = "Hello, \nWorld";
// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
// RUN: c-index-test -code-completion-at=%s:11:16 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
// CHECK-CC4: VarDecl:{ResultType struct X}{TypedText f1} (50)
// CHECK-CC4: VarDecl:{ResultType struct X}{TypedText f1} (50) (deprecated)
// RUN: c-index-test -code-completion-at=%s:13:28 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: NotImplemented:{TypedText void} (40)

View File

@ -182,6 +182,19 @@ static void PrintCursor(CXCursor Cursor) {
if (clang_isCursorDefinition(Cursor))
printf(" (Definition)");
switch (clang_getCursorAvailability(Cursor)) {
case CXAvailability_Available:
break;
case CXAvailability_Deprecated:
printf(" (deprecated)");
break;
case CXAvailability_NotAvailable:
printf(" (unavailable)");
break;
}
}
}
@ -865,8 +878,21 @@ void print_completion_result(CXCompletionResult *completion_result,
clang_disposeString(ks);
print_completion_string(completion_result->CompletionString, file);
fprintf(file, " (%u)\n",
fprintf(file, " (%u)",
clang_getCompletionPriority(completion_result->CompletionString));
switch (clang_getCompletionAvailability(completion_result->CompletionString)){
case CXAvailability_Available:
break;
case CXAvailability_Deprecated:
fprintf(file, " (deprecated)");
break;
case CXAvailability_NotAvailable:
fprintf(file, " (unavailable)");
break;
}
fprintf(file, "\n");
}
int perform_code_completion(int argc, const char **argv, int timing_only) {

View File

@ -3018,6 +3018,21 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
}
extern "C" {
enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind))
if (Decl *D = cxcursor::getCursorDecl(cursor)) {
if (D->hasAttr<UnavailableAttr>() ||
(isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted()))
return CXAvailability_Available;
if (D->hasAttr<DeprecatedAttr>())
return CXAvailability_Deprecated;
}
return CXAvailability_Available;
}
CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind))
return getDeclLanguage(cxcursor::getCursorDecl(cursor));

View File

@ -48,11 +48,15 @@ namespace {
/// This is the representation behind a CXCompletionString.
class CXStoredCodeCompletionString : public CodeCompletionString {
unsigned Priority;
CXAvailabilityKind Availability;
public:
CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { }
CXStoredCodeCompletionString(unsigned Priority,
CXAvailabilityKind Availability)
: Priority(Priority), Availability(Availability) { }
unsigned getPriority() const { return Priority; }
CXAvailabilityKind getAvailability() const { return Availability; }
};
}
@ -210,6 +214,13 @@ unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely);
}
enum CXAvailabilityKind
clang_getCompletionAvailability(CXCompletionString completion_string) {
CXStoredCodeCompletionString *CCStr
= (CXStoredCodeCompletionString *)completion_string;
return CCStr? CCStr->getAvailability() : CXAvailability_Available;
}
static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
unsigned &Value) {
if (Memory + sizeof(unsigned) > MemoryEnd)
@ -433,8 +444,13 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
if (ReadUnsigned(Str, StrEnd, Priority))
break;
unsigned Availability;
if (ReadUnsigned(Str, StrEnd, Availability))
break;
CXStoredCodeCompletionString *CCStr
= new CXStoredCodeCompletionString(Priority);
= new CXStoredCodeCompletionString(Priority,
(CXAvailabilityKind)Availability);
if (!CCStr->Deserialize(Str, StrEnd)) {
delete CCStr;
continue;
@ -559,7 +575,8 @@ namespace {
AllocatedResults.NumResults = NumResults;
for (unsigned I = 0; I != NumResults; ++I) {
CXStoredCodeCompletionString *StoredCompletion
= new CXStoredCodeCompletionString(Results[I].Priority);
= new CXStoredCodeCompletionString(Results[I].Priority,
Results[I].Availability);
(void)Results[I].CreateCodeCompletionString(S, StoredCompletion);
AllocatedResults.Results[I].CursorKind = Results[I].CursorKind;
AllocatedResults.Results[I].CompletionString = StoredCompletion;
@ -743,7 +760,7 @@ void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
= static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
delete Results;
}
unsigned
clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
AllocatedCXCodeCompleteResults *Results

View File

@ -32,11 +32,13 @@ _clang_formatDiagnostic
_clang_getCString
_clang_getCanonicalType
_clang_getClangVersion
_clang_getCompletionAvailability
_clang_getCompletionChunkCompletionString
_clang_getCompletionChunkKind
_clang_getCompletionChunkText
_clang_getCompletionPriority
_clang_getCursor
_clang_getCursorAvailability
_clang_getCursorDefinition
_clang_getCursorExtent
_clang_getCursorKind

View File

@ -32,11 +32,13 @@ clang_formatDiagnostic
clang_getCString
clang_getCanonicalType
clang_getClangVersion
clang_getCompletionAvailability
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
clang_getCompletionPriority
clang_getCursor
clang_getCursorAvailability
clang_getCursorDefinition
clang_getCursorExtent
clang_getCursorKind