diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index ff0d92a38c2f..9615a6de399f 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -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. diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index e323170b08ff..614807b61e2a 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -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; diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index aadc4592f27c..59d8a4fd0485 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -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 { diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 14ff75d5c6b8..8a15f92045e0 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -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 diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 29d97a24145e..cab853a5cb53 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -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()) + Availability = CXAvailability_NotAvailable; + else if (Declaration->getAttr()) + 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(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?"); diff --git a/clang/test/Index/c-index-api-loadTU-test.m b/clang/test/Index/c-index-api-loadTU-test.m index 4e5eed43697a..a86bf629ea77 100644 --- a/clang/test/Index/c-index-api-loadTU-test.m +++ b/clang/test/Index/c-index-api-loadTU-test.m @@ -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: :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] diff --git a/clang/test/Index/complete-exprs.c b/clang/test/Index/complete-exprs.c index d6ad8abdf9f8..1fbabab01bbb 100644 --- a/clang/test/Index/complete-exprs.c +++ b/clang/test/Index/complete-exprs.c @@ -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) diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 95dbd45d8bf8..330fa545f931 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -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) { diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index a98f064e6f90..e59bdde43d57 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -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() || + (isa(D) && cast(D)->isDeleted())) + return CXAvailability_Available; + + if (D->hasAttr()) + return CXAvailability_Deprecated; + } + + return CXAvailability_Available; +} + CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { if (clang_isDeclaration(cursor.kind)) return getDeclLanguage(cxcursor::getCursorDecl(cursor)); diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp index c2febf9b722d..e99927b5b968 100644 --- a/clang/tools/libclang/CIndexCodeCompletion.cpp +++ b/clang/tools/libclang/CIndexCodeCompletion.cpp @@ -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(ResultsIn); delete Results; } - + unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { AllocatedCXCodeCompleteResults *Results diff --git a/clang/tools/libclang/libclang.darwin.exports b/clang/tools/libclang/libclang.darwin.exports index 444d669e67b3..f2087b73f2bc 100644 --- a/clang/tools/libclang/libclang.darwin.exports +++ b/clang/tools/libclang/libclang.darwin.exports @@ -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 diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports index a1e114afd919..c1658f6032c3 100644 --- a/clang/tools/libclang/libclang.exports +++ b/clang/tools/libclang/libclang.exports @@ -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