Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1531,10 +1531,16 @@ const PrintingPolicy &P) const { const DeclContext *Ctx = getDeclContext(); - // For ObjC methods, look through categories and use the interface as context. + // For ObjC methods and properties, look through categories and use the + // interface as context. if (auto *MD = dyn_cast(this)) if (auto *ID = MD->getClassInterface()) Ctx = ID; + if (auto *PD = dyn_cast(this)) { + if (auto *MD = PD->getGetterMethodDecl()) + if (auto *ID = MD->getClassInterface()) + Ctx = ID; + } if (Ctx->isFunctionOrMethod()) { printName(OS); Index: unittests/AST/NamedDeclPrinterTest.cpp =================================================================== --- unittests/AST/NamedDeclPrinterTest.cpp +++ unittests/AST/NamedDeclPrinterTest.cpp @@ -115,6 +115,18 @@ "input.cc"); } +::testing::AssertionResult +PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName, + StringRef ExpectedPrinted) { + std::vector Args{"-std=c++11", "-xobjective-c++"}; + return PrintedNamedDeclMatches(Code, + Args, + /*SuppressUnwrittenScope*/ true, + objcPropertyDecl(hasName(DeclName)).bind("id"), + ExpectedPrinted, + "input.m"); +} + } // unnamed namespace TEST(NamedDeclPrinter, TestNamespace1) { @@ -179,3 +191,31 @@ "A", "X::A")); } + +TEST(NamedDeclPrinter, TestObjCClassExtension) { + ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches( + R"( + @interface Obj + @end + + @interface Obj () + @property(nonatomic) int property; + @end + )", + "property", + "Obj::property")); +} + +TEST(NamedDeclPrinter, TestObjCClassExtensionWithGetter) { + ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches( + R"( + @interface Obj + @end + + @interface Obj () + @property(nonatomic, getter=myPropertyGetter) int property; + @end + )", + "property", + "Obj::property")); +}