/// 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(); }
/// CreateType - get objective-c interface type. llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit Unit) { ObjCInterfaceDecl *Decl = Ty->getDecl(); unsigned Tag = llvm::dwarf::DW_TAG_structure_type; SourceManager &SM = M->getContext().getSourceManager(); // Get overall information about the record type for the debug info. std::string Name = Decl->getNameAsString(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); unsigned Line = SM.getInstantiationLineNumber(Decl->getLocation()); // To handle recursive interface, we // first generate a debug descriptor for the struct as a forward declaration. // Then (if it is a definition) we go through and get debug info for all of // its members. Finally, we create a descriptor for the complete type (which // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DIType FwdDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. if (Decl->isForwardDecl()) return FwdDecl; // Otherwise, insert it into the TypeCache so that recursive uses will find // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; ObjCInterfaceDecl *SClass = Decl->getSuperClass(); if (SClass) { llvm::DIType SClassTy = getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit); llvm::DIType InhTag = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, Unit, "", Unit, 0, 0, 0, 0 /* offset */, 0, SClassTy); EltTys.push_back(InhTag); } const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl); unsigned FieldNo = 0; for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(), E = Decl->ivar_end(); I != E; ++I, ++FieldNo) { ObjCIvarDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); std::string FieldName = Field->getNameAsString(); // Get the location for the field. SourceLocation FieldDefLoc = Field->getLocation(); llvm::DICompileUnit FieldDefUnit = getOrCreateCompileUnit(FieldDefLoc); unsigned FieldLine = SM.getInstantiationLineNumber(FieldDefLoc); QualType FType = Field->getType(); uint64_t FieldSize = 0; unsigned FieldAlign = 0; if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. FieldSize = M->getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) FieldSize = BitWidth->getIntegerConstantExprValue(M->getContext()).getZExtValue(); FieldAlign = M->getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); unsigned Flags = 0; if (Field->getAccessControl() == ObjCIvarDecl::Protected) Flags = llvm::DIType::FlagProtected; else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DIType::FlagPrivate; // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, FieldOffset, Flags, FieldTy); EltTys.push_back(FieldTy); } llvm::DIArray Elements = DebugFactory.GetOrCreateArray(&EltTys[0], EltTys.size()); // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); llvm::DIType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. FwdDecl.getGV()->replaceAllUsesWith(RealDecl.getGV()); FwdDecl.getGV()->eraseFromParent(); return RealDecl; }