]> granicus.if.org Git - clang/commitdiff
Implement code completion for Objective-C message sends to "super".
authorDouglas Gregor <dgregor@apple.com>
Tue, 17 Nov 2009 17:59:40 +0000 (17:59 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 17 Nov 2009 17:59:40 +0000 (17:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89112 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaCodeComplete.cpp
test/Index/complete-objc-message.m

index e2aac775077e88c21a4a7924c4b1dc1001a207ab..cb3bd1c06c312e2788bfe23f41fb1595d3880e6d 100644 (file)
@@ -13,6 +13,7 @@
 #include "Sema.h"
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -1555,11 +1556,61 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
 
 void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) {
   typedef CodeCompleteConsumer::Result Result;
+  ObjCInterfaceDecl *CDecl = 0;
+
+  // FIXME: Pass this in!
+  SourceLocation NameLoc;
+
+  if (FName->isStr("super")) {
+    // We're sending a message to "super".
+    if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
+      // Figure out which interface we're in.
+      CDecl = CurMethod->getClassInterface();
+      if (!CDecl)
+        return;
+
+      // Find the superclass of this class.
+      CDecl = CDecl->getSuperClass();
+      if (!CDecl)
+        return;
+
+      if (CurMethod->isInstanceMethod()) {
+        // We are inside an instance method, which means that the message
+        // send [super ...] is actually calling an instance method on the
+        // current object. Build the super expression and handle this like
+        // an instance method.
+        QualType SuperTy = Context.getObjCInterfaceType(CDecl);
+        SuperTy = Context.getObjCObjectPointerType(SuperTy);
+        OwningExprResult Super
+          = Owned(new (Context) ObjCSuperExpr(NameLoc, SuperTy));
+        return CodeCompleteObjCInstanceMethod(S, (Expr *)Super.get());
+      }
+
+      // Okay, we're calling a factory method in our superclass.
+    } 
+  }
+
+  // If the given name refers to an interface type, retrieve the
+  // corresponding declaration.
+  if (!CDecl)
+    if (TypeTy *Ty = getTypeName(*FName, NameLoc, S, 0, false)) {
+      QualType T = GetTypeFromParser(Ty, 0);
+      if (!T.isNull()) 
+        if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
+          CDecl = Interface->getDecl();
+    }
+
+  if (!CDecl && FName->isStr("super")) {
+    // "super" may be the name of a variable, in which case we are
+    // probably calling an instance method.
+    OwningExprResult Super = ActOnDeclarationNameExpr(S, NameLoc, FName,
+                                                      false, 0, false);
+    return CodeCompleteObjCInstanceMethod(S, (Expr *)Super.get());
+  }
+
   ResultBuilder Results(*this);
   Results.EnterNewScope();
   
-  ObjCInterfaceDecl *CDecl = getObjCInterfaceDecl(FName);
-    
   while (CDecl != NULL) {
     for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(), 
                                                E = CDecl->classmeth_end(); 
index c495d0b7a63e3acda23eda688174b7ed30ca348a..728d9803c5ae8858a32c9e1a0ddc3d0ddd69811f 100644 (file)
@@ -23,6 +23,57 @@ void func() {
   Foo *obj = [Foo new];
   [obj xx];
 }
+
+@interface MyClass { }
++ (int)MyClassMethod:(id)obj;
+- (int)MyInstMethod:(id)x second:(id)y;
+@end
+
+@interface MySubClass : MyClass { }
++ (int)MySubClassMethod;
+- (int)MySubInstMethod;
+@end
+
+@implementation MyClass 
++ (int)MyClassMethod:(id)obj {
+  return 0;
+}
+
++ (int)MyPrivateMethod {
+  return 1;
+}
+
+- (int)MyInstMethod:(id)x second:(id)y {
+  return 2;
+}
+
+- (int)MyPrivateInstMethod {
+  return 3;
+}
+@end
+
+@implementation MySubClass
++ (int)MySubClassMethod {
+  return 2;
+}
+
++ (int)MySubPrivateMethod {
+  return [super MyPrivateMethod];
+}
+
+- (int)MySubInstMethod:(id)obj {
+  return [super MyInstMethod: obj second:obj];
+}
+
+- (int)MyInstMethod:(id)x second:(id)y {
+  return 3;
+}
+@end
+
+void test_super_var(MySubClass *super) {
+  [super MyInstMethod: super second:super];
+}
+
 // RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
 // CHECK-CC1: {TypedText categoryClassMethod}
 // CHECK-CC1: {TypedText classMethod2}
@@ -33,3 +84,13 @@ void func() {
 // CHECK-CC2: {TypedText categoryInstanceMethod}
 // CHECK-CC2: {TypedText instanceMethod1}
 // CHECK-CC2: {TypedText protocolInstanceMethod:}{Placeholder (int)value}
+// RUN: c-index-test -code-completion-at=%s:61:16 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCClassMethodDecl:{TypedText MyClassMethod:}{Placeholder (id)obj}
+// FIXME-CC3: ObjCClassMethodDecl:{TypedText MyPrivateMethod}
+// RUN: c-index-test -code-completion-at=%s:65:16 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: ObjCInstanceMethodDecl:{TypedText MyInstMethod:}{Placeholder (id)x}{Text  second:}{Placeholder (id)y}
+// FIXME-CC4: ObjCInstanceMethodDecl:{TypedText MyPrivateInstMethod}
+// RUN: c-index-test -code-completion-at=%s:74:9 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MySubInstMethod}
+// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MyInstMethod:}{Placeholder (id)x}{Text  second:}{Placeholder (id)y}
+