aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ExprObjC.h68
-rw-r--r--lib/AST/StmtDumper.cpp8
-rw-r--r--lib/Sema/SemaPseudoObject.cpp15
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp6
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp1
-rw-r--r--test/Index/get-cursor.m17
-rw-r--r--tools/libclang/CIndex.cpp13
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))