Introduce a new libclang API to determine the parent context of a code

completion item. For example, if the code completion itself represents
a declaration in a namespace (say, std::vector), then this API
retrieves the cursor kind and name of the namespace (std). Implements
<rdar://problem/11121951>.

llvm-svn: 153545
This commit is contained in:
Douglas Gregor 2012-03-27 23:34:16 +00:00
parent 43f340f440
commit 78254c8880
12 changed files with 250 additions and 77 deletions

View File

@ -3542,6 +3542,26 @@ CINDEX_LINKAGE CXString
clang_getCompletionAnnotation(CXCompletionString completion_string,
unsigned annotation_number);
/**
* \brief Retrieve the parent context of the given completion string.
*
* The parent context of a completion string is the semantic parent of
* the declaration (if any) that the code completion represents. For example,
* a code completion for an Objective-C method would have the method's class
* or protocol as its context.
*
* \param completion_string The code completion string whose parent is
* being queried.
*
* \param kind If non-NULL, will be set to the kind of the parent context,
* or CXCursor_NotImplemented if there is no context.
*
* \param Returns the name of the completion parent, e.g., "NSObject" if
* the completion string represents a method in the NSObject class.
*/
CINDEX_LINKAGE CXString
clang_getCompletionParent(CXCompletionString completion_string,
enum CXCursorKind *kind);
/**
* \brief Retrieve a completion string for an arbitrary declaration or macro
* definition cursor.

View File

@ -434,17 +434,24 @@ private:
unsigned NumAnnotations : 16;
/// \brief The priority of this code-completion string.
unsigned Priority : 30;
unsigned Priority : 16;
/// \brief The availability of this code-completion result.
unsigned Availability : 2;
/// \brief The kind of the parent context.
unsigned ParentKind : 14;
/// \brief The name of the parent context.
StringRef ParentName;
CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
CodeCompletionString(const Chunk *Chunks, unsigned NumChunks,
unsigned Priority, CXAvailabilityKind Availability,
const char **Annotations, unsigned NumAnnotations);
const char **Annotations, unsigned NumAnnotations,
CXCursorKind ParentKind, StringRef ParentName);
~CodeCompletionString() { }
friend class CodeCompletionBuilder;
@ -477,6 +484,16 @@ public:
/// \brief Retrieve the annotation string specified by \c AnnotationNr.
const char *getAnnotation(unsigned AnnotationNr) const;
/// \brief Retrieve parent context's cursor kind.
CXCursorKind getParentContextKind() const {
return (CXCursorKind)ParentKind;
}
/// \brief Retrieve the name of the parent context.
StringRef getParentContextName() const {
return ParentName;
}
/// \brief Retrieve a string representation of the code completion string,
/// which is mainly useful for debugging.
std::string getAsString() const;
@ -484,6 +501,8 @@ public:
/// \brief An allocator used specifically for the purpose of code completion.
class CodeCompletionAllocator : public llvm::BumpPtrAllocator {
llvm::DenseMap<DeclContext *, StringRef> ParentNames;
public:
/// \brief Copy the given string into this allocator.
const char *CopyString(StringRef String);
@ -500,6 +519,12 @@ public:
const char *CopyString(const std::string &String) {
return CopyString(StringRef(String));
}
/// \brief Retrieve the mapping from known parent declaration contexts to
/// the (already copied) strings associated with each context.
llvm::DenseMap<DeclContext *, StringRef> &getParentNames() {
return ParentNames;
}
};
} // end namespace clang
@ -521,7 +546,9 @@ private:
CodeCompletionAllocator &Allocator;
unsigned Priority;
CXAvailabilityKind Availability;
CXCursorKind ParentKind;
StringRef ParentName;
/// \brief The chunks stored in this string.
SmallVector<Chunk, 4> Chunks;
@ -529,12 +556,13 @@ private:
public:
CodeCompletionBuilder(CodeCompletionAllocator &Allocator)
: Allocator(Allocator), Priority(0), Availability(CXAvailability_Available){
}
: Allocator(Allocator), Priority(0), Availability(CXAvailability_Available),
ParentKind(CXCursor_NotImplemented) { }
CodeCompletionBuilder(CodeCompletionAllocator &Allocator,
unsigned Priority, CXAvailabilityKind Availability)
: Allocator(Allocator), Priority(Priority), Availability(Availability) { }
: Allocator(Allocator), Priority(Priority), Availability(Availability),
ParentKind(CXCursor_NotImplemented) { }
/// \brief Retrieve the allocator into which the code completion
/// strings should be allocated.
@ -570,6 +598,12 @@ public:
void AddChunk(CodeCompletionString::ChunkKind CK, const char *Text = "");
void AddAnnotation(const char *A) { Annotations.push_back(A); }
/// \brief Add the parent context information to this code completion.
void addParentContext(DeclContext *DC);
CXCursorKind getParentKind() const { return ParentKind; }
StringRef getParentName() const { return ParentName; }
};
/// \brief Captures a result of code completion.
@ -586,11 +620,11 @@ public:
/// \brief The kind of result stored here.
ResultKind Kind;
union {
/// \brief When Kind == RK_Declaration, the declaration we are referring
/// to.
NamedDecl *Declaration;
/// \brief When Kind == RK_Declaration or RK_Pattern, the declaration we are
/// referring to. In the latter case, the declaration might be NULL.
NamedDecl *Declaration;
union {
/// \brief When Kind == RK_Keyword, the string representing the keyword
/// or symbol's spelling.
const char *Keyword;
@ -655,7 +689,7 @@ public:
/// \brief Build a result that refers to a keyword or symbol.
CodeCompletionResult(const char *Keyword, unsigned Priority = CCP_Keyword)
: Kind(RK_Keyword), Keyword(Keyword), Priority(Priority),
: Kind(RK_Keyword), Declaration(0), Keyword(Keyword), Priority(Priority),
Availability(CXAvailability_Available),
StartParameter(0), Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
@ -665,7 +699,7 @@ public:
/// \brief Build a result that refers to a macro.
CodeCompletionResult(IdentifierInfo *Macro, unsigned Priority = CCP_Macro)
: Kind(RK_Macro), Macro(Macro), Priority(Priority),
: Kind(RK_Macro), Declaration(0), Macro(Macro), Priority(Priority),
Availability(CXAvailability_Available), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
@ -677,8 +711,9 @@ public:
CodeCompletionResult(CodeCompletionString *Pattern,
unsigned Priority = CCP_CodePattern,
CXCursorKind CursorKind = CXCursor_NotImplemented,
CXAvailabilityKind Availability = CXAvailability_Available)
: Kind(RK_Pattern), Pattern(Pattern), Priority(Priority),
CXAvailabilityKind Availability = CXAvailability_Available,
NamedDecl *D = 0)
: Kind(RK_Pattern), Declaration(D), Pattern(Pattern), Priority(Priority),
CursorKind(CursorKind), Availability(Availability), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
@ -686,6 +721,18 @@ public:
{
}
/// \brief Build a result that refers to a pattern with an associated
/// declaration.
CodeCompletionResult(CodeCompletionString *Pattern, NamedDecl *D,
unsigned Priority)
: Kind(RK_Pattern), Declaration(D), Pattern(Pattern), Priority(Priority),
Availability(CXAvailability_Available), StartParameter(0),
Hidden(false), QualifierIsInformative(false),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(0) {
computeCursorKindAndAvailability();
}
/// \brief Retrieve the declaration stored in this result.
NamedDecl *getDeclaration() const {
assert(Kind == RK_Declaration && "Not a declaration result");

View File

@ -845,7 +845,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
}
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOpts());
return getQualifiedNameAsString(getASTContext().getPrintingPolicy());
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {

View File

@ -192,9 +192,12 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks,
unsigned Priority,
CXAvailabilityKind Availability,
const char **Annotations,
unsigned NumAnnotations)
: NumChunks(NumChunks), NumAnnotations(NumAnnotations)
, Priority(Priority), Availability(Availability)
unsigned NumAnnotations,
CXCursorKind ParentKind,
StringRef ParentName)
: NumChunks(NumChunks), NumAnnotations(NumAnnotations),
Priority(Priority), Availability(Availability), ParentKind(ParentKind),
ParentName(ParentName)
{
assert(NumChunks <= 0xffff);
assert(NumAnnotations <= 0xffff);
@ -272,7 +275,8 @@ CodeCompletionString *CodeCompletionBuilder::TakeString() {
CodeCompletionString *Result
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
Priority, Availability,
Annotations.data(), Annotations.size());
Annotations.data(), Annotations.size(),
ParentKind, ParentName);
Chunks.clear();
return Result;
}
@ -311,6 +315,70 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
Chunks.push_back(Chunk(CK, Text));
}
void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (DC->isTranslationUnit()) {
ParentKind = CXCursor_TranslationUnit;
return;
}
if (DC->isFunctionOrMethod())
return;
NamedDecl *ND = dyn_cast<NamedDecl>(DC);
if (!ND)
return;
ParentKind = getCursorKindForDecl(ND);
// Check whether we've already cached the parent name.
StringRef &CachedParentName = Allocator.getParentNames()[DC];
if (!CachedParentName.empty()) {
ParentName = CachedParentName;
return;
}
// Find the interesting names.
llvm::SmallVector<DeclContext *, 2> Contexts;
while (DC && !DC->isFunctionOrMethod()) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
if (ND->getIdentifier())
Contexts.push_back(DC);
}
DC = DC->getParent();
}
{
llvm::SmallString<128> S;
llvm::raw_svector_ostream OS(S);
bool First = true;
for (unsigned I = Contexts.size(); I != 0; --I) {
if (First)
First = false;
else {
OS << "::";
}
DeclContext *CurDC = Contexts[I-1];
if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
CurDC = CatImpl->getCategoryDecl();
if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
ObjCInterfaceDecl *Interface = Cat->getClassInterface();
if (!Interface)
return;
OS << Interface->getName() << '(' << Cat->getName() << ')';
} else {
OS << cast<NamedDecl>(CurDC)->getName();
}
}
ParentName = Allocator.CopyString(OS.str());
CachedParentName = ParentName;
}
}
unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) {
if (!ND)
return CCP_Unlikely;
@ -444,6 +512,13 @@ static AvailabilityResult getDeclAvailability(Decl *D) {
void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
switch (Kind) {
case RK_Pattern:
if (!Declaration) {
// Do nothing: Patterns can come with cursor kinds!
break;
}
// Fall through
case RK_Declaration: {
// Set the availability based on attributes.
switch (getDeclAvailability(Declaration)) {
@ -488,11 +563,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
case RK_Keyword:
Availability = CXAvailability_Available;
CursorKind = CXCursor_NotImplemented;
break;
case RK_Pattern:
// Do nothing: Patterns can come with cursor kinds!
break;
break;
}
if (!Accessible)

View File

@ -2454,6 +2454,13 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
if (Kind == RK_Pattern) {
Pattern->Priority = Priority;
Pattern->Availability = Availability;
if (Declaration) {
Result.addParentContext(Declaration->getDeclContext());
Pattern->ParentKind = Result.getParentKind();
Pattern->ParentName = Result.getParentName();
}
return Pattern;
}
@ -2509,7 +2516,8 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
assert(Kind == RK_Declaration && "Missed a result kind?");
NamedDecl *ND = Declaration;
Result.addParentContext(ND->getDeclContext());
if (StartsNestedNameSpecifier) {
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(ND->getNameAsString()));
@ -3023,7 +3031,9 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(CodeCompletionResult(Builder.TakeString(),
CCP_SuperCompletion,
CXCursor_CXXMethod));
CXCursor_CXXMethod,
CXAvailability_Available,
Overridden));
Results.Ignore(Overridden);
}
}
@ -3342,28 +3352,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(Name->getName()));
CXAvailabilityKind Availability = CXAvailability_Available;
switch (M->getAvailability()) {
case AR_Available:
case AR_NotYetIntroduced:
Availability = CXAvailability_Available;
break;
case AR_Deprecated:
Availability = CXAvailability_Deprecated;
break;
case AR_Unavailable:
Availability = CXAvailability_NotAvailable;
break;
}
Results.MaybeAddResult(Result(Builder.TakeString(),
CCP_MemberDeclaration + CCD_MethodAsProperty,
M->isInstanceMethod()
? CXCursor_ObjCInstanceMethodDecl
: CXCursor_ObjCClassMethodDecl,
Availability),
Results.MaybeAddResult(Result(Builder.TakeString(), *M,
CCP_MemberDeclaration + CCD_MethodAsProperty),
CurContext);
}
}
@ -4028,7 +4018,8 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
// namespace to the list of results.
Results.EnterNewScope();
for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
NS = OrigToLatest.begin(),
NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
Results.AddResult(CodeCompletionResult(NS->second, 0),
CurContext, 0, false);
@ -4188,7 +4179,9 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Results.AddResult(CodeCompletionResult(Builder.TakeString(),
SawLastInitializer? CCP_NextInitializer
: CCP_MemberDeclaration,
CXCursor_MemberRef));
CXCursor_MemberRef,
CXAvailability_Available,
*Field));
SawLastInitializer = false;
}
Results.ExitScope();
@ -5057,10 +5050,8 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
}
}
Results.AddResult(CodeCompletionResult(Builder.TakeString(), CCP_SuperCompletion,
SuperMethod->isInstanceMethod()
? CXCursor_ObjCInstanceMethodDecl
: CXCursor_ObjCClassMethodDecl));
Results.AddResult(CodeCompletionResult(Builder.TakeString(), SuperMethod,
CCP_SuperCompletion));
return SuperMethod;
}
@ -6747,10 +6738,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
if (!M->second.second)
Priority += CCD_InBaseClass;
Results.AddResult(Result(Builder.TakeString(), Priority,
Method->isInstanceMethod()
? CXCursor_ObjCInstanceMethodDecl
: CXCursor_ObjCClassMethodDecl));
Results.AddResult(Result(Builder.TakeString(), Method, Priority));
}
// Add Key-Value-Coding and Key-Value-Observing accessor methods for all of

View File

@ -34,6 +34,17 @@ void X::f() const {
}
namespace N {
int x;
class C {
int member;
int f(int param) {
return member;
}
};
}
// RUN: c-index-test -code-completion-at=%s:20:2 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:20:2 -std=c++0x %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText alignof}{LeftParen (}{Placeholder type}{RightParen )} (40)
@ -65,3 +76,9 @@ void X::f() const {
// RUN: c-index-test -code-completion-at=%s:34:1 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: NotImplemented:{ResultType const X *}{TypedText this} (40)
// RUN: c-index-test -code-completion-at=%s:43:14 %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: FieldDecl:{ResultType int}{TypedText member} (8) (parent: ClassDecl 'N::C')
// CHECK-CC5: ParmDecl:{ResultType int}{TypedText param} (8)
// CHECK-CC5: StructDecl:{TypedText X} (50) (parent: TranslationUnit '(null)')
// CHECK-CC5: VarDecl:{ResultType int}{TypedText x} (12) (parent: Namespace 'N')

View File

@ -69,11 +69,11 @@
@end
// RUN: c-index-test -code-completion-at=%s:17:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc}
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt}
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf}
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc} (40) (parent: ObjCProtocolDecl 'P1')
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt} (40) (parent: ObjCProtocolDecl 'P1')
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf} (40) (parent: ObjCProtocolDecl 'P1')
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x} (40) (parent: ObjCProtocolDecl 'P1')
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y} (40) (parent: ObjCProtocolDecl 'P1')
// RUN: c-index-test -code-completion-at=%s:17:7 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCInstanceMethodDecl:{TypedText abc}
// CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{TypedText getSelf}
@ -94,8 +94,8 @@
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText setValue}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:33:8 %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (42) (parent: ObjCProtocolDecl 'P1')
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (40) (parent: ObjCInterfaceDecl 'B')
// CHECK-CC5-NOT: {TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText setValue}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:37:7 %s | FileCheck -check-prefix=CHECK-CC6 %s

View File

@ -190,11 +190,11 @@ void test_DO(DO *d, A* a) {
}
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText categoryClassMethod}
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)}
// CHECK-CC1: {TypedText classMethod2}
// CHECK-CC1: {TypedText new}
// CHECK-CC1: {TypedText protocolClassMethod}
// CHECK-CC1: {TypedText categoryClassMethod} (35) (parent: ObjCCategoryDecl 'Foo(FooTestCategory)')
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)} (35) (parent: ObjCInterfaceDecl 'Foo')
// CHECK-CC1: {TypedText classMethod2} (35) (parent: ObjCInterfaceDecl 'Foo')
// CHECK-CC1: {TypedText new} (35) (parent: ObjCInterfaceDecl 'Foo')
// CHECK-CC1: {TypedText protocolClassMethod} (37) (parent: ObjCProtocolDecl 'FooTestProtocol')
// CHECK-CC1: Completion contexts:
// CHECK-CC1-NEXT: Objective-C class method
// CHECK-CC1-NEXT: Container Kind: ObjCInterfaceDecl
@ -309,7 +309,7 @@ void test_DO(DO *d, A* a) {
// RUN: c-index-test -code-completion-at=%s:170:16 %s | FileCheck -check-prefix=CHECK-CLASS-RESULT %s
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method3} (35)
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35)
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35) (parent: ObjCCategoryDecl 'A(Cat)')
// RUN: c-index-test -code-completion-at=%s:181:4 %s | FileCheck -check-prefix=CHECK-BLOCK-RECEIVER %s
// CHECK-BLOCK-RECEIVER: ObjCInterfaceDecl:{TypedText A} (50)

View File

@ -14,7 +14,7 @@ void foo()
Foo::
// RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CC1 %s
// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35)
// CHECK-CC1: ClassDecl:{TypedText Foo} (35)
// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )} (35)
// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35)
// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35) (parent: ClassDecl 'Foo')
// CHECK-CC1: ClassDecl:{TypedText Foo} (35) (parent: ClassDecl 'Foo')
// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )} (35) (parent: ClassDecl 'Foo')
// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35) (parent: ClassDecl 'Foo')

View File

@ -1082,7 +1082,9 @@ void print_completion_result(CXCompletionResult *completion_result,
FILE *file = (FILE *)client_data;
CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
unsigned annotationCount;
enum CXCursorKind ParentKind;
CXString ParentName;
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@ -1121,6 +1123,19 @@ void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, ")");
}
if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
ParentName = clang_getCompletionParent(completion_result->CompletionString,
&ParentKind);
if (ParentKind != CXCursor_NotImplemented) {
CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
fprintf(file, " (parent: %s '%s')",
clang_getCString(KindSpelling),
clang_getCString(ParentName));
clang_disposeString(KindSpelling);
}
clang_disposeString(ParentName);
}
fprintf(file, "\n");
}

View File

@ -213,7 +213,21 @@ CXString clang_getCompletionAnnotation(CXCompletionString completion_string,
: createCXString((const char *) 0);
}
CXString
clang_getCompletionParent(CXCompletionString completion_string,
CXCursorKind *kind) {
if (kind)
*kind = CXCursor_NotImplemented;
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr)
return createCXString((const char *)0);
if (kind)
*kind = CCStr->getParentContextKind();
return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
}
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {

View File

@ -65,6 +65,7 @@ clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
clang_getCompletionNumAnnotations
clang_getCompletionParent
clang_getCompletionPriority
clang_getCursor
clang_getCursorAvailability