[cfe-commits] r100548 - in /cfe/trunk: lib/Sema/SemaCodeComplete.cpp test/Index/complete-objc-message-id.m

Douglas Gregor dgregor at apple.com
Tue Apr 6 12:22:33 PDT 2010


Author: dgregor
Date: Tue Apr  6 14:22:33 2010
New Revision: 100548

URL: http://llvm.org/viewvc/llvm-project?rev=100548&view=rev
Log:
When sending a message to "id", apply some heuristics to try to narrow
down the set of code-completion results based on Objective-C
conventions. 

Added:
    cfe/trunk/test/Index/complete-objc-message-id.m
Modified:
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=100548&r1=100547&r2=100548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Apr  6 14:22:33 2010
@@ -20,6 +20,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
 #include <list>
 #include <map>
 #include <vector>
@@ -2909,6 +2910,65 @@
   HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size());
 }
 
+/// \brief When we have an expression with type "id", we may assume
+/// that it has some more-specific class type based on knowledge of
+/// common uses of Objective-C. This routine returns that class type,
+/// or NULL if no better result could be determined.
+static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
+  ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E);
+  if (!Msg)
+    return 0;
+
+  Selector Sel = Msg->getSelector();
+  if (Sel.isNull())
+    return 0;
+
+  IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0);
+  if (!Id)
+    return 0;
+
+  ObjCMethodDecl *Method = Msg->getMethodDecl();
+  if (!Method)
+    return 0;
+
+  // Determine the class that we're sending the message to.
+  ObjCInterfaceDecl *IFace = Msg->getClassInfo().Decl;
+  if (!IFace) {
+    if (Expr *Receiver = Msg->getReceiver()) {
+      QualType T = Receiver->getType();
+      if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
+        IFace = Ptr->getInterfaceDecl();
+    }
+  }
+
+  if (!IFace)
+    return 0;
+
+  ObjCInterfaceDecl *Super = IFace->getSuperClass();
+  if (Method->isInstanceMethod())
+    return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
+      .Case("retain", IFace)
+      .Case("autorelease", IFace)
+      .Case("copy", IFace)
+      .Case("copyWithZone", IFace)
+      .Case("mutableCopy", IFace)
+      .Case("mutableCopyWithZone", IFace)
+      .Case("awakeFromCoder", IFace)
+      .Case("replacementObjectFromCoder", IFace)
+      .Case("class", IFace)
+      .Case("classForCoder", IFace)
+      .Case("superclass", Super)
+      .Default(0);
+
+  return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
+    .Case("new", IFace)
+    .Case("alloc", IFace)
+    .Case("allocWithZone", IFace)
+    .Case("class", IFace)
+    .Case("superclass", Super)
+    .Default(0);
+}
+
 void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
                                         SourceLocation FNameLoc,
                                         IdentifierInfo **SelIdents,
@@ -3032,6 +3092,14 @@
   // Build the set of methods we can see.
   ResultBuilder Results(*this);
   Results.EnterNewScope();
+
+  // If we're messaging an expression with type "id" or "Class", check
+  // whether we know something special about the receiver that allows
+  // us to assume a more-specific receiver type.
+  if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType())
+    if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr))
+      ReceiverType = Context.getObjCObjectPointerType(
+                                          Context.getObjCInterfaceType(IFace));
   
   // Handle messages to Class. This really isn't a message to an instance
   // method, so we treat it the same way we would treat a message send to a

Added: cfe/trunk/test/Index/complete-objc-message-id.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-objc-message-id.m?rev=100548&view=auto
==============================================================================
--- cfe/trunk/test/Index/complete-objc-message-id.m (added)
+++ cfe/trunk/test/Index/complete-objc-message-id.m Tue Apr  6 14:22:33 2010
@@ -0,0 +1,42 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+ at interface A
++ (id)alloc;
++ (id)init;
++ (id)new;
++ (Class)class;
++ (Class)superclass;
+- (id)retain;
+- (id)autorelease;
+- (id)superclass;
+ at end
+
+ at interface B : A
+- (int)B_method;
+ at end
+
+ at interface Unrelated
++ (id)icky;
+ at end
+
+void message_id(B *b) {
+  [[A alloc] init];
+  [[b retain] B_method];
+  [[b superclass] B_method];
+}
+
+// RUN: c-index-test -code-completion-at=%s:24:14 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease}
+// CHECK-CC1-NOT: B_method
+// CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain}
+// RUN: c-index-test -code-completion-at=%s:25:15 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease}
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText B_method}
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain}
+// RUN: c-index-test -code-completion-at=%s:26:19 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease}
+// CHECK-CC3-NOT: B_method
+// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain}
+
+





More information about the cfe-commits mailing list