diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 18d054733da1..632d4b95e376 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1942,6 +1942,10 @@ public: Optional> getObjCSubstitutions(const DeclContext *dc) const; + /// Determines if this is an ObjC interface type that may accept type + /// parameters. + bool acceptsObjCTypeParams() const; + const char *getTypeClassName() const; QualType getCanonicalTypeInternal() const { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 5a60655bf484..cee5fee83913 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1339,6 +1339,17 @@ Optional> Type::getObjCSubstitutions( return objectType->getTypeArgs(); } +bool Type::acceptsObjCTypeParams() const { + if (auto *IfaceT = getAsObjCInterfaceType()) { + if (auto *ID = IfaceT->getInterface()) { + if (ID->getTypeParamList()) + return true; + } + } + + return false; +} + void ObjCObjectType::computeSuperClassTypeSlow() const { // Retrieve the class declaration for this type. If there isn't one // (e.g., this is some variant of "id" or "Class"), then there is no diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 4f16d47dfa75..ed6090453daa 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -1658,8 +1658,13 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( identifierLocs[i])); } - Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), - identifierLocPairs.size()); + QualType BaseT = Actions.GetTypeFromParser(baseType); + if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + } else { + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), + identifierLocPairs.size()); + } cutOffParsing(); return; } diff --git a/clang/test/Index/complete-parameterized-classes.m b/clang/test/Index/complete-parameterized-classes.m index c7d273ac1ef7..70d85885e3b7 100644 --- a/clang/test/Index/complete-parameterized-classes.m +++ b/clang/test/Index/complete-parameterized-classes.m @@ -37,6 +37,11 @@ void test2(Test *obj) { -(id)getit:(id)val {} @end +void test3() { + Test<> t; + NSObject<> n; +} + // RUN: c-index-test -code-completion-at=%s:25:8 %s | FileCheck -check-prefix=CHECK-CC0 %s // CHECK-CC0: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply2:}{Placeholder ^(MyClsA *, MyClsB *)block} (35) // CHECK-CC0: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply:}{Placeholder ^(MyClsA *, MyClsB *)block} (35) @@ -64,3 +69,11 @@ void test2(Test *obj) { // CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText apply}{TypedText :}{LeftParen (}{Text void (^)(id, NSObject *)}{RightParen )}{Text block} (40) // CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text NSObject *}{RightParen )}{TypedText getit}{TypedText :}{LeftParen (}{Text id}{RightParen )}{Text val} (40) // CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText prop} (40) + +// RUN: c-index-test -code-completion-at=%s:41:8 %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: ObjCInterfaceDecl:{TypedText MyClsA} +// RUN: c-index-test -code-completion-at=%s:42:12 %s > %t.out +// RUN: FileCheck -input-file=%t.out -check-prefix=CHECK-CC8 %s +// RUN: FileCheck -input-file=%t.out -check-prefix=CHECK-CC9 %s +// CHECK-CC8: ObjCProtocolDecl:{TypedText NSObject} +// CHECK-CC9-NOT: ObjCInterfaceDecl:{TypedText MyClsA}