Introduce a new libclang aPI function,

clang_codeCompleteGetContexts(), that provides the client with
information about the context in which code completion has occurred
and what kinds of entities make sense as completions at that
point. Patch by Connor Wakamo!

llvm-svn: 134615
This commit is contained in:
Douglas Gregor 2011-07-07 16:03:39 +00:00
parent cc4a55f6f2
commit 2132584d36
11 changed files with 541 additions and 41 deletions

View File

@ -2870,6 +2870,137 @@ enum CXCodeComplete_Flags {
CXCodeComplete_IncludeCodePatterns = 0x02
};
/**
* \brief Bits that represent the context under which completion is occurring.
*
* The enumerators in this enumeration may be bitwise-OR'd together if multiple
* contexts are occurring simultaneously.
*/
enum CXCompletionContext {
/**
* \brief The context for completions is unexposed, as only Clang results
* should be included. (This is equivalent to having no context bits set.)
*/
CXCompletionContext_Unexposed = 0,
/**
* \brief Completions for any possible type should be included in the results.
*/
CXCompletionContext_AnyType = 1 << 0,
/**
* \brief Completions for any possible value (variables, function calls, etc.)
* should be included in the results.
*/
CXCompletionContext_AnyValue = 1 << 1,
/**
* \brief Completions for values that resolve to an Objective-C object should
* be included in the results.
*/
CXCompletionContext_ObjCObjectValue = 1 << 2,
/**
* \brief Completions for values that resolve to an Objective-C selector
* should be included in the results.
*/
CXCompletionContext_ObjCSelectorValue = 1 << 3,
/**
* \brief Completions for values that resolve to a C++ class type should be
* included in the results.
*/
CXCompletionContext_CXXClassTypeValue = 1 << 4,
/**
* \brief Completions for fields of the member being accessed using the dot
* operator should be included in the results.
*/
CXCompletionContext_DotMemberAccess = 1 << 5,
/**
* \brief Completions for fields of the member being accessed using the arrow
* operator should be included in the results.
*/
CXCompletionContext_ArrowMemberAccess = 1 << 6,
/**
* \brief Completions for properties of the Objective-C object being accessed
* using the dot operator should be included in the results.
*/
CXCompletionContext_ObjCPropertyAccess = 1 << 7,
/**
* \brief Completions for enum tags should be included in the results.
*/
CXCompletionContext_EnumTag = 1 << 8,
/**
* \brief Completions for union tags should be included in the results.
*/
CXCompletionContext_UnionTag = 1 << 9,
/**
* \brief Completions for struct tags should be included in the results.
*/
CXCompletionContext_StructTag = 1 << 10,
/**
* \brief Completions for C++ class names should be included in the results.
*/
CXCompletionContext_ClassTag = 1 << 11,
/**
* \brief Completions for C++ namespaces and namespace aliases should be
* included in the results.
*/
CXCompletionContext_Namespace = 1 << 12,
/**
* \brief Completions for C++ nested name specifiers should be included in
* the results.
*/
CXCompletionContext_NestedNameSpecifier = 1 << 13,
/**
* \brief Completions for Objective-C interfaces (classes) should be included
* in the results.
*/
CXCompletionContext_ObjCInterface = 1 << 14,
/**
* \brief Completions for Objective-C protocols should be included in
* the results.
*/
CXCompletionContext_ObjCProtocol = 1 << 15,
/**
* \brief Completions for Objective-C categories should be included in
* the results.
*/
CXCompletionContext_ObjCCategory = 1 << 16,
/**
* \brief Completions for Objective-C instance messages should be included
* in the results.
*/
CXCompletionContext_ObjCInstanceMessage = 1 << 17,
/**
* \brief Completions for Objective-C class messages should be included in
* the results.
*/
CXCompletionContext_ObjCClassMessage = 1 << 18,
/**
* \brief Completions for Objective-C selector names should be included in
* the results.
*/
CXCompletionContext_ObjCSelectorName = 1 << 19,
/**
* \brief Completions for preprocessor macro names should be included in
* the results.
*/
CXCompletionContext_MacroName = 1 << 20,
/**
* \brief Natural language completions should be included in the results.
*/
CXCompletionContext_NaturalLanguage = 1 << 21,
/**
* \brief The current context is unknown, so set all contexts.
*/
CXCompletionContext_Unknown = ((1 << 22) - 1)
};
/**
* \brief Returns a default set of code-completion options that can be
* passed to\c clang_codeCompleteAt().
@ -2990,6 +3121,19 @@ CINDEX_LINKAGE
CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
unsigned Index);
/**
* \brief Determines what compeltions are appropriate for the context
* the given code completion.
*
* \param Results the code completion results to query
*
* \returns the kinds of completions that are appropriate for use
* along with the given code completion results.
*/
CINDEX_LINKAGE
unsigned long long clang_codeCompleteGetContexts(
CXCodeCompleteResults *Results);
/**
* @}
*/

View File

@ -185,12 +185,26 @@ public:
/// is expected.
CCC_ObjCMessageReceiver,
/// \brief Code completion occurred on the right-hand side of a member
/// access expression.
/// access expression using the dot operator.
///
/// The results of this completion are the members of the type being
/// accessed. The type itself is available via
/// \c CodeCompletionContext::getType().
CCC_MemberAccess,
CCC_DotMemberAccess,
/// \brief Code completion occurred on the right-hand side of a member
/// access expression using the arrow operator.
///
/// The results of this completion are the members of the type being
/// accessed. The type itself is available via
/// \c CodeCompletionContext::getType().
CCC_ArrowMemberAccess,
/// \brief Code completion occurred on the right-hand side of an Objective-C
/// property access expression.
///
/// The results of this completion are the members of the type being
/// accessed. The type itself is available via
/// \c CodeCompletionContext::getType().
CCC_ObjCPropertyAccess,
/// \brief Code completion occurred after the "enum" keyword, to indicate
/// an enumeration name.
CCC_EnumTag,
@ -235,6 +249,15 @@ public:
/// \brief Code completion in a parenthesized expression, which means that
/// we may also have types here in C and Objective-C (as well as in C++).
CCC_ParenthesizedExpression,
/// \brief Code completion where an Objective-C instance message is expcted.
CCC_ObjCInstanceMessage,
/// \brief Code completion where an Objective-C class message is expected.
CCC_ObjCClassMessage,
/// \brief Code completion where a superclass of an Objective-C class is
/// expected.
CCC_ObjCSuperclass,
/// \brief Code completion where an Objective-C category name is expected.
CCC_ObjCCategoryName,
/// \brief An unknown context, in which we are recovering from a parsing
/// error and don't know which completions we should give.
CCC_Recovery
@ -256,7 +279,8 @@ public:
/// \brief Construct a new code-completion context of the given kind.
CodeCompletionContext(enum Kind Kind, QualType T) : Kind(Kind) {
if (Kind == CCC_MemberAccess)
if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess ||
Kind == CCC_ObjCPropertyAccess)
BaseType = T;
else
PreferredType = T;

View File

@ -182,6 +182,10 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
// all types are available due to functional casts.
if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND))
Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
// In Objective-C, you can only be a subclass of another Objective-C class
if (isa<ObjCInterfaceDecl>(ND))
Contexts |= (1 << (CodeCompletionContext::CCC_ObjCSuperclass - 1));
// Deal with tag names.
if (isa<EnumDecl>(ND)) {
@ -208,6 +212,8 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
} else if (isa<ObjCProtocolDecl>(ND)) {
Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
} else if (isa<ObjCCategoryDecl>(ND)) {
Contexts = (1 << (CodeCompletionContext::CCC_ObjCCategoryName - 1));
} else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) {
Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1));
@ -1902,7 +1908,7 @@ namespace {
/// results from an ASTUnit with the code-completion results provided to it,
/// then passes the result on to
class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer {
unsigned NormalContexts;
unsigned long long NormalContexts;
ASTUnit &AST;
CodeCompleteConsumer &Next;
@ -1916,22 +1922,24 @@ namespace {
// Compute the set of contexts in which we will look when we don't have
// any information about the specific context.
NormalContexts
= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
| (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
| (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1))
| (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
| (1 << (CodeCompletionContext::CCC_Statement - 1))
| (1 << (CodeCompletionContext::CCC_Expression - 1))
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
| (1 << (CodeCompletionContext::CCC_MemberAccess - 1))
| (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1))
| (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
| (1 << (CodeCompletionContext::CCC_Recovery - 1));
= (1LL << (CodeCompletionContext::CCC_TopLevel - 1))
| (1LL << (CodeCompletionContext::CCC_ObjCInterface - 1))
| (1LL << (CodeCompletionContext::CCC_ObjCImplementation - 1))
| (1LL << (CodeCompletionContext::CCC_ObjCIvarList - 1))
| (1LL << (CodeCompletionContext::CCC_Statement - 1))
| (1LL << (CodeCompletionContext::CCC_Expression - 1))
| (1LL << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
| (1LL << (CodeCompletionContext::CCC_DotMemberAccess - 1))
| (1LL << (CodeCompletionContext::CCC_ArrowMemberAccess - 1))
| (1LL << (CodeCompletionContext::CCC_ObjCPropertyAccess - 1))
| (1LL << (CodeCompletionContext::CCC_ObjCProtocolName - 1))
| (1LL << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
| (1LL << (CodeCompletionContext::CCC_Recovery - 1));
if (AST.getASTContext().getLangOptions().CPlusPlus)
NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1))
| (1 << (CodeCompletionContext::CCC_UnionTag - 1))
| (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
NormalContexts |= (1LL << (CodeCompletionContext::CCC_EnumTag - 1))
| (1LL << (CodeCompletionContext::CCC_UnionTag - 1))
| (1LL << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
}
virtual void ProcessCodeCompleteResults(Sema &S,
@ -1969,12 +1977,15 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_Statement:
case CodeCompletionContext::CCC_Expression:
case CodeCompletionContext::CCC_ObjCMessageReceiver:
case CodeCompletionContext::CCC_MemberAccess:
case CodeCompletionContext::CCC_DotMemberAccess:
case CodeCompletionContext::CCC_ArrowMemberAccess:
case CodeCompletionContext::CCC_ObjCPropertyAccess:
case CodeCompletionContext::CCC_Namespace:
case CodeCompletionContext::CCC_Type:
case CodeCompletionContext::CCC_Name:
case CodeCompletionContext::CCC_PotentiallyQualifiedName:
case CodeCompletionContext::CCC_ParenthesizedExpression:
case CodeCompletionContext::CCC_ObjCSuperclass:
break;
case CodeCompletionContext::CCC_EnumTag:
@ -1993,6 +2004,9 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_TypeQualifiers:
case CodeCompletionContext::CCC_Other:
case CodeCompletionContext::CCC_OtherWithMacros:
case CodeCompletionContext::CCC_ObjCInstanceMessage:
case CodeCompletionContext::CCC_ObjCClassMessage:
case CodeCompletionContext::CCC_ObjCCategoryName:
// We're looking for nothing, or we're looking for names that cannot
// be hidden.
return;

View File

@ -46,7 +46,9 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_ObjCImplementation:
case CCC_ObjCIvarList:
case CCC_ClassStructUnion:
case CCC_MemberAccess:
case CCC_DotMemberAccess:
case CCC_ArrowMemberAccess:
case CCC_ObjCPropertyAccess:
case CCC_EnumTag:
case CCC_UnionTag:
case CCC_ClassOrStructTag:
@ -64,6 +66,10 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_TypeQualifiers:
case CCC_Other:
case CCC_OtherWithMacros:
case CCC_ObjCInstanceMessage:
case CCC_ObjCClassMessage:
case CCC_ObjCSuperclass:
case CCC_ObjCCategoryName:
return false;
}

View File

@ -3244,8 +3244,23 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
return;
}
enum CodeCompletionContext::Kind contextKind;
if (IsArrow) {
contextKind = CodeCompletionContext::CCC_ArrowMemberAccess;
}
else {
if (BaseType->isObjCObjectPointerType() ||
BaseType->isObjCObjectOrInterfaceType()) {
contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess;
}
else {
contextKind = CodeCompletionContext::CCC_DotMemberAccess;
}
}
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess,
CodeCompletionContext(contextKind,
BaseType),
&ResultBuilder::IsMember);
Results.EnterNewScope();
@ -3471,10 +3486,17 @@ void Sema::CodeCompleteCase(Scope *S) {
}
Results.ExitScope();
if (CodeCompleter->includeMacros())
//We need to make sure we're setting the right context,
//so only say we include macros if the code completer says we do
enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other;
if (CodeCompleter->includeMacros()) {
AddMacroResults(PP, Results);
kind = CodeCompletionContext::CCC_OtherWithMacros;
}
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_OtherWithMacros,
kind,
Results.data(),Results.size());
}
@ -4934,7 +4956,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
bool AtArgumentExpression,
bool IsSuper) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
CodeCompletionContext::CCC_ObjCClassMessage);
AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents,
AtArgumentExpression, IsSuper, Results);
@ -4954,7 +4976,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
CodeCompletionContext::CCC_ObjCClassMessage,
Results.data(), Results.size());
}
@ -4997,7 +5019,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// Build the set of methods we can see.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
CodeCompletionContext::CCC_ObjCInstanceMessage);
Results.EnterNewScope();
// If this is a send-to-super, try to add the special "super" send
@ -5110,7 +5132,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
CodeCompletionContext::CCC_ObjCInstanceMessage,
Results.data(),Results.size());
}
@ -5301,8 +5323,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
false, Results);
Results.ExitScope();
// FIXME: Add a special context for this, use cached global completion
// results.
// FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
Results.data(),Results.size());
@ -5311,7 +5332,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
SourceLocation ClassNameLoc) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
CodeCompletionContext::CCC_ObjCSuperclass);
Results.EnterNewScope();
// Make sure that we ignore the class we're currently defining.
@ -5325,10 +5346,9 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
false, Results);
Results.ExitScope();
// FIXME: Add a special context for this, use cached global completion
// results.
// FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
CodeCompletionContext::CCC_ObjCSuperclass,
Results.data(),Results.size());
}
@ -5342,8 +5362,7 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
true, Results);
Results.ExitScope();
// FIXME: Add a special context for this, use cached global completion
// results.
// FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
Results.data(),Results.size());
@ -5355,7 +5374,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
CodeCompletionContext::CCC_ObjCCategoryName);
// Ignore any categories we find that have already been implemented by this
// interface.
@ -5379,7 +5398,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
CodeCompletionContext::CCC_ObjCCategoryName,
Results.data(),Results.size());
}
@ -5398,7 +5417,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
CodeCompletionContext::CCC_ObjCCategoryName);
// Add all of the categories that have have corresponding interface
// declarations in this class and any of its superclasses, except for
@ -5419,7 +5438,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
CodeCompletionContext::CCC_ObjCCategoryName,
Results.data(),Results.size());
}

View File

@ -52,10 +52,21 @@ Z::operator int() const {
// CHECK-MEMBER: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )}
// CHECK-MEMBER: CXXDestructor:{ResultType void}{Informative Y::}{TypedText ~Y}{LeftParen (}{RightParen )}
// CHECK-MEMBER: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )}
// CHECK-MEMBER: Completion contexts:
// CHECK-MEMBER-NEXT: Dot member access
// CHECK-OVERLOAD: NotImplemented:{ResultType int &}{Text overloaded}{LeftParen (}{Text Z z}{Comma , }{CurrentParameter int second}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType float &}{Text overloaded}{LeftParen (}{Text int i}{Comma , }{CurrentParameter long second}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType double &}{Text overloaded}{LeftParen (}{Text float f}{Comma , }{CurrentParameter int second}{RightParen )}
// CHECK-OVERLOAD: Completion contexts:
// CHECK-OVERLOAD-NEXT: Any type
// CHECK-OVERLOAD-NEXT: Any value
// CHECK-OVERLOAD-NEXT: Enum tag
// CHECK-OVERLOAD-NEXT: Union tag
// CHECK-OVERLOAD-NEXT: Struct tag
// CHECK-OVERLOAD-NEXT: Class name
// CHECK-OVERLOAD-NEXT: Nested name specifier
// CHECK-OVERLOAD-NEXT: Objective-C interface
// RUN: c-index-test -code-completion-at=%s:37:10 %s | FileCheck -check-prefix=CHECK-EXPR %s
// CHECK-EXPR: NotImplemented:{TypedText int} (50)
@ -65,3 +76,12 @@ Z::operator int() const {
// CHECK-EXPR: FieldDecl:{ResultType float}{Text Y::}{TypedText member} (18)
// CHECK-EXPR: CXXMethod:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} (37)
// CHECK-EXPR: Namespace:{TypedText N}{Text ::} (75)
// CHECK-EXPR: Completion contexts:
// CHECK-EXPR-NEXT: Any type
// CHECK-EXPR-NEXT: Any value
// CHECK-EXPR-NEXT: Enum tag
// CHECK-EXPR-NEXT: Union tag
// CHECK-EXPR-NEXT: Struct tag
// CHECK-EXPR-NEXT: Class name
// CHECK-EXPR-NEXT: Nested name specifier
// CHECK-EXPR-NEXT: Objective-C interface

View File

@ -11,8 +11,9 @@ char in_char = 'a';
// RUN: c-index-test -code-completion-at=%s:4:32 %s > %t
// RUN: echo "DONE" >> %t
// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t
// CHECK-CC1-NOT: :
// CHECK-CC1: DONE
// CHECK-CC1: Completion contexts:
// CHECK-CC1-NEXT: Natural language
// CHECK-CC1-NEXT: DONE
// RUN: c-index-test -code-completion-at=%s:5:18 %s > %t
// RUN: echo "DONE" >> %t
// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t

View File

@ -1018,6 +1018,79 @@ void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, "\n");
}
void print_completion_contexts(unsigned long long contexts, FILE *file) {
fprintf(file, "Completion contexts:\n");
if (contexts == CXCompletionContext_Unknown) {
fprintf(file, "Unknown\n");
}
if (contexts & CXCompletionContext_AnyType) {
fprintf(file, "Any type\n");
}
if (contexts & CXCompletionContext_AnyValue) {
fprintf(file, "Any value\n");
}
if (contexts & CXCompletionContext_ObjCObjectValue) {
fprintf(file, "Objective-C object value\n");
}
if (contexts & CXCompletionContext_ObjCSelectorValue) {
fprintf(file, "Objective-C selector value\n");
}
if (contexts & CXCompletionContext_CXXClassTypeValue) {
fprintf(file, "C++ class type value\n");
}
if (contexts & CXCompletionContext_DotMemberAccess) {
fprintf(file, "Dot member access\n");
}
if (contexts & CXCompletionContext_ArrowMemberAccess) {
fprintf(file, "Arrow member access\n");
}
if (contexts & CXCompletionContext_ObjCPropertyAccess) {
fprintf(file, "Objective-C property access\n");
}
if (contexts & CXCompletionContext_EnumTag) {
fprintf(file, "Enum tag\n");
}
if (contexts & CXCompletionContext_UnionTag) {
fprintf(file, "Union tag\n");
}
if (contexts & CXCompletionContext_StructTag) {
fprintf(file, "Struct tag\n");
}
if (contexts & CXCompletionContext_ClassTag) {
fprintf(file, "Class name\n");
}
if (contexts & CXCompletionContext_Namespace) {
fprintf(file, "Namespace or namespace alias\n");
}
if (contexts & CXCompletionContext_NestedNameSpecifier) {
fprintf(file, "Nested name specifier\n");
}
if (contexts & CXCompletionContext_ObjCInterface) {
fprintf(file, "Objective-C interface\n");
}
if (contexts & CXCompletionContext_ObjCProtocol) {
fprintf(file, "Objective-C protocol\n");
}
if (contexts & CXCompletionContext_ObjCCategory) {
fprintf(file, "Objective-C category\n");
}
if (contexts & CXCompletionContext_ObjCInstanceMessage) {
fprintf(file, "Objective-C instance method\n");
}
if (contexts & CXCompletionContext_ObjCClassMessage) {
fprintf(file, "Objective-C class method\n");
}
if (contexts & CXCompletionContext_ObjCSelectorName) {
fprintf(file, "Objective-C selector name\n");
}
if (contexts & CXCompletionContext_MacroName) {
fprintf(file, "Macro name\n");
}
if (contexts & CXCompletionContext_NaturalLanguage) {
fprintf(file, "Natural language\n");
}
}
int my_stricmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2);
@ -1099,6 +1172,7 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
if (results) {
unsigned i, n = results->NumResults;
unsigned long long contexts;
if (!timing_only) {
/* Sort the code-completion results based on the typed text. */
clang_sortCodeCompletionResults(results->Results, results->NumResults);
@ -1112,6 +1186,10 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
PrintDiagnostic(diag);
clang_disposeDiagnostic(diag);
}
contexts = clang_codeCompleteGetContexts(results);
print_completion_contexts(contexts, stdout);
clang_disposeCodeCompleteResults(results);
}
clang_disposeTranslationUnit(TU);

View File

@ -235,6 +235,13 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Allocator used to store code completion results.
clang::CodeCompletionAllocator CodeCompletionAllocator;
/// \brief Context under which completion occurred.
enum clang::CodeCompletionContext::Kind ContextKind;
/// \brief A bitfield representing the acceptable completions for the
/// current context.
unsigned long long Contexts;
};
/// \brief Tracks the number of code-completion result objects that are
@ -273,6 +280,177 @@ AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
} // end extern "C"
static unsigned long long getContextsForContextKind(
enum CodeCompletionContext::Kind kind,
Sema &S) {
unsigned long long contexts = 0;
switch (kind) {
case CodeCompletionContext::CCC_OtherWithMacros: {
//We can allow macros here, but we don't know what else is permissible
//So we'll say the only thing permissible are macros
contexts = CXCompletionContext_MacroName;
break;
}
case CodeCompletionContext::CCC_TopLevel:
case CodeCompletionContext::CCC_ObjCIvarList:
case CodeCompletionContext::CCC_ClassStructUnion:
case CodeCompletionContext::CCC_Type: {
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface;
if (S.getLangOptions().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
CXCompletionContext_ClassTag |
CXCompletionContext_NestedNameSpecifier;
}
break;
}
case CodeCompletionContext::CCC_Statement: {
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_AnyValue;
if (S.getLangOptions().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
CXCompletionContext_ClassTag |
CXCompletionContext_NestedNameSpecifier;
}
break;
}
case CodeCompletionContext::CCC_Expression: {
contexts = CXCompletionContext_AnyValue;
if (S.getLangOptions().CPlusPlus) {
contexts |= CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
CXCompletionContext_ClassTag |
CXCompletionContext_NestedNameSpecifier;
}
break;
}
case CodeCompletionContext::CCC_ObjCMessageReceiver: {
contexts = CXCompletionContext_ObjCObjectValue |
CXCompletionContext_ObjCSelectorValue |
CXCompletionContext_ObjCInterface;
if (S.getLangOptions().CPlusPlus) {
contexts |= CXCompletionContext_CXXClassTypeValue |
CXCompletionContext_AnyType |
CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
CXCompletionContext_ClassTag |
CXCompletionContext_NestedNameSpecifier;
}
break;
}
case CodeCompletionContext::CCC_DotMemberAccess: {
contexts = CXCompletionContext_DotMemberAccess;
break;
}
case CodeCompletionContext::CCC_ArrowMemberAccess: {
contexts = CXCompletionContext_ArrowMemberAccess;
break;
}
case CodeCompletionContext::CCC_ObjCPropertyAccess: {
contexts = CXCompletionContext_ObjCPropertyAccess;
break;
}
case CodeCompletionContext::CCC_EnumTag: {
contexts = CXCompletionContext_EnumTag |
CXCompletionContext_NestedNameSpecifier;
break;
}
case CodeCompletionContext::CCC_UnionTag: {
contexts = CXCompletionContext_UnionTag |
CXCompletionContext_NestedNameSpecifier;
break;
}
case CodeCompletionContext::CCC_ClassOrStructTag: {
contexts = CXCompletionContext_StructTag |
CXCompletionContext_ClassTag |
CXCompletionContext_NestedNameSpecifier;
break;
}
case CodeCompletionContext::CCC_ObjCProtocolName: {
contexts = CXCompletionContext_ObjCProtocol;
break;
}
case CodeCompletionContext::CCC_Namespace: {
contexts = CXCompletionContext_Namespace;
break;
}
case CodeCompletionContext::CCC_PotentiallyQualifiedName: {
contexts = CXCompletionContext_NestedNameSpecifier;
break;
}
case CodeCompletionContext::CCC_MacroNameUse: {
contexts = CXCompletionContext_MacroName;
break;
}
case CodeCompletionContext::CCC_NaturalLanguage: {
contexts = CXCompletionContext_NaturalLanguage;
break;
}
case CodeCompletionContext::CCC_SelectorName: {
contexts = CXCompletionContext_ObjCSelectorName;
break;
}
case CodeCompletionContext::CCC_ParenthesizedExpression: {
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_AnyValue;
if (S.getLangOptions().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
CXCompletionContext_ClassTag |
CXCompletionContext_NestedNameSpecifier;
}
break;
}
case CodeCompletionContext::CCC_ObjCInstanceMessage: {
contexts = CXCompletionContext_ObjCInstanceMessage;
break;
}
case CodeCompletionContext::CCC_ObjCClassMessage: {
contexts = CXCompletionContext_ObjCClassMessage;
break;
}
case CodeCompletionContext::CCC_ObjCSuperclass: {
contexts = CXCompletionContext_ObjCInterface;
break;
}
case CodeCompletionContext::CCC_ObjCCategoryName: {
contexts = CXCompletionContext_ObjCCategory;
break;
}
case CodeCompletionContext::CCC_Other:
case CodeCompletionContext::CCC_ObjCInterface:
case CodeCompletionContext::CCC_ObjCImplementation:
case CodeCompletionContext::CCC_Name:
case CodeCompletionContext::CCC_MacroName:
case CodeCompletionContext::CCC_PreprocessorExpression:
case CodeCompletionContext::CCC_PreprocessorDirective:
case CodeCompletionContext::CCC_TypeQualifiers: {
//Only Clang results should be accepted, so we'll set all of the other
//context bits to 0 (i.e. the empty set)
contexts = CXCompletionContext_Unexposed;
break;
}
case CodeCompletionContext::CCC_Recovery: {
//We don't know what the current context is, so we'll return unknown
//This is the equivalent of setting all of the other context bits
contexts = CXCompletionContext_Unknown;
break;
}
}
return contexts;
}
namespace {
class CaptureCompletionResults : public CodeCompleteConsumer {
AllocatedCXCodeCompleteResults &AllocatedResults;
@ -298,6 +476,11 @@ namespace {
R.CompletionString = StoredCompletion;
StoredResults.push_back(R);
}
enum CodeCompletionContext::Kind kind = Context.getKind();
AllocatedResults.ContextKind = kind;
AllocatedResults.Contexts = getContextsForContextKind(kind, S);
}
virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
@ -538,6 +721,15 @@ clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
}
unsigned long long
clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) {
AllocatedCXCodeCompleteResults *Results
= static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
if (!Results)
return 0;
return Results->Contexts;
}
} // end extern "C"

View File

@ -6,6 +6,7 @@ _clang_annotateTokens
_clang_codeCompleteAt
_clang_codeCompleteGetDiagnostic
_clang_codeCompleteGetNumDiagnostics
_clang_codeCompleteGetContexts
_clang_constructUSR_ObjCCategory
_clang_constructUSR_ObjCClass
_clang_constructUSR_ObjCIvar

View File

@ -6,6 +6,7 @@ clang_annotateTokens
clang_codeCompleteAt
clang_codeCompleteGetDiagnostic
clang_codeCompleteGetNumDiagnostics
clang_codeCompleteGetContexts
clang_constructUSR_ObjCCategory
clang_constructUSR_ObjCClass
clang_constructUSR_ObjCIvar