#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>
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,
// 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
--- /dev/null
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+@interface A
++ (id)alloc;
++ (id)init;
++ (id)new;
++ (Class)class;
++ (Class)superclass;
+- (id)retain;
+- (id)autorelease;
+- (id)superclass;
+@end
+
+@interface B : A
+- (int)B_method;
+@end
+
+@interface Unrelated
++ (id)icky;
+@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}
+
+