Teach code completion to adjust its completion priorities based on the
type that we expect to see at a given point in the grammar, e.g., when
initializing a variable, returning a result, or calling a function. We
don't prune the candidate set at all, just adjust priorities to favor
things that should type-check, using an ultra-simplified type system.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105128 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index d5488e8..74b3b5b 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -2729,7 +2729,27 @@
/// \param NumArgs the number of arguments in \p Args.
virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
ExprTy **Args, unsigned NumArgs) { }
-
+
+ /// \brief Code completion for the initializer of a variable declaration.
+ ///
+ /// \param S The scope in which the initializer occurs.
+ ///
+ /// \param D The declaration being initialized.
+ virtual void CodeCompleteInitializer(Scope *S, DeclPtrTy D) { }
+
+ /// \brief Code completion after the "return" keyword within a function.
+ ///
+ /// \param S The scope in which the return statement occurs.
+ virtual void CodeCompleteReturn(Scope *S) { }
+
+ /// \brief Code completion for the right-hand side of an assignment or
+ /// compound assignment operator.
+ ///
+ /// \param S The scope in which the assignment occurs.
+ ///
+ /// \param LHS The left-hand side of the assignment expression.
+ virtual void CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS) { }
+
/// \brief Code completion for a C++ nested-name-specifier that precedes a
/// qualified-id of some form.
///
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 1f1c0cc..fd000b8 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -59,6 +59,18 @@
CCD_InBaseClass = 2
};
+/// \brief Priority value factors by which we will divide or multiply the
+/// priority of a code-completion result.
+enum {
+ /// \brief Divide by this factor when a code-completion result's type exactly
+ /// matches the type we expect.
+ CCF_ExactTypeMatch = 4,
+ /// \brief Divide by this factor when a code-completion result's type is
+ /// similar to the type we expect (e.g., both arithmetic types, both
+ /// Objective-C object pointer types).
+ CCF_SimilarTypeMatch = 2
+};
+
class FunctionDecl;
class FunctionType;
class FunctionTemplateDecl;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 76da135..5d52d8b 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -556,6 +556,13 @@
Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl);
}
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteInitializer(CurScope, ThisDecl);
+ ConsumeCodeCompletionToken();
+ SkipUntil(tok::comma, true, true);
+ return ThisDecl;
+ }
+
OwningExprResult Init(ParseInitializer());
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 0059a9a..7be1a19 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -343,6 +343,14 @@
}
}
+ // Code completion for the right-hand side of an assignment expression
+ // goes through a special hook that takes the left-hand side into account.
+ if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) {
+ Actions.CodeCompleteAssignmentRHS(CurScope, LHS.get());
+ ConsumeCodeCompletionToken();
+ return ExprError();
+ }
+
// Parse another leaf here for the RHS of the operator.
// ParseCastExpression works here because all RHS expressions in C have it
// as a prefix, at least. However, in C++, an assignment-expression could
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 1ca6a0c..f0930a0 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1199,6 +1199,13 @@
OwningExprResult R(Actions);
if (Tok.isNot(tok::semi)) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteReturn(CurScope);
+ ConsumeCodeCompletionToken();
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+
R = ParseExpression();
if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
SkipUntil(tok::semi, false, true);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 0870cf4..7338915 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -4417,6 +4417,7 @@
//@{
virtual void CodeCompleteOrdinaryName(Scope *S,
CodeCompletionContext CompletionContext);
+ virtual void CodeCompleteExpression(Scope *S, QualType T);
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
SourceLocation OpLoc,
bool IsArrow);
@@ -4424,6 +4425,10 @@
virtual void CodeCompleteCase(Scope *S);
virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
ExprTy **Args, unsigned NumArgs);
+ virtual void CodeCompleteInitializer(Scope *S, DeclPtrTy D);
+ virtual void CodeCompleteReturn(Scope *S);
+ virtual void CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS);
+
virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext);
virtual void CodeCompleteUsing(Scope *S);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 876aecb..339c46f 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -119,6 +119,13 @@
/// nested-name-specifiers that would otherwise be filtered out.
bool AllowNestedNameSpecifiers;
+ /// \brief If set, the type that we would prefer our resulting value
+ /// declarations to have.
+ ///
+ /// Closely matching the preferred type gives a boost to a result's
+ /// priority.
+ CanQualType PreferredType;
+
/// \brief A list of shadow maps, which is used to model name hiding at
/// different levels of, e.g., the inheritance hierarchy.
std::list<ShadowMap> ShadowMaps;
@@ -147,6 +154,11 @@
unsigned size() const { return Results.size(); }
bool empty() const { return Results.empty(); }
+ /// \brief Specify the preferred type.
+ void setPreferredType(QualType T) {
+ PreferredType = SemaRef.Context.getCanonicalType(T);
+ }
+
/// \brief Specify whether nested-name-specifiers are allowed.
void allowNestedNameSpecifiers(bool Allow = true) {
AllowNestedNameSpecifiers = Allow;
@@ -565,6 +577,118 @@
Results.push_back(R);
}
+enum SimplifiedTypeClass {
+ STC_Arithmetic,
+ STC_Array,
+ STC_Block,
+ STC_Function,
+ STC_ObjectiveC,
+ STC_Other,
+ STC_Pointer,
+ STC_Record,
+ STC_Void
+};
+
+/// \brief A simplified classification of types used to determine whether two
+/// types are "similar enough" when adjusting priorities.
+static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) {
+ switch (T->getTypeClass()) {
+ case Type::Builtin:
+ switch (cast<BuiltinType>(T)->getKind()) {
+ case BuiltinType::Void:
+ return STC_Void;
+
+ case BuiltinType::NullPtr:
+ return STC_Pointer;
+
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::UndeducedAuto:
+ return STC_Other;
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ return STC_ObjectiveC;
+
+ default:
+ return STC_Arithmetic;
+ }
+ return STC_Other;
+
+ case Type::Complex:
+ return STC_Arithmetic;
+
+ case Type::Pointer:
+ return STC_Pointer;
+
+ case Type::BlockPointer:
+ return STC_Block;
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ return getSimplifiedTypeClass(T->getAs<ReferenceType>()->getPointeeType());
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::DependentSizedArray:
+ return STC_Array;
+
+ case Type::DependentSizedExtVector:
+ case Type::Vector:
+ case Type::ExtVector:
+ return STC_Arithmetic;
+
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return STC_Function;
+
+ case Type::Record:
+ return STC_Record;
+
+ case Type::Enum:
+ return STC_Arithmetic;
+
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ return STC_ObjectiveC;
+
+ default:
+ return STC_Other;
+ }
+}
+
+/// \brief Get the type that a given expression will have if this declaration
+/// is used as an expression in its "typical" code-completion form.
+static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) {
+ ND = cast<NamedDecl>(ND->getUnderlyingDecl());
+
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ return C.getTypeDeclType(Type);
+ if (ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND))
+ return C.getObjCInterfaceType(Iface);
+
+ QualType T;
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ T = Function->getResultType();
+ else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ T = Method->getResultType();
+ else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
+ T = FunTmpl->getTemplatedDecl()->getResultType();
+ else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext()));
+ else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ T = Property->getType();
+ else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+ T = Value->getType();
+ else
+ return QualType();
+
+ return T.getNonReferenceType();
+}
+
void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
NamedDecl *Hiding, bool InBaseClass = false) {
if (R.Kind != Result::RK_Declaration) {
@@ -618,6 +742,21 @@
if (InBaseClass)
R.Priority += CCD_InBaseClass;
+ if (!PreferredType.isNull()) {
+ if (ValueDecl *Value = dyn_cast<ValueDecl>(R.Declaration)) {
+ CanQualType T = SemaRef.Context.getCanonicalType(
+ getDeclUsageType(SemaRef.Context, Value));
+ // Check for exactly-matching types (modulo qualifiers).
+ if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, T))
+ R.Priority /= CCF_ExactTypeMatch;
+ // Check for nearly-matching types, based on classification of each.
+ else if ((getSimplifiedTypeClass(PreferredType)
+ == getSimplifiedTypeClass(T)) &&
+ !(PreferredType->isEnumeralType() && T->isEnumeralType()))
+ R.Priority /= CCF_SimilarTypeMatch;
+ }
+ }
+
// Insert this result into the set of results.
Results.push_back(R);
}
@@ -755,35 +894,6 @@
isa<ObjCPropertyDecl>(ND);
}
-/// \brief Get the type that a given expression will have if this declaration
-/// is used as an expression in its "typical" code-completion form.
-static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) {
- ND = cast<NamedDecl>(ND->getUnderlyingDecl());
-
- if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
- return C.getTypeDeclType(Type);
- if (ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND))
- return C.getObjCInterfaceType(Iface);
-
- QualType T;
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
- T = Function->getResultType();
- else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
- T = Method->getResultType();
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
- T = FunTmpl->getTemplatedDecl()->getResultType();
- else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
- T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext()));
- else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
- T = Property->getType();
- else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
- T = Value->getType();
- else
- return QualType();
-
- return T.getNonReferenceType();
-}
-
static bool isObjCReceiverType(ASTContext &C, QualType T) {
T = C.getCanonicalType(T);
switch (T->getTypeClass()) {
@@ -2131,6 +2241,31 @@
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+/// \brief Perform code-completion in an expression context when we know what
+/// type we're looking for.
+void Sema::CodeCompleteExpression(Scope *S, QualType T) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+
+ if (WantTypesInContext(CCC_Expression, getLangOptions()))
+ Results.setFilter(&ResultBuilder::IsOrdinaryName);
+ else
+ Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);
+ Results.setPreferredType(T.getNonReferenceType());
+
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+
+ Results.EnterNewScope();
+ AddOrdinaryNameResults(CCC_Expression, S, *this, Results);
+ Results.ExitScope();
+
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+
static void AddObjCProperties(ObjCContainerDecl *Container,
bool AllowCategories,
DeclContext *CurContext,
@@ -2447,6 +2582,8 @@
}
}
+ QualType ParamType;
+
if (!CandidateSet.empty()) {
// Sort the overload candidate set by placing the best overloads first.
std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
@@ -2459,14 +2596,85 @@
if (Cand->Viable)
Results.push_back(ResultCandidate(Cand->Function));
}
+
+ // From the viable candidates, try to determine the type of this parameter.
+ for (unsigned I = 0, N = Results.size(); I != N; ++I) {
+ if (const FunctionType *FType = Results[I].getFunctionType())
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FType))
+ if (NumArgs < Proto->getNumArgs()) {
+ if (ParamType.isNull())
+ ParamType = Proto->getArgType(NumArgs);
+ else if (!Context.hasSameUnqualifiedType(
+ ParamType.getNonReferenceType(),
+ Proto->getArgType(NumArgs).getNonReferenceType())) {
+ ParamType = QualType();
+ break;
+ }
+ }
+ }
+ } else {
+ // Try to determine the parameter type from the type of the expression
+ // being called.
+ QualType FunctionType = Fn->getType();
+ if (const PointerType *Ptr = FunctionType->getAs<PointerType>())
+ FunctionType = Ptr->getPointeeType();
+ else if (const BlockPointerType *BlockPtr
+ = FunctionType->getAs<BlockPointerType>())
+ FunctionType = BlockPtr->getPointeeType();
+ else if (const MemberPointerType *MemPtr
+ = FunctionType->getAs<MemberPointerType>())
+ FunctionType = MemPtr->getPointeeType();
+
+ if (const FunctionProtoType *Proto
+ = FunctionType->getAs<FunctionProtoType>()) {
+ if (NumArgs < Proto->getNumArgs())
+ ParamType = Proto->getArgType(NumArgs);
+ }
}
- CodeCompleteOrdinaryName(S, CCC_Expression);
+ if (ParamType.isNull())
+ CodeCompleteOrdinaryName(S, CCC_Expression);
+ else
+ CodeCompleteExpression(S, ParamType);
+
if (!Results.empty())
CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
Results.size());
}
+void Sema::CodeCompleteInitializer(Scope *S, DeclPtrTy D) {
+ ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D.getAs<Decl>());
+ if (!VD) {
+ CodeCompleteOrdinaryName(S, CCC_Expression);
+ return;
+ }
+
+ CodeCompleteExpression(S, VD->getType());
+}
+
+void Sema::CodeCompleteReturn(Scope *S) {
+ QualType ResultType;
+ if (isa<BlockDecl>(CurContext)) {
+ if (BlockScopeInfo *BSI = getCurBlock())
+ ResultType = BSI->ReturnType;
+ } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(CurContext))
+ ResultType = Function->getResultType();
+ else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext))
+ ResultType = Method->getResultType();
+
+ if (ResultType.isNull())
+ CodeCompleteOrdinaryName(S, CCC_Expression);
+ else
+ CodeCompleteExpression(S, ResultType);
+}
+
+void Sema::CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS) {
+ if (LHS)
+ CodeCompleteExpression(S, static_cast<Expr *>(LHS)->getType());
+ else
+ CodeCompleteOrdinaryName(S, CCC_Expression);
+}
+
void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.getScopeRep() || !CodeCompleter)
diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c
index 7733016..1b55c78 100644
--- a/test/Index/complete-exprs.c
+++ b/test/Index/complete-exprs.c
@@ -9,13 +9,19 @@
// RUN: c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: macro definition:{TypedText __VERSION__} (70)
-// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12)
// CHECK-CC1-NOT: NotImplemented:{TypedText float} (40)
-// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8)
+// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (2)
// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
-// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
-// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
-// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: macro definition:{TypedText __VERSION__} (70)
+// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC3-NOT: NotImplemented:{TypedText float} (40)
+// CHECK-CC3: ParmDecl:{ResultType int}{TypedText j} (8)
+// CHECK-CC3: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expressio
+
+// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: c-index-test -code-completion-at=%s:7:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: macro definition:{TypedText __VERSION__} (70)
// CHECK-CC2: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
diff --git a/test/Index/complete-type-factors.m b/test/Index/complete-type-factors.m
new file mode 100644
index 0000000..3f56b38
--- /dev/null
+++ b/test/Index/complete-type-factors.m
@@ -0,0 +1,117 @@
+/* Run lines are at the end, since line/column matter in this test. */
+
+enum Color {
+ Red, Green, Blue
+};
+
+enum Priority {
+ Low,
+ High
+};
+
+int func1(enum Color);
+enum Priority func2(int);
+void func3(float);
+enum Priority test1(enum Priority priority, enum Color color, int integer) {
+ int i = integer;
+ enum Color c = color;
+ return priority;
+ func1(c);
+ void (^block)(enum Color, int);
+ block(c, 17);
+ c = color;
+}
+
+// FIXME: It would be great for message sends to have the same
+// benefits as function calls, but we don't quite have the
+// infrastructure yet.
+
+// RUN: c-index-test -code-completion-at=%s:16:11 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (30)
+// CHECK-CC1: ParmDecl:{ResultType enum Color}{TypedText color} (4)
+// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (12)
+// CHECK-CC1: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (25)
+// CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (30)
+// CHECK-CC1: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (30)
+// CHECK-CC1: VarDecl:{ResultType int}{TypedText i} (2)
+// CHECK-CC1: ParmDecl:{ResultType int}{TypedText integer} (2)
+// CHECK-CC1: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (30)
+// CHECK-CC1: macro definition:{TypedText OBJC_NEW_PROPERTIES} (70)
+// CHECK-CC1: macro definition:{TypedText OBJC_ZEROCOST_EXCEPTIONS} (70)
+// CHECK-CC1: ParmDecl:{ResultType enum Priority}{TypedText priority} (4)
+// CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (30)
+// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
+// CHECK-CC1: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (25)
+// RUN: c-index-test -code-completion-at=%s:17:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (15)
+// CHECK-CC2: VarDecl:{ResultType enum Color}{TypedText c} (2)
+// CHECK-CC2: ParmDecl:{ResultType enum Color}{TypedText color} (2)
+// CHECK-CC2: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (25)
+// CHECK-CC2: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (15)
+// CHECK-CC2: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (60)
+// CHECK-CC2: VarDecl:{ResultType int}{TypedText i} (4)
+// CHECK-CC2: ParmDecl:{ResultType int}{TypedText integer} (4)
+// CHECK-CC2: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (60)
+// CHECK-CC2: macro definition:{TypedText OBJC_NEW_PROPERTIES} (70)
+// CHECK-CC2: macro definition:{TypedText OBJC_ZEROCOST_EXCEPTIONS} (70)
+// CHECK-CC2: ParmDecl:{ResultType enum Priority}{TypedText priority} (8)
+// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (15)
+// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
+// CHECK-CC2: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50)
+// RUN: c-index-test -code-completion-at=%s:18:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (60)
+// CHECK-CC3: VarDecl:{ResultType enum Color}{TypedText c} (8)
+// CHECK-CC3: ParmDecl:{ResultType enum Color}{TypedText color} (8)
+// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (25)
+// CHECK-CC3: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (12)
+// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText func3}{LeftParen (}{Placeholder float}{RightParen )} (50)
+// CHECK-CC3: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (60)
+// CHECK-CC3: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (15)
+// CHECK-CC3: VarDecl:{ResultType int}{TypedText i} (4)
+// CHECK-CC3: ParmDecl:{ResultType int}{TypedText integer} (4)
+// CHECK-CC3: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (15)
+// CHECK-CC3: macro definition:{TypedText OBJC_NEW_PROPERTIES} (70)
+// CHECK-CC3: macro definition:{TypedText OBJC_ZEROCOST_EXCEPTIONS} (70)
+// CHECK-CC3: ParmDecl:{ResultType enum Priority}{TypedText priority} (2)
+// CHECK-CC3: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (60)
+// CHECK-CC3: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
+// CHECK-CC3: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (12)
+// RUN: c-index-test -code-completion-at=%s:19:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (15)
+// CHECK-CC4: VarDecl:{ResultType enum Color}{TypedText c} (2)
+// CHECK-CC4: ParmDecl:{ResultType enum Color}{TypedText color} (2)
+// CHECK-CC4: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (25)
+// CHECK-CC4: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC4: FunctionDecl:{ResultType void}{TypedText func3}{LeftParen (}{Placeholder float}{RightParen )} (50)
+// CHECK-CC4: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (15)
+// CHECK-CC4: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (60)
+// CHECK-CC4: VarDecl:{ResultType int}{TypedText i} (4)
+// CHECK-CC4: ParmDecl:{ResultType int}{TypedText integer} (4)
+// CHECK-CC4: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (60)
+// CHECK-CC4: macro definition:{TypedText OBJC_NEW_PROPERTIES} (70)
+// CHECK-CC4: macro definition:{TypedText OBJC_ZEROCOST_EXCEPTIONS} (70)
+// CHECK-CC4: ParmDecl:{ResultType enum Priority}{TypedText priority} (8)
+// CHECK-CC4: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (15)
+// CHECK-CC4: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
+// CHECK-CC4: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50)
+// RUN: c-index-test -code-completion-at=%s:21:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: c-index-test -code-completion-at=%s:22:7 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: VarDecl:{ResultType void (^)(enum Color, int)}{TypedText block} (8)
+// CHECK-CC6: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (15)
+// CHECK-CC6: VarDecl:{ResultType enum Color}{TypedText c} (2)
+// CHECK-CC6: ParmDecl:{ResultType enum Color}{TypedText color} (2)
+// CHECK-CC6: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (25)
+// CHECK-CC6: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC6: FunctionDecl:{ResultType void}{TypedText func3}{LeftParen (}{Placeholder float}{RightParen )} (50)
+// CHECK-CC6: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (15)
+// CHECK-CC6: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (60)
+// CHECK-CC6: VarDecl:{ResultType int}{TypedText i} (4)
+// CHECK-CC6: ParmDecl:{ResultType int}{TypedText integer} (4)
+// CHECK-CC6: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (60)
+// CHECK-CC6: macro definition:{TypedText OBJC_NEW_PROPERTIES} (70)
+// CHECK-CC6: macro definition:{TypedText OBJC_ZEROCOST_EXCEPTIONS} (70)
+// CHECK-CC6: ParmDecl:{ResultType enum Priority}{TypedText priority} (8)
+// CHECK-CC6: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (15)
+// CHECK-CC6: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
+// CHECK-CC6: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50)