From 08ee284dc08719fa071ec112f4d1ce9cfb646fba Mon Sep 17 00:00:00 2001
From: Alex Lorenz <arphaman@gmail.com>
Date: Wed, 23 May 2018 00:52:20 +0000
Subject: [PATCH] [AST][ObjC] Print implicit property expression that only has
 a setter without crashing

rdar://40447209


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333046 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/IdentifierTable.h |  3 +++
 lib/AST/StmtPrinter.cpp               | 10 +++++++---
 lib/Basic/IdentifierTable.cpp         |  6 ++++++
 test/Misc/ast-print-objectivec.m      | 10 ++++++++++
 4 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 10a0251453..9a33873518 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -825,6 +825,9 @@ public:
   static Selector constructSetterSelector(IdentifierTable &Idents,
                                           SelectorTable &SelTable,
                                           const IdentifierInfo *Name);
+
+  /// Return the property name for the given setter selector.
+  static std::string getPropertyNameFromSetterSelector(Selector Sel);
 };
 
 /// DeclarationNameExtra - Common base of the MultiKeywordSelector,
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index dc6cc16071..38ec6632e7 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1406,9 +1406,13 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
     OS << Node->getClassReceiver()->getName() << ".";
   }
 
-  if (Node->isImplicitProperty())
-    Node->getImplicitPropertyGetter()->getSelector().print(OS);
-  else
+  if (Node->isImplicitProperty()) {
+    if (const auto *Getter = Node->getImplicitPropertyGetter())
+      Getter->getSelector().print(OS);
+    else
+      OS << SelectorTable::getPropertyNameFromSetterSelector(
+          Node->getImplicitPropertySetter()->getSelector());
+  } else
     OS << Node->getExplicitProperty()->getName();
 }
 
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index ec9ca7616c..37703ca776 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -645,6 +645,12 @@ SelectorTable::constructSetterSelector(IdentifierTable &Idents,
   return SelTable.getUnarySelector(SetterName);
 }
 
+std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) {
+  StringRef Name = Sel.getNameForSlot(0);
+  assert(Name.startswith("set") && "invalid setter name");
+  return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();
+}
+
 size_t SelectorTable::getTotalMemory() const {
   SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
   return SelTabImpl.Allocator.getTotalMemory();
diff --git a/test/Misc/ast-print-objectivec.m b/test/Misc/ast-print-objectivec.m
index eb1b469610..05a0a5d4aa 100644
--- a/test/Misc/ast-print-objectivec.m
+++ b/test/Misc/ast-print-objectivec.m
@@ -50,3 +50,13 @@ struct __attribute__((objc_bridge_related(C1,,))) S1;
 
 // CHECK: @class C1;
 // CHECK: struct __attribute__((objc_bridge_related(C1, , ))) S1;
+
+@interface ImplicitPropertyWithSetterOnly
+
+- (void)setX:(int)x;
+
+@end
+
+void printImplicitPropertyWithSetterOnly(ImplicitPropertyWithSetterOnly *x) {
+  x.x = 313; // CHECK: x.x = 313;
+}
-- 
2.40.0