summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/Type.h4
-rw-r--r--clang/lib/AST/Type.cpp11
-rw-r--r--clang/lib/Parse/ParseObjc.cpp9
-rw-r--r--clang/test/Index/complete-parameterized-classes.m13
4 files changed, 35 insertions, 2 deletions
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 18d054733da..632d4b95e37 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1942,6 +1942,10 @@ public:
Optional<ArrayRef<QualType>>
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 5a60655bf48..cee5fee8391 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1339,6 +1339,17 @@ Optional<ArrayRef<QualType>> 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 4f16d47dfa7..ed6090453da 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 c7d273ac1ef..70d85885e3b 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}
OpenPOWER on IntegriCloud