diff options
| author | Douglas Gregor <dgregor@apple.com> | 2010-04-06 19:22:33 +0000 | 
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2010-04-06 19:22:33 +0000 | 
| commit | 9d2ddb2e5dc10060299240072d64074510fce9d0 (patch) | |
| tree | 4b50f65cb90fc8a732571711493d1bd66c2d7884 /clang/lib | |
| parent | 08355d6cda3306027cfb210221c09669e0f6e4d7 (diff) | |
| download | bcm5719-llvm-9d2ddb2e5dc10060299240072d64074510fce9d0.tar.gz bcm5719-llvm-9d2ddb2e5dc10060299240072d64074510fce9d0.zip  | |
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. 
llvm-svn: 100548
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 68 | 
1 files changed, 68 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index ac56fab9e8a..49a32a6bddd 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -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 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl,    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 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,    // 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  | 

