From de4827dd340b77640b4cead98502148d8a5bcf70 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 8 Mar 2010 16:40:19 +0000 Subject: [PATCH] Extend ObjCMessageExpr for class method sends with the source location of the class name. llvm-svn: 97943 --- clang/include/clang/AST/ExprObjC.h | 30 +++++++++++++++++--- clang/lib/AST/Expr.cpp | 34 +++++++++++++---------- clang/lib/Checker/CFRefCount.cpp | 4 +-- clang/lib/CodeGen/CGObjC.cpp | 2 +- clang/lib/Frontend/PCHReaderStmt.cpp | 5 ++-- clang/lib/Frontend/PCHWriterStmt.cpp | 5 ++-- clang/lib/Index/Analyzer.cpp | 4 +-- clang/lib/Sema/SemaExprObjC.cpp | 12 ++++---- clang/test/Index/c-index-getCursor-test.m | 4 ++- clang/tools/CIndex/CIndex.cpp | 9 ++++++ 10 files changed, 75 insertions(+), 34 deletions(-) diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index df39b535eb3e..6f43973a3e1d 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -347,6 +347,9 @@ class ObjCMessageExpr : public Expr { // message expression. unsigned NumArgs; + /// \brief The location of the class name in a class message. + SourceLocation ClassNameLoc; + // A unigue name for this message. Selector SelName; @@ -367,7 +370,8 @@ class ObjCMessageExpr : public Expr { public: /// This constructor is used to represent class messages where the /// ObjCInterfaceDecl* of the receiver is not known. - ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, Selector selInfo, + ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, + SourceLocation clsNameLoc, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); @@ -375,7 +379,8 @@ public: /// This constructor is used to represent class messages where the /// ObjCInterfaceDecl* of the receiver is known. // FIXME: clsName should be typed to ObjCInterfaceType - ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, Selector selInfo, + ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, + SourceLocation clsNameLoc, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); @@ -411,7 +416,24 @@ public: ObjCMethodDecl *getMethodDecl() { return MethodProto; } void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; } - typedef std::pair ClassInfo; + /// \brief Describes the class receiver of a message send. + struct ClassInfo { + /// \brief The interface declaration for the class that is + /// receiving the message. May be NULL. + ObjCInterfaceDecl *Decl; + + /// \brief The name of the class that is receiving the + /// message. This will never be NULL. + IdentifierInfo *Name; + + /// \brief The source location of the class name. + SourceLocation Loc; + + ClassInfo() : Decl(0), Name(0), Loc() { } + + ClassInfo(ObjCInterfaceDecl *Decl, IdentifierInfo *Name, SourceLocation Loc) + : Decl(Decl), Name(Name), Loc(Loc) { } + }; /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl* /// and IdentifierInfo* of the invoked class. Both can be NULL if this @@ -423,7 +445,7 @@ public: /// getClassName - For class methods, this returns the invoked class, /// and returns NULL otherwise. For instance methods, use getReceiver. IdentifierInfo *getClassName() const { - return getClassInfo().second; + return getClassInfo().Name; } /// getNumArgs - Return the number of actual arguments to this call. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index a2914bc6bf4e..c08a3a26e178 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2115,12 +2115,12 @@ ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver, // constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, - Selector selInfo, QualType retType, - ObjCMethodDecl *mproto, + SourceLocation clsNameLoc, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), - MethodProto(mproto) { + : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), + SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); @@ -2134,12 +2134,14 @@ ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, // constructor for class messages. ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, - Selector selInfo, QualType retType, + SourceLocation clsNameLoc, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) -: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), -MethodProto(mproto) { + : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), + SelName(selInfo), MethodProto(mproto) +{ NumArgs = nargs; SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); @@ -2157,23 +2159,27 @@ ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { default: assert(false && "Invalid ObjCMessageExpr."); case IsInstMeth: - return ClassInfo(0, 0); + return ClassInfo(0, 0, SourceLocation()); case IsClsMethDeclUnknown: - return ClassInfo(0, (IdentifierInfo*) (x & ~Flags)); + return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc); case IsClsMethDeclKnown: { ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); - return ClassInfo(D, D->getIdentifier()); + return ClassInfo(D, D->getIdentifier(), ClassNameLoc); } } } void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { - if (CI.first == 0 && CI.second == 0) + if (CI.Decl == 0 && CI.Name == 0) { SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth); - else if (CI.first == 0) - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.second | IsClsMethDeclUnknown); + return; + } + + if (CI.Decl == 0) + SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown); else - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown); + SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown); + ClassNameLoc = CI.Loc; } void ObjCMessageExpr::DoDestroy(ASTContext &C) { diff --git a/clang/lib/Checker/CFRefCount.cpp b/clang/lib/Checker/CFRefCount.cpp index ecb98a0496f0..9a76f6a2a3ad 100644 --- a/clang/lib/Checker/CFRefCount.cpp +++ b/clang/lib/Checker/CFRefCount.cpp @@ -853,7 +853,7 @@ public: RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { return getClassMethodSummary(ME->getSelector(), ME->getClassName(), - ME->getClassInfo().first, + ME->getClassInfo().Decl, ME->getMethodDecl(), ME->getType()); } @@ -2511,7 +2511,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this // is a call to a class method whose type we can resolve. In such // cases, promote the return type to XXX* (where XXX is the class). - const ObjCInterfaceDecl *D = ME->getClassInfo().first; + const ObjCInterfaceDecl *D = ME->getClassInfo().Decl; return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); } diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index b62e6ed44366..3ff77f0170c1 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -59,7 +59,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { // Find the receiver llvm::Value *Receiver; if (!ReceiverExpr) { - const ObjCInterfaceDecl *OID = E->getClassInfo().first; + const ObjCInterfaceDecl *OID = E->getClassInfo().Decl; // Very special case, super send in class method. The receiver is // self (the class object) and the send uses super semantics. diff --git a/clang/lib/Frontend/PCHReaderStmt.cpp b/clang/lib/Frontend/PCHReaderStmt.cpp index d123694d699d..7b94805d3999 100644 --- a/clang/lib/Frontend/PCHReaderStmt.cpp +++ b/clang/lib/Frontend/PCHReaderStmt.cpp @@ -792,8 +792,9 @@ unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { cast_or_null(StmtStack[StmtStack.size() - E->getNumArgs() - 1])); if (!E->getReceiver()) { ObjCMessageExpr::ClassInfo CI; - CI.first = cast_or_null(Reader.GetDecl(Record[Idx++])); - CI.second = Reader.GetIdentifierInfo(Record, Idx); + CI.Decl = cast_or_null(Reader.GetDecl(Record[Idx++])); + CI.Name = Reader.GetIdentifierInfo(Record, Idx); + CI.Loc = SourceLocation::getFromRawEncoding(Record[Idx++]); E->setClassInfo(CI); } diff --git a/clang/lib/Frontend/PCHWriterStmt.cpp b/clang/lib/Frontend/PCHWriterStmt.cpp index a8cc9d6f4591..9a5417ca6102 100644 --- a/clang/lib/Frontend/PCHWriterStmt.cpp +++ b/clang/lib/Frontend/PCHWriterStmt.cpp @@ -720,8 +720,9 @@ void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) { if (!E->getReceiver()) { ObjCMessageExpr::ClassInfo CI = E->getClassInfo(); - Writer.AddDeclRef(CI.first, Record); - Writer.AddIdentifierRef(CI.second, Record); + Writer.AddDeclRef(CI.Decl, Record); + Writer.AddIdentifierRef(CI.Name, Record); + Writer.AddSourceLocation(CI.Loc, Record); } for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); diff --git a/clang/lib/Index/Analyzer.cpp b/clang/lib/Index/Analyzer.cpp index fb3529d5405c..7b414f2a9fb5 100644 --- a/clang/lib/Index/Analyzer.cpp +++ b/clang/lib/Index/Analyzer.cpp @@ -177,7 +177,7 @@ public: if (IsInstanceMethod) return false; - MsgD = Msg->getClassInfo().first; + MsgD = Msg->getClassInfo().Decl; // FIXME: Case when we only have an identifier. assert(MsgD && "Identifier only"); } @@ -250,7 +250,7 @@ public: while (true) { if (Msg->getReceiver() == 0) { CanBeClassMethod = true; - MsgD = Msg->getClassInfo().first; + MsgD = Msg->getClassInfo().Decl; // FIXME: Case when we only have an identifier. assert(MsgD && "Identifier only"); break; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 3a05241c016b..c60455d8456c 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -470,13 +470,13 @@ Sema::ExprResult Sema::ActOnClassMessage( // now, we simply pass the "super" identifier through (which isn't consistent // with instance methods. if (isSuper) - return new (Context) ObjCMessageExpr(Context, receiverName, Sel, returnType, - Method, lbrac, rbrac, ArgExprs, - NumArgs); + return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc, + Sel, returnType, Method, lbrac, rbrac, + ArgExprs, NumArgs); else - return new (Context) ObjCMessageExpr(Context, ClassDecl, Sel, returnType, - Method, lbrac, rbrac, ArgExprs, - NumArgs); + return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc, + Sel, returnType, Method, lbrac, rbrac, + ArgExprs, NumArgs); } // ActOnInstanceMessage - used for both unary and keyword messages. diff --git a/clang/test/Index/c-index-getCursor-test.m b/clang/test/Index/c-index-getCursor-test.m index 197a7d41c57b..8341b80a673f 100644 --- a/clang/test/Index/c-index-getCursor-test.m +++ b/clang/test/Index/c-index-getCursor-test.m @@ -120,7 +120,9 @@ int main (int argc, const char * argv[]) { // CHECK: [47:4 - 47:6] VarDecl=c:47:12 (Definition) // CHECK: [47:6 - 47:10] ObjCProtocolRef=SubP:27:1 // CHECK: [47:10 - 47:16] VarDecl=c:47:12 (Definition) -// CHECK: [47:16 - 47:26] ObjCMessageExpr=fooC:8:1 +// CHECK: [47:16 - 47:17] ObjCMessageExpr=fooC:8:1 +// CHECK: [47:17 - 47:20] ObjCClassRef=Foo:3:12 +// CHECK: [47:20 - 47:26] ObjCMessageExpr=fooC:8:1 // CHECK: [47:26 - 47:27] UnexposedStmt= // CHECK: [47:27 - 48:2] UnexposedStmt= // CHECK: [48:2 - 48:4] TypeRef=id:0:0 diff --git a/clang/tools/CIndex/CIndex.cpp b/clang/tools/CIndex/CIndex.cpp index 4ae2f806062f..6fff18304386 100644 --- a/clang/tools/CIndex/CIndex.cpp +++ b/clang/tools/CIndex/CIndex.cpp @@ -315,6 +315,7 @@ public: bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); bool VisitExplicitCastExpr(ExplicitCastExpr *E); bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + bool VisitObjCMessageExpr(ObjCMessageExpr *E); }; } // end anonymous namespace @@ -901,6 +902,14 @@ bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return VisitExpr(E); } +bool CursorVisitor::VisitObjCMessageExpr(ObjCMessageExpr *E) { + ObjCMessageExpr::ClassInfo CI = E->getClassInfo(); + if (CI.Decl && Visit(MakeCursorObjCClassRef(CI.Decl, CI.Loc, TU))) + return true; + + return VisitExpr(E); +} + bool CursorVisitor::VisitAttributes(Decl *D) { for (const Attr *A = D->getAttrs(); A; A = A->getNext()) if (Visit(MakeCXCursor(A, D, TU)))