diff options
-rw-r--r-- | include/clang/AST/ExprObjC.h | 68 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaPseudoObject.cpp | 15 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 6 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 1 | ||||
-rw-r--r-- | test/Index/get-cursor.m | 17 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 13 |
7 files changed, 110 insertions, 18 deletions
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 6e4e5b9a32..4bfd12c069 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -510,7 +510,18 @@ private: /// if the bool is false, this is an explicit property reference; /// the pointer is an ObjCPropertyDecl and Setter is always null. llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; - ObjCMethodDecl *Setter; + + /// \brief Indicates whether the property reference will result in a message + /// to the getter, the setter, or both. + /// This applies to both implicit and explicit property references. + enum MethodRefFlags { + MethodRef_None = 0, + MethodRef_Getter = 0x1, + MethodRef_Setter = 0x2 + }; + + /// \brief Contains the Setter method pointer and MethodRefFlags bit flags. + llvm::PointerIntPair<ObjCMethodDecl *, 2, unsigned> SetterAndMethodRefFlags; // FIXME: Maybe we should store the property identifier here, // because it's not rederivable from the other data when there's an @@ -533,7 +544,7 @@ public: /*TypeDependent=*/false, base->isValueDependent(), base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), - PropertyOrGetter(PD, false), Setter(0), + PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), IdLoc(l), ReceiverLoc(), Receiver(base) { assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -544,7 +555,7 @@ public: : Expr(ObjCPropertyRefExprClass, t, VK, OK, /*TypeDependent=*/false, false, st->isInstantiationDependentType(), st->containsUnexpandedParameterPack()), - PropertyOrGetter(PD, false), Setter(0), + PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -555,7 +566,7 @@ public: : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, Base->isValueDependent(), Base->isInstantiationDependent(), Base->containsUnexpandedParameterPack()), - PropertyOrGetter(Getter, true), Setter(Setter), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -565,7 +576,7 @@ public: SourceLocation IdLoc, SourceLocation SuperLoc, QualType SuperTy) : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), - PropertyOrGetter(Getter, true), Setter(Setter), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -575,7 +586,7 @@ public: SourceLocation IdLoc, SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), - PropertyOrGetter(Getter, true), Setter(Setter), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -598,7 +609,7 @@ public: ObjCMethodDecl *getImplicitPropertySetter() const { assert(isImplicitProperty()); - return Setter; + return SetterAndMethodRefFlags.getPointer(); } Selector getGetterSelector() const { @@ -613,6 +624,28 @@ public: return getExplicitProperty()->getSetterName(); } + /// \brief True if the property reference will result in a message to the + /// getter. + /// This applies to both implicit and explicit property references. + bool isMessagingGetter() const { + return SetterAndMethodRefFlags.getInt() & MethodRef_Getter; + } + + /// \brief True if the property reference will result in a message to the + /// setter. + /// This applies to both implicit and explicit property references. + bool isMessagingSetter() const { + return SetterAndMethodRefFlags.getInt() & MethodRef_Setter; + } + + void setIsMessagingGetter(bool val = true) { + setMethodRefFlag(MethodRef_Getter, val); + } + + void setIsMessagingSetter(bool val = true) { + setMethodRefFlag(MethodRef_Setter, val); + } + const Expr *getBase() const { return cast<Expr>(Receiver.get<Stmt*>()); } @@ -689,15 +722,19 @@ public: private: friend class ASTStmtReader; - void setExplicitProperty(ObjCPropertyDecl *D) { + friend class ASTStmtWriter; + void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) { PropertyOrGetter.setPointer(D); PropertyOrGetter.setInt(false); - Setter = 0; + SetterAndMethodRefFlags.setPointer(0); + SetterAndMethodRefFlags.setInt(methRefFlags); } - void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter) { + void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + unsigned methRefFlags) { PropertyOrGetter.setPointer(Getter); PropertyOrGetter.setInt(true); - this->Setter = Setter; + SetterAndMethodRefFlags.setPointer(Setter); + SetterAndMethodRefFlags.setInt(methRefFlags); } void setBase(Expr *Base) { Receiver = Base; } void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); } @@ -705,6 +742,15 @@ private: void setLocation(SourceLocation L) { IdLoc = L; } void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; } + + void setMethodRefFlag(MethodRefFlags flag, bool val) { + unsigned f = SetterAndMethodRefFlags.getInt(); + if (val) + f |= flag; + else + f &= ~flag; + SetterAndMethodRefFlags.setInt(f); + } }; /// ObjCSubscriptRefExpr - used for array and dictionary subscripting. diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index aea4c395d5..b5e298c0c9 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -686,6 +686,14 @@ void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { if (Node->isSuperReceiver()) OS << " super"; + + OS << " Messaging="; + if (Node->isMessagingGetter() && Node->isMessagingSetter()) + OS << "Getter&Setter"; + else if (Node->isMessagingGetter()) + OS << "Getter"; + else if (Node->isMessagingSetter()) + OS << "Setter"; } void StmtDumper::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) { diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index aebc0eb608..d52c912457 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -208,6 +208,7 @@ namespace { /// A PseudoOpBuilder for Objective-C @properties. class ObjCPropertyOpBuilder : public PseudoOpBuilder { ObjCPropertyRefExpr *RefExpr; + ObjCPropertyRefExpr *SyntacticRefExpr; OpaqueValueExpr *InstanceReceiver; ObjCMethodDecl *Getter; @@ -217,7 +218,7 @@ namespace { public: ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr), - InstanceReceiver(0), Getter(0), Setter(0) { + SyntacticRefExpr(0), InstanceReceiver(0), Getter(0), Setter(0) { } ExprResult buildRValueOperation(Expr *op); @@ -538,6 +539,10 @@ Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase); } + if (ObjCPropertyRefExpr * + refE = dyn_cast<ObjCPropertyRefExpr>(syntacticBase->IgnoreParens())) + SyntacticRefExpr = refE; + return syntacticBase; } @@ -545,7 +550,10 @@ Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { ExprResult ObjCPropertyOpBuilder::buildGet() { findGetter(); assert(Getter); - + + if (SyntacticRefExpr) + SyntacticRefExpr->setIsMessagingGetter(); + QualType receiverType; if (RefExpr->isClassReceiver()) { receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); @@ -581,6 +589,9 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, bool hasSetter = findSetter(); assert(hasSetter); (void) hasSetter; + if (SyntacticRefExpr) + SyntacticRefExpr->setIsMessagingSetter(); + QualType receiverType; if (RefExpr->isClassReceiver()) { receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index d8289f227f..1c9817b955 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -887,13 +887,15 @@ void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { VisitExpr(E); + unsigned MethodRefFlags = Record[Idx++]; bool Implicit = Record[Idx++] != 0; if (Implicit) { ObjCMethodDecl *Getter = ReadDeclAs<ObjCMethodDecl>(Record, Idx); ObjCMethodDecl *Setter = ReadDeclAs<ObjCMethodDecl>(Record, Idx); - E->setImplicitProperty(Getter, Setter); + E->setImplicitProperty(Getter, Setter, MethodRefFlags); } else { - E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx)); + E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx), + MethodRefFlags); } E->setLocation(ReadSourceLocation(Record, Idx)); E->setReceiverLocation(ReadSourceLocation(Record, Idx)); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 791403b5a2..eac7e1fb73 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -851,6 +851,7 @@ void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { VisitExpr(E); + Record.push_back(E->SetterAndMethodRefFlags.getInt()); Record.push_back(E->isImplicitProperty()); if (E->isImplicitProperty()) { Writer.AddDeclRef(E->getImplicitPropertyGetter(), Record); diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m index d343e66a00..ead18de0c0 100644 --- a/test/Index/get-cursor.m +++ b/test/Index/get-cursor.m @@ -41,6 +41,17 @@ struct S { int x; }; } @end +@interface Test2 +-(int)implicitProp; +-(void)setImplicitProp:(int)x; +@end + +void foo1(Test2 *test2) { + int x = test2.implicitProp; + test2.implicitProp = x; + ++test2.implicitProp; +} + // RUN: c-index-test -cursor-at=%s:4:28 -cursor-at=%s:5:28 %s | FileCheck -check-prefix=CHECK-PROP %s // CHECK-PROP: ObjCPropertyDecl=foo1:4:26 // CHECK-PROP: ObjCPropertyDecl=foo2:5:27 @@ -54,6 +65,10 @@ struct S { int x; }; // RUN: c-index-test -cursor-at=%s:37:17 %s | FileCheck -check-prefix=CHECK-IN-IMPL %s // CHECK-IN-IMPL: VarDecl=i:37:17 -// RUN: c-index-test -cursor-at=%s:38:6 -cursor-at=%s:40:11 %s | FileCheck -check-prefix=CHECK-MEMBERREF %s +// RUN: c-index-test -cursor-at=%s:38:6 -cursor-at=%s:40:11 \ +// RUN: -cursor-at=%s:50:20 -cursor-at=%s:51:15 -cursor-at=%s:52:20 %s | FileCheck -check-prefix=CHECK-MEMBERREF %s // CHECK-MEMBERREF: 38:6 MemberRefExpr=x:34:16 SingleRefName=[38:6 - 38:7] RefName=[38:6 - 38:7] Extent=[38:3 - 38:7] // CHECK-MEMBERREF: 40:9 MemberRefExpr=name:23:21 Extent=[40:3 - 40:13] Spelling=name +// CHECK-MEMBERREF: 50:17 MemberRefExpr=implicitProp:45:7 Extent=[50:11 - 50:29] Spelling=implicitProp +// CHECK-MEMBERREF: 51:9 MemberRefExpr=setImplicitProp::46:8 Extent=[51:3 - 51:21] +// CHECK-MEMBERREF: 52:11 MemberRefExpr=setImplicitProp::46:8 Extent=[52:5 - 52:23] diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 972beaf9e7..2a05b1b6f7 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2901,8 +2901,17 @@ static Decl *getDeclFromExpr(Stmt *E) { return ME->getMemberDecl(); if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) return RE->getDecl(); - if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) - return PRE->isExplicitProperty() ? PRE->getExplicitProperty() : 0; + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (PRE->isExplicitProperty()) + return PRE->getExplicitProperty(); + // It could be messaging both getter and setter as in: + // ++myobj.myprop; + // in which case prefer to associate the setter since it is less obvious + // from inspecting the source that the setter is going to get called. + if (PRE->isMessagingSetter()) + return PRE->getImplicitPropertySetter(); + return PRE->getImplicitPropertyGetter(); + } if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) return getDeclFromExpr(POE->getSyntacticForm()); if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) |