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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111818 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/Action.h b/include/clang/Sema/Action.h
index 87cafaf..cc2b71a 100644
--- a/include/clang/Sema/Action.h
+++ b/include/clang/Sema/Action.h
@@ -2798,6 +2798,22 @@
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
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 82ea46c..aadc459 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -164,7 +164,12 @@
/// 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:
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 0bd672f..a8a3562 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4640,6 +4640,9 @@
//@{
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,
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 9aa9f5b..c7d4730 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -235,7 +235,8 @@
| (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 @@
| (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 @@
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:
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 371d8ad..8265f37 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -853,21 +853,7 @@
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 @@
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 @@
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.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 1b456ed..aafe999 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -774,9 +774,9 @@
/// __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)) {
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 34d0c4a..bdcc3ac 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2222,7 +2222,7 @@
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 @@
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.
///
diff --git a/test/Index/complete-declarators.cpp b/test/Index/complete-declarators.cpp
new file mode 100644
index 0000000..ba16e22
--- /dev/null
+++ b/test/Index/complete-declarators.cpp
@@ -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)
+
diff --git a/test/Index/complete-declarators.m b/test/Index/complete-declarators.m
new file mode 100644
index 0000000..d2c3f61
--- /dev/null
+++ b/test/Index/complete-declarators.m
@@ -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)