Introduce a new code-completion point when we're parsing a

declarator. Here, we can only see a few things (e.g., cvr-qualifiers,
nested name specifiers) and we do not want to provide other non-macro
completions. Previously, we would end up in recovery mode and would
provide a large number of non-relevant completions.

llvm-svn: 111818
This commit is contained in:
Douglas Gregor 2010-08-23 18:23:48 +00:00
parent 08fd2cf26a
commit c49f5b2f11
9 changed files with 178 additions and 22 deletions

View File

@ -2798,6 +2798,22 @@ public:
virtual void CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext) { }
/// \brief Code completion for a declarator name.
///
///
///
/// \param S The scope in which code completion occurs.
///
/// \param AllowNonIdentifiers Whether non-identifier names are allowed in
/// this context, e.g., operator+.
///
/// \param AllowNestedNameSpecifiers Whether nested-name-specifiers are
/// allowed in this context, e.g., because it is a top-level declaration or
/// a friend declaration.
virtual void CodeCompleteDeclarator(Scope *S,
bool AllowNonIdentifiers,
bool AllowNestedNameSpecifiers) { }
/// \brief Code completion for a member access expression.
///
/// This code completion action is invoked when the code-completion token

View File

@ -164,7 +164,12 @@ public:
/// is expected.
CCC_Namespace,
/// \brief Code completion occurred where a type name is expected.
CCC_Type
CCC_Type,
/// \brief Code completion occurred where a new name is expected.
CCC_Name,
/// \brief Code completion occurred where a new name is expected and a
/// qualified name is permissible.
CCC_PotentiallyQualifiedName
};
private:

View File

@ -4640,6 +4640,9 @@ public:
//@{
virtual void CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext);
virtual void CodeCompleteDeclarator(Scope *S,
bool AllowNonIdentifiers,
bool AllowNestedNameSpecifiers);
virtual void CodeCompleteExpression(Scope *S, QualType T,
bool IntegralConstantExpression = false);
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,

View File

@ -235,7 +235,8 @@ void ASTUnit::CacheCodeCompletionResults() {
| (1 << (CodeCompletionContext::CCC_EnumTag - 1))
| (1 << (CodeCompletionContext::CCC_UnionTag - 1))
| (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1))
| (1 << (CodeCompletionContext::CCC_Type - 1));
| (1 << (CodeCompletionContext::CCC_Type - 1))
| (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1));
if (isa<NamespaceDecl>(Results[I].Declaration) ||
isa<NamespaceAliasDecl>(Results[I].Declaration))
@ -275,7 +276,10 @@ void ASTUnit::CacheCodeCompletionResults() {
| (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
| (1 << (CodeCompletionContext::CCC_Statement - 1))
| (1 << (CodeCompletionContext::CCC_Expression - 1))
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
| (1 << (CodeCompletionContext::CCC_Name - 1))
| (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1));
CachedResult.Priority = Results[I].Priority;
CachedResult.Kind = Results[I].CursorKind;
CachedResult.TypeClass = STC_Void;
@ -1532,6 +1536,8 @@ void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_MemberAccess:
case CodeCompletionContext::CCC_Namespace:
case CodeCompletionContext::CCC_Type:
case CodeCompletionContext::CCC_Name:
case CodeCompletionContext::CCC_PotentiallyQualifiedName:
break;
case CodeCompletionContext::CCC_EnumTag:

View File

@ -853,21 +853,7 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
DeclSpecContext DSContext) {
if (Tok.is(tok::code_completion)) {
Action::ParserCompletionContext CCC = Action::PCC_Namespace;
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
CCC = DSContext == DSC_class? Action::PCC_MemberTemplate
: Action::PCC_Template;
else if (DSContext == DSC_class)
CCC = Action::PCC_Class;
else if (ObjCImpDecl)
CCC = Action::PCC_ObjCImplementation;
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
ConsumeCodeCompletionToken();
}
DeclSpecContext DSContext) {
DS.SetRangeStart(Tok.getLocation());
while (1) {
bool isInvalid = false;
@ -884,6 +870,38 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.Finish(Diags, PP);
return;
case tok::code_completion: {
Action::ParserCompletionContext CCC = Action::PCC_Namespace;
if (DS.hasTypeSpecifier()) {
bool AllowNonIdentifiers
= (getCurScope()->getFlags() & (Scope::ControlScope |
Scope::BlockScope |
Scope::TemplateParamScope |
Scope::FunctionPrototypeScope |
Scope::AtCatchScope)) == 0;
bool AllowNestedNameSpecifiers
= DSContext == DSC_top_level ||
(DSContext == DSC_class && DS.isFriendSpecified());
Actions.CodeCompleteDeclarator(getCurScope(), AllowNonIdentifiers,
AllowNestedNameSpecifiers);
ConsumeCodeCompletionToken();
return;
}
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
CCC = DSContext == DSC_class? Action::PCC_MemberTemplate
: Action::PCC_Template;
else if (DSContext == DSC_class)
CCC = Action::PCC_Class;
else if (ObjCImpDecl)
CCC = Action::PCC_ObjCImplementation;
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
ConsumeCodeCompletionToken();
return;
}
case tok::coloncolon: // ::foo::bar
// C++ scope specifier. Annotate and loop, or bail out on error.
if (TryAnnotateCXXScopeToken(true)) {
@ -2501,6 +2519,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
DirectDeclParseFunction DirectDeclParser) {
if (Diags.hasAllExtensionsSilenced())
D.setExtension();
// C++ member pointers start with a '::' or a nested-name.
// Member pointers get special handling, since there's no place for the
// scope spec in the generic path below.

View File

@ -774,9 +774,9 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
/// __attribute__((unused))
///
Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::TokenKind mType,
Decl *IDecl,
tok::ObjCKeywordKind MethodImplKind) {
tok::TokenKind mType,
Decl *IDecl,
tok::ObjCKeywordKind MethodImplKind) {
ParsingDeclRAIIObject PD(*this);
if (Tok.is(tok::code_completion)) {

View File

@ -2222,7 +2222,7 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S,
void Sema::CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext) {
typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this);
ResultBuilder Results(*this);
// Determine how to filter results, e.g., so that the names of
// values (functions, enumerators, function templates, etc.) are
@ -2268,6 +2268,45 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
Results.data(),Results.size());
}
void Sema::CodeCompleteDeclarator(Scope *S,
bool AllowNonIdentifiers,
bool AllowNestedNameSpecifiers) {
typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this);
Results.EnterNewScope();
// Type qualifiers can come after names.
Results.AddResult(Result("const"));
Results.AddResult(Result("volatile"));
if (getLangOptions().C99)
Results.AddResult(Result("restrict"));
if (getLangOptions().CPlusPlus) {
if (AllowNonIdentifiers) {
Results.AddResult(Result("operator"));
}
// Add nested-name-specifiers.
if (AllowNestedNameSpecifiers) {
Results.allowNestedNameSpecifiers();
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer,
CodeCompleter->includeGlobals());
}
}
Results.ExitScope();
// Allow macros for names.
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter,
AllowNestedNameSpecifiers
? CodeCompletionContext::CCC_PotentiallyQualifiedName
: CodeCompletionContext::CCC_Name,
Results.data(), Results.size());
}
/// \brief Perform code-completion in an expression context when we know what
/// type we're looking for.
///

View File

@ -0,0 +1,39 @@
// This test is line- and column-sensitive, so test commands are at the bottom.
namespace N {
struct X {
int f(X);
};
}
int g(int a);
struct Y { };
struct Z {
int member;
friend int N::X::f(N::X);
};
// RUN: c-index-test -code-completion-at=%s:8:5 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: NotImplemented:{TypedText const} (30)
// CHECK-CC1: NotImplemented:{TypedText N}{Text ::} (75)
// CHECK-CC1: NotImplemented:{TypedText operator} (30)
// CHECK-CC1: NotImplemented:{TypedText volatile} (30)
// RUN: c-index-test -code-completion-at=%s:8:11 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: NotImplemented:{TypedText const} (30)
// CHECK-CC2-NOT: NotImplemented:{TypedText N}{Text ::} (75)
// CHECK-CC2-NOT: NotImplemented:{TypedText operator} (30)
// CHECK-CC2: NotImplemented:{TypedText volatile} (30)
// RUN: c-index-test -code-completion-at=%s:13:7 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: NotImplemented:{TypedText const} (30)
// CHECK-CC3-NOT: NotImplemented:{TypedText N}{Text ::} (75)
// CHECK-CC3: NotImplemented:{TypedText operator} (30)
// CHECK-CC3: NotImplemented:{TypedText volatile} (30)
// RUN: c-index-test -code-completion-at=%s:14:14 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: NotImplemented:{TypedText const} (30)
// CHECK-CC4: NotImplemented:{TypedText N}{Text ::} (75)
// CHECK-CC4: NotImplemented:{TypedText operator} (30)
// CHECK-CC4: NotImplemented:{TypedText volatile} (30)
// CHECK-CC4: StructDecl:{TypedText Y} (40)
// CHECK-CC4: StructDecl:{TypedText Z} (20)

View File

@ -0,0 +1,29 @@
// This test is line- and column-sensitive, so test commands are at the bottom.
@protocol P
- (int)method:(id)param1;
@end
@interface A <P>
- (int)method:(id)param1;
@property int prop1;
@end
@implementation A
- (int)method:(id)param1 {
for(id x in param1) {
int y;
}
}
@end
// RUN: c-index-test -code-completion-at=%s:7:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1-NOT: NotImplemented:{TypedText extern} (30)
// CHECK-CC1: NotImplemented:{TypedText param1} (30)
// RUN: c-index-test -code-completion-at=%s:9:15 %s | FileCheck -check-prefix=CHECK-CC2 %s
// RUN: c-index-test -code-completion-at=%s:14:10 %s | FileCheck -check-prefix=CHECK-CC2 %s
// RUN: c-index-test -code-completion-at=%s:15:9 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: NotImplemented:{TypedText const} (30)
// CHECK-CC2-NOT: int
// CHECK-CC2: NotImplemented:{TypedText restrict} (30)
// CHECK-CC2: NotImplemented:{TypedText volatile} (30)