static void checkAllProps(MigrationContext &MigrateCtx, std::vector<ObjCPropertyDecl *> &AllProps) { typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; llvm::DenseMap<unsigned, IndivPropsTy> AtProps; for (unsigned i = 0, e = AllProps.size(); i != e; ++i) { ObjCPropertyDecl *PD = AllProps[i]; if (PD->getPropertyAttributesAsWritten() & (ObjCPropertyDecl::OBJC_PR_assign | ObjCPropertyDecl::OBJC_PR_readonly)) { SourceLocation AtLoc = PD->getAtLoc(); if (AtLoc.isInvalid()) continue; unsigned RawAt = AtLoc.getRawEncoding(); AtProps[RawAt].push_back(PD); } } for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator I = AtProps.begin(), E = AtProps.end(); I != E; ++I) { SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first); IndivPropsTy &IndProps = I->second; checkAllAtProps(MigrateCtx, AtLoc, IndProps); } }
ObjCInterfaceDecl *getGetterInterface(ObjCPropertyRefExpr *node) { if (node->isExplicitProperty()) { ObjCPropertyDecl *decl = node->getExplicitProperty(); return decl->getGetterMethodDecl()->getClassInterface(); } return node->getImplicitPropertyGetter()->getClassInterface(); }
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an /// objective C interface. This is a property reference expression. ExprResult Sema:: HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, bool Super) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); if (IFace->isForwardDecl()) { Diag(MemberLoc, diag::err_property_not_found_forward_class) << MemberName << QualType(OPT, 0); Diag(IFace->getLocation(), diag::note_forward_class); return ExprError(); } // Search for a declared property first. if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); QualType ResTy = PD->getType(); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) ResTy = Getter->getResultType(); if (Super) return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, VK_LValue, OK_ObjCProperty, MemberLoc, SuperLoc, SuperType)); else return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, VK_LValue, OK_ObjCProperty, MemberLoc, BaseExpr)); } // Check protocols on qualified interfaces. for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); if (Super) return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), VK_LValue, OK_ObjCProperty, MemberLoc, SuperLoc, SuperType)); else return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), VK_LValue, OK_ObjCProperty, MemberLoc, BaseExpr)); } // If that failed, look for an "implicit" property by seeing if the nullary // selector is implemented. // FIXME: The logic for looking up nullary and unary selectors should be // shared with the code in ActOnInstanceMessage. Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); // May be founf in property's qualified list. if (!Getter) Getter = LookupMethodInQualifiedType(Sel, OPT, true); // If this reference is in an @implementation, check for 'private' methods. if (!Getter) Getter = IFace->lookupPrivateMethod(Sel); // Look through local category implementations associated with the class. if (!Getter) Getter = IFace->getCategoryInstanceMethod(Sel); if (Getter) { // Check if we can reference this property. if (DiagnoseUseOfDecl(Getter, MemberLoc)) return ExprError(); } // If we found a getter then this may be a valid dot-reference, we // will look for the matching setter, in case it is needed. Selector SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); // May be founf in property's qualified list. if (!Setter) Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. Setter = IFace->lookupPrivateMethod(SetterSel); } // Look through local category implementations associated with the class. if (!Setter) Setter = IFace->getCategoryInstanceMethod(SetterSel); if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); if (Getter || Setter) { QualType PType; if (Getter) PType = Getter->getSendResultType(); else { ParmVarDecl *ArgDecl = *Setter->param_begin(); PType = ArgDecl->getType(); } ExprValueKind VK = VK_LValue; ExprObjectKind OK = OK_ObjCProperty; if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() && PType->isVoidType()) VK = VK_RValue, OK = OK_Ordinary; if (Super) return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, PType, VK, OK, MemberLoc, SuperLoc, SuperType)); else return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, PType, VK, OK, MemberLoc, BaseExpr)); } // Attempt to correct for typos in property names. LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName); if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) && Res.getAsSingle<ObjCPropertyDecl>()) { DeclarationName TypoResult = Res.getLookupName(); Diag(MemberLoc, diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0) << TypoResult << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString()); ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) << Property->getDeclName(); return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc, SuperLoc, SuperType, Super); } ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = IFace->lookupInstanceVariable(Member, ClassDeclared)) { QualType T = Ivar->getType(); if (const ObjCObjectPointerType * OBJPT = T->getAsObjCInterfacePointerType()) { const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); if (ObjCInterfaceDecl *IFace = IFaceT->getDecl()) if (IFace->isForwardDecl()) { Diag(MemberLoc, diag::err_property_not_as_forward_class) << MemberName << IFace; Diag(IFace->getLocation(), diag::note_forward_class); return ExprError(); } } } Diag(MemberLoc, diag::err_property_not_found) << MemberName << QualType(OPT, 0); if (Setter) Diag(Setter->getLocation(), diag::note_getter_unavailable) << MemberName << BaseExpr->getSourceRange(); return ExprError(); }
void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, unsigned Indentation) { // Print DeclContext name. switch (DC->getDeclKind()) { case Decl::TranslationUnit: Out << "[translation unit] " << DC; break; case Decl::Namespace: { Out << "[namespace] "; const NamespaceDecl* ND = cast<NamespaceDecl>(DC); Out << ND->getNameAsString(); break; } case Decl::Enum: { const EnumDecl* ED = cast<EnumDecl>(DC); if (ED->isDefinition()) Out << "[enum] "; else Out << "<enum> "; Out << ED->getNameAsString(); break; } case Decl::Record: { const RecordDecl* RD = cast<RecordDecl>(DC); if (RD->isDefinition()) Out << "[struct] "; else Out << "<struct> "; Out << RD->getNameAsString(); break; } case Decl::CXXRecord: { const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC); if (RD->isDefinition()) Out << "[class] "; else Out << "<class> "; Out << RD->getNameAsString() << " " << DC; break; } case Decl::ObjCMethod: Out << "[objc method]"; break; case Decl::ObjCInterface: Out << "[objc interface]"; break; case Decl::ObjCCategory: Out << "[objc category]"; break; case Decl::ObjCProtocol: Out << "[objc protocol]"; break; case Decl::ObjCImplementation: Out << "[objc implementation]"; break; case Decl::ObjCCategoryImpl: Out << "[objc categoryimpl]"; break; case Decl::LinkageSpec: Out << "[linkage spec]"; break; case Decl::Block: Out << "[block]"; break; case Decl::Function: { const FunctionDecl* FD = cast<FunctionDecl>(DC); if (FD->isThisDeclarationADefinition()) Out << "[function] "; else Out << "<function> "; Out << FD->getNameAsString(); // Print the parameters. Out << "("; bool PrintComma = false; for (FunctionDecl::param_const_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { if (PrintComma) Out << ", "; else PrintComma = true; Out << (*I)->getNameAsString(); } Out << ")"; break; } case Decl::CXXMethod: { const CXXMethodDecl* D = cast<CXXMethodDecl>(DC); if (D->isOutOfLineDefinition()) Out << "[c++ method] "; else if (D->isImplicit()) Out << "(c++ method) "; else Out << "<c++ method> "; Out << D->getNameAsString(); // Print the parameters. Out << "("; bool PrintComma = false; for (FunctionDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) { if (PrintComma) Out << ", "; else PrintComma = true; Out << (*I)->getNameAsString(); } Out << ")"; // Check the semantic DeclContext. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::CXXConstructor: { const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC); if (D->isOutOfLineDefinition()) Out << "[c++ ctor] "; else if (D->isImplicit()) Out << "(c++ ctor) "; else Out << "<c++ ctor> "; Out << D->getNameAsString(); // Print the parameters. Out << "("; bool PrintComma = false; for (FunctionDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) { if (PrintComma) Out << ", "; else PrintComma = true; Out << (*I)->getNameAsString(); } Out << ")"; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::CXXDestructor: { const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC); if (D->isOutOfLineDefinition()) Out << "[c++ dtor] "; else if (D->isImplicit()) Out << "(c++ dtor) "; else Out << "<c++ dtor> "; Out << D->getNameAsString(); // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::CXXConversion: { const CXXConversionDecl* D = cast<CXXConversionDecl>(DC); if (D->isOutOfLineDefinition()) Out << "[c++ conversion] "; else if (D->isImplicit()) Out << "(c++ conversion) "; else Out << "<c++ conversion> "; Out << D->getNameAsString(); // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } default: assert(0 && "a decl that inherits DeclContext isn't handled"); } Out << "\n"; // Print decls in the DeclContext. // FIXME: Should not use a NULL DeclContext! ASTContext *Context = 0; for (DeclContext::decl_iterator I = DC->decls_begin(*Context), E = DC->decls_end(*Context); I != E; ++I) { for (unsigned i = 0; i < Indentation; ++i) Out << " "; Decl::Kind DK = I->getKind(); switch (DK) { case Decl::Namespace: case Decl::Enum: case Decl::Record: case Decl::CXXRecord: case Decl::ObjCMethod: case Decl::ObjCInterface: case Decl::ObjCCategory: case Decl::ObjCProtocol: case Decl::ObjCImplementation: case Decl::ObjCCategoryImpl: case Decl::LinkageSpec: case Decl::Block: case Decl::Function: case Decl::CXXMethod: case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: { DeclContext* DC = cast<DeclContext>(*I); PrintDeclContext(DC, Indentation+2); break; } case Decl::Field: { FieldDecl* FD = cast<FieldDecl>(*I); Out << "<field> " << FD->getNameAsString() << "\n"; break; } case Decl::Typedef: { TypedefDecl* TD = cast<TypedefDecl>(*I); Out << "<typedef> " << TD->getNameAsString() << "\n"; break; } case Decl::EnumConstant: { EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I); Out << "<enum constant> " << ECD->getNameAsString() << "\n"; break; } case Decl::Var: { VarDecl* VD = cast<VarDecl>(*I); Out << "<var> " << VD->getNameAsString() << "\n"; break; } case Decl::ImplicitParam: { ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I); Out << "<implicit parameter> " << IPD->getNameAsString() << "\n"; break; } case Decl::ParmVar: { ParmVarDecl* PVD = cast<ParmVarDecl>(*I); Out << "<parameter> " << PVD->getNameAsString() << "\n"; break; } case Decl::OriginalParmVar: { OriginalParmVarDecl* OPVD = cast<OriginalParmVarDecl>(*I); Out << "<original parameter> " << OPVD->getNameAsString() << "\n"; break; } case Decl::ObjCProperty: { ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); Out << "<objc property> " << OPD->getNameAsString() << "\n"; break; } default: fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName()); assert(0 && "decl unhandled"); } } }
static void checkAllAtProps(MigrationContext &MigrateCtx, SourceLocation AtLoc, IndivPropsTy &IndProps) { if (IndProps.empty()) return; for (IndivPropsTy::iterator PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { QualType T = (*PI)->getType(); if (T.isNull() || !T->isObjCRetainableType()) return; } SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs; bool hasWeak = false, hasStrong = false; ObjCPropertyDecl::PropertyAttributeKind Attrs = ObjCPropertyDecl::OBJC_PR_noattr; for (IndivPropsTy::iterator PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { ObjCPropertyDecl *PD = *PI; Attrs = PD->getPropertyAttributesAsWritten(); TypeSourceInfo *TInfo = PD->getTypeSourceInfo(); if (!TInfo) return; TypeLoc TL = TInfo->getTypeLoc(); if (AttributedTypeLoc ATL = TL.getAs<AttributedTypeLoc>()) { ATLs.push_back(std::make_pair(ATL, PD)); if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { hasWeak = true; } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) hasStrong = true; else return; } } if (ATLs.empty()) return; if (hasWeak && hasStrong) return; TransformActions &TA = MigrateCtx.Pass.TA; Transaction Trans(TA); if (GCAttrsCollector::hasObjCImpl( cast<Decl>(IndProps.front()->getDeclContext()))) { if (hasWeak) MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding()); } else { StringRef toAttr = "strong"; if (hasWeak) { if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(), /*AllowOnUnkwownClass=*/true)) toAttr = "weak"; else toAttr = "unsafe_unretained"; } if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc); else MigrateCtx.addPropertyAttribute(toAttr, AtLoc); } for (unsigned i = 0, e = ATLs.size(); i != e; ++i) { SourceLocation Loc = ATLs[i].first.getAttrNameLoc(); if (Loc.isMacroID()) Loc = MigrateCtx.Pass.Ctx.getSourceManager() .getImmediateExpansionRange(Loc).first; TA.remove(Loc); TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc); TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership, ATLs[i].second->getLocation()); MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding()); } }
static bool ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, const ObjCImplementationDecl *ImpDecl, const ObjCInterfaceDecl *IDecl, ObjCProtocolDecl *Protocol) { // In auto-synthesis, protocol properties are not synthesized. So, // a conforming protocol must have its required properties declared // in class interface. bool HasAtleastOneRequiredProperty = false; if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { ObjCPropertyDecl *Property = *P; if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) continue; HasAtleastOneRequiredProperty = true; DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); if (R.size() == 0) { // Relax the rule and look into class's implementation for a synthesize // or dynamic declaration. Class is implementing a property coming from // another protocol. This still makes the target protocol as conforming. if (!ImpDecl->FindPropertyImplDecl( Property->getDeclName().getAsIdentifierInfo())) return false; } else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) { if ((ClassProperty->getPropertyAttributes() != Property->getPropertyAttributes()) || !Ctx.hasSameType(ClassProperty->getType(), Property->getType())) return false; } else return false; } // At this point, all required properties in this protocol conform to those // declared in the class. // Check that class implements the required methods of the protocol too. bool HasAtleastOneRequiredMethod = false; if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) { if (PDecl->meth_begin() == PDecl->meth_end()) return HasAtleastOneRequiredProperty; for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(), MEnd = PDecl->meth_end(); M != MEnd; ++M) { ObjCMethodDecl *MD = (*M); if (MD->isImplicit()) continue; if (MD->getImplementationControl() == ObjCMethodDecl::Optional) continue; DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); if (R.size() == 0) return false; bool match = false; HasAtleastOneRequiredMethod = true; for (unsigned I = 0, N = R.size(); I != N; ++I) if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0])) if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { match = true; break; } if (!match) return false; } } if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod) return true; return false; }
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an /// objective C interface. This is a property reference expression. Action::OwningExprResult Sema:: HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, DeclarationName MemberName, SourceLocation MemberLoc) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); // Search for a declared property first. if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); QualType ResTy = PD->getType(); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) ResTy = Getter->getSendResultType(); return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, MemberLoc, BaseExpr)); } // Check protocols on qualified interfaces. for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), MemberLoc, BaseExpr)); } // If that failed, look for an "implicit" property by seeing if the nullary // selector is implemented. // FIXME: The logic for looking up nullary and unary selectors should be // shared with the code in ActOnInstanceMessage. Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); // If this reference is in an @implementation, check for 'private' methods. if (!Getter) Getter = IFace->lookupPrivateInstanceMethod(Sel); // Look through local category implementations associated with the class. if (!Getter) Getter = IFace->getCategoryInstanceMethod(Sel); if (Getter) { // Check if we can reference this property. if (DiagnoseUseOfDecl(Getter, MemberLoc)) return ExprError(); } // If we found a getter then this may be a valid dot-reference, we // will look for the matching setter, in case it is needed. Selector SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. Setter = IFace->lookupPrivateInstanceMethod(SetterSel); } // Look through local category implementations associated with the class. if (!Setter) Setter = IFace->getCategoryInstanceMethod(SetterSel); if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); if (Getter) { QualType PType; PType = Getter->getSendResultType(); return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } // Attempt to correct for typos in property names. LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName); if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) && Res.getAsSingle<ObjCPropertyDecl>()) { DeclarationName TypoResult = Res.getLookupName(); Diag(MemberLoc, diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0) << TypoResult << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString()); ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) << Property->getDeclName(); return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc); } Diag(MemberLoc, diag::err_property_not_found) << MemberName << QualType(OPT, 0); if (Setter && !Getter) Diag(Setter->getLocation(), diag::note_getter_unavailable) << MemberName << BaseExpr->getSourceRange(); return ExprError(); }