// FIXME: A callback should disable checkers at the start of functions. static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { if (!ND) return false; const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND); if (!MD) return false; if (!isInitializationMethod(MD)) return false; // self = [super init] applies only to NSObject subclasses. // For instance, NSProxy doesn't implement -init. ASTContext &Ctx = MD->getASTContext(); IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass(); for ( ; ID ; ID = ID->getSuperClass()) { IdentifierInfo *II = ID->getIdentifier(); if (II == NSObjectII) break; } if (!ID) return false; return true; }
bool VisitObjCMessageExpr(ObjCMessageExpr *objCMsgExpr) { ObjCInterfaceDecl *objCInterfaceDecl = objCMsgExpr->getReceiverInterface(); string selectorString = objCMsgExpr->getSelector().getAsString(); vector<string> arraySelectors; arraySelectors.push_back("array"); arraySelectors.push_back("arrayWithObject:"); arraySelectors.push_back("arrayWithObjects:count:"); arraySelectors.push_back("arrayWithObjects:"); vector<string> dictionarySelectors; dictionarySelectors.push_back("dictionary"); dictionarySelectors.push_back("dictionaryWithObject:forKey:"); dictionarySelectors.push_back("dictionaryWithObjects:forKeys:count:"); dictionarySelectors.push_back("dictionaryWithObjectsAndKeys:"); dictionarySelectors.push_back("dictionaryWithObjects:forKeys:"); if (objCInterfaceDecl && ((objCInterfaceDecl->getNameAsString() == "NSArray" && vectorContains<string>(selectorString, arraySelectors)) || (objCInterfaceDecl->getNameAsString() == "NSDictionary" && vectorContains<string>(selectorString, dictionarySelectors)))) { addViolation(objCMsgExpr, this); } return true; }
bool trans::canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass) { if (!Ctx.getLangOptions().ObjCRuntimeHasWeak) return false; QualType T = type; if (T.isNull()) return false; while (const PointerType *ptr = T->getAs<PointerType>()) T = ptr->getPointeeType(); if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) return false; // id/NSObject is not safe for weak. if (!AllowOnUnknownClass && Class->isForwardDecl()) return false; // forward classes are not verifiable, therefore not safe. if (Class->isArcWeakrefUnavailable()) return false; if (isClassInWeakBlacklist(Class)) return false; } return true; }
bool trans::canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass) { if (!Ctx.getLangOpts().ObjCARCWeak) return false; QualType T = type; if (T.isNull()) return false; // iOS is always safe to use 'weak'. if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS) AllowOnUnknownClass = true; while (const PointerType *ptr = T->getAs<PointerType>()) T = ptr->getPointeeType(); if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) return false; // id/NSObject is not safe for weak. if (!AllowOnUnknownClass && !Class->hasDefinition()) return false; // forward classes are not verifiable, therefore not safe. if (Class && Class->isArcWeakrefUnavailable()) return false; } return true; }
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return 0; if (data().ExternallyCompleted) LoadExternalDefinition(); ObjCInterfaceDecl* ClassDecl = this; while (ClassDecl != NULL) { if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); CDecl; CDecl = CDecl->getNextClassExtension()) { if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } } ClassDecl = ClassDecl->getSuperClass(); } return NULL; }
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) { std::string I = OID->getName(); ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) Out << "@implementation " << I << " : " << SID->getName(); else Out << "@implementation " << I; for (ObjCImplementationDecl::instmeth_iterator I = OID->instmeth_begin(), E = OID->instmeth_end(); I != E; ++I) { ObjCMethodDecl *OMD = *I; PrintObjCMethodDecl(OMD); if (OMD->getBody()) { Out << ' '; OMD->getBody()->printPretty(Out); Out << '\n'; } } for (ObjCImplementationDecl::classmeth_iterator I = OID->classmeth_begin(), E = OID->classmeth_end(); I != E; ++I) { ObjCMethodDecl *OMD = *I; PrintObjCMethodDecl(OMD); if (OMD->getBody()) { Out << ' '; OMD->getBody()->printPretty(Out); Out << '\n'; } } Out << "@end\n"; }
/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super /// class whose name is passed as argument. If it is not one of the super classes /// the it returns NULL. ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( const IdentifierInfo*ICName) { ObjCInterfaceDecl* ClassDecl = this; while (ClassDecl != NULL) { if (ClassDecl->getIdentifier() == ICName) return ClassDecl; ClassDecl = ClassDecl->getSuperClass(); } return NULL; }
void CGObjCJit::GenerateClass(const ObjCImplementationDecl *ClassDecl) { if (isUsable) { const char* ClassName = ClassDecl->getIdentifier()->getNameStart(); void* Superclass = 0; ObjCInterfaceDecl *superClassDecl = ClassDecl->getClassInterface()->getSuperClass(); if (superClassDecl) { const char* superClassName = superClassDecl->getIdentifier()->getNameStart(); Superclass = _objc_getClass(superClassName); } void *theClass = _objc_allocateClassPair(Superclass, ClassName, 0); // TODO: always zero? // Add methods AddMethodsToClass(theClass); // Add interface ivars const ObjCInterfaceDecl *classInterfaceDecl = ClassDecl->getClassInterface(); AddIvarsToClass(theClass, classInterfaceDecl->ivar_begin(), classInterfaceDecl->ivar_end()); // Add implementation ivars AddIvarsToClass(theClass, ClassDecl->ivar_begin(), ClassDecl->ivar_end()); // Add protocols ObjCInterfaceDecl::protocol_iterator protocol = classInterfaceDecl->protocol_begin(); const ObjCInterfaceDecl::protocol_iterator protocol_end = classInterfaceDecl->protocol_end(); while (protocol != protocol_end) { void *theProtocol = 0; // Search "locally" first, then from runtime llvm::StringMap<void*>::iterator proto_local = DefinedProtocols.find((*protocol)->getName()); if (proto_local != DefinedProtocols.end()) { theProtocol = proto_local->second; } else { theProtocol = _objc_getProtocol((*protocol)->getNameAsString().c_str()); } _class_addProtocol(theClass, theProtocol); protocol++; } // Finalize class (adding methods later, at runtime, in init function) _objc_registerClassPair(theClass); } }
bool VisitObjCMessageExpr(ObjCMessageExpr *objCMsgExpr) { ObjCInterfaceDecl *objCInterfaceDecl = objCMsgExpr->getReceiverInterface(); if (objCInterfaceDecl && objCInterfaceDecl->getNameAsString() == "NSNumber" && objCMsgExpr->getNumArgs() == 1 && canSimplify(objCMsgExpr)) { addViolation(objCMsgExpr, this); } return true; }
void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { ObjCInterfaceDecl* ID = D->getClassInterface(); IvarUsageMap M; ASTContext &Ctx = BR.getContext(); // Iterate over the ivars. for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); I!=E; ++I) { ObjCIvarDecl* ID = *I; // Ignore ivars that aren't private. if (ID->getAccessControl() != ObjCIvarDecl::Private) continue; // Skip IB Outlets. if (ID->getAttr<IBOutletAttr>()) continue; M[ID] = Unused; } if (M.empty()) return; // Now scan the methods for accesses. for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(Ctx), E = D->instmeth_end(Ctx); I!=E; ++I) Scan(M, (*I)->getBody(Ctx)); // Scan for @synthesized property methods that act as setters/getters // to an ivar. for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(Ctx), E = D->propimpl_end(Ctx); I!=E; ++I) Scan(M, *I); // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { std::ostringstream os; os << "Instance variable '" << I->first->getNameAsString() << "' in class '" << ID->getNameAsString() << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; BR.EmitBasicReport("Unused instance variable", "Optimization", os.str().c_str(), I->first->getLocation()); } }
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { switch (D->getKind()) { default: llvm_unreachable("Invalid ObjC container."); case Decl::ObjCInterface: case Decl::ObjCImplementation: GenObjCClass(D->getName()); break; case Decl::ObjCCategory: { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); ObjCInterfaceDecl *ID = CD->getClassInterface(); if (!ID) { // Handle invalid code where the @interface might not // have been specified. // FIXME: We should be able to generate this USR even if the // @interface isn't available. IgnoreResults = true; return; } // Specially handle class extensions, which are anonymous categories. // We want to mangle in the location to uniquely distinguish them. if (CD->IsClassExtension()) { Out << "objc(ext)" << ID->getName() << '@'; GenLoc(CD); } else GenObjCCategory(ID->getName(), CD->getName()); break; } case Decl::ObjCCategoryImpl: { ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); ObjCInterfaceDecl *ID = CD->getClassInterface(); if (!ID) { // Handle invalid code where the @interface might not // have been specified. // FIXME: We should be able to generate this USR even if the // @interface isn't available. IgnoreResults = true; return; } GenObjCCategory(ID->getName(), CD->getName()); break; } case Decl::ObjCProtocol: GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName()); break; } }
void DeclPrinter::PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID) { std::string I = OID->getNameAsString(); ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) Out << "@interface " << I << " : " << SID->getNameAsString(); else Out << "@interface " << I; // Protocols? const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); if (!Protocols.empty()) { for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); } if (!Protocols.empty()) Out << ">"; Out << '\n'; if (OID->ivar_size() > 0) { Out << '{'; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { Out << '\t' << (*I)->getType().getAsString() << ' ' << (*I)->getNameAsString() << ";\n"; } Out << "}\n"; } // FIXME: Should not use a NULL DeclContext! ASTContext *Context = 0; for (ObjCInterfaceDecl::prop_iterator I = OID->prop_begin(*Context), E = OID->prop_end(*Context); I != E; ++I) PrintObjCPropertyDecl(*I); bool eol_needed = false; for (ObjCInterfaceDecl::classmeth_iterator I = OID->classmeth_begin(*Context), E = OID->classmeth_end(*Context); I != E; ++I) eol_needed = true, PrintObjCMethodDecl(*I); for (ObjCInterfaceDecl::instmeth_iterator I = OID->instmeth_begin(*Context), E = OID->instmeth_end(*Context); I != E; ++I) eol_needed = true, PrintObjCMethodDecl(*I); Out << (eol_needed ? "\n@end\n" : "@end\n"); // FIXME: implement the rest... }
ExprResult Sema::ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, SourceLocation SelectorLoc, SourceLocation RBracLoc, MultiExprArg Args) { // Determine whether we are inside a method or not. ObjCMethodDecl *Method = tryCaptureObjCSelf(); if (!Method) { Diag(SuperLoc, diag::err_invalid_receiver_to_message_super); return ExprError(); } ObjCInterfaceDecl *Class = Method->getClassInterface(); if (!Class) { Diag(SuperLoc, diag::error_no_super_class_message) << Method->getDeclName(); return ExprError(); } ObjCInterfaceDecl *Super = Class->getSuperClass(); if (!Super) { // The current class does not have a superclass. Diag(SuperLoc, diag::error_root_class_cannot_use_super) << Class->getIdentifier(); return ExprError(); } // We are in a method whose class has a superclass, so 'super' // is acting as a keyword. if (Method->isInstanceMethod()) { // Since we are in an instance method, this is an instance // message to the superclass instance. QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(0, SuperTy, SuperLoc, Sel, /*Method=*/0, LBracLoc, SelectorLoc, RBracLoc, move(Args)); } // Since we are in a class method, this is a class message to // the superclass. return BuildClassMessage(/*ReceiverTypeInfo=*/0, Context.getObjCInterfaceType(Super), SuperLoc, Sel, /*Method=*/0, LBracLoc, SelectorLoc, RBracLoc, move(Args)); }
/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super /// class whose name is passed as argument. If it is not one of the super classes /// the it returns NULL. ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( const IdentifierInfo*ICName) { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return 0; if (data().ExternallyCompleted) LoadExternalDefinition(); ObjCInterfaceDecl* ClassDecl = this; while (ClassDecl != NULL) { if (ClassDecl->getIdentifier() == ICName) return ClassDecl; ClassDecl = ClassDecl->getSuperClass(); } return NULL; }
static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter, const ObjCMethodDecl *Setter, const NSAPI &NS, edit::Commit &commit) { ASTContext &Context = NS.getASTContext(); std::string PropertyString = "@property"; const ParmVarDecl *argDecl = *Setter->param_begin(); QualType ArgType = Context.getCanonicalType(argDecl->getType()); Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime(); if (ArgType->isObjCRetainableType() && propertyLifetime == Qualifiers::OCL_Strong) { if (const ObjCObjectPointerType *ObjPtrTy = ArgType->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); if (IDecl && IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) PropertyString += "(copy)"; } } else if (propertyLifetime == Qualifiers::OCL_Weak) // TODO. More precise determination of 'weak' attribute requires // looking into setter's implementation for backing weak ivar. PropertyString += "(weak)"; else PropertyString += "(unsafe_unretained)"; // strip off any ARC lifetime qualifier. QualType CanResultTy = Context.getCanonicalType(Getter->getResultType()); if (CanResultTy.getQualifiers().hasObjCLifetime()) { Qualifiers Qs = CanResultTy.getQualifiers(); Qs.removeObjCLifetime(); CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); } PropertyString += " "; PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy()); PropertyString += " "; PropertyString += Getter->getNameAsString(); commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), Getter->getDeclaratorEndLoc()), PropertyString); SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); // Get location past ';' EndLoc = EndLoc.getLocWithOffset(1); commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc)); return true; }
void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl, ObjCMethodDecl *OM) { ObjCInstanceTypeFamily OIT_Family = Selector::getInstTypeMethodFamily(OM->getSelector()); if (OIT_Family == OIT_None) return; // TODO. Many more to come switch (OIT_Family) { case OIT_Array: break; case OIT_Dictionary: break; default: return; } if (!OM->getResultType()->isObjCIdType()) return; ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); if (!IDecl) { if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) IDecl = CatDecl->getClassInterface(); else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) IDecl = ImpDecl->getClassInterface(); } if (!IDecl) return; if (OIT_Family == OIT_Array && !IDecl->lookupInheritedClass(&Ctx.Idents.get("NSArray"))) return; else if (OIT_Family == OIT_Dictionary && !IDecl->lookupInheritedClass(&Ctx.Idents.get("NSDictionary"))) return; TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo(); TypeLoc TL = TSInfo->getTypeLoc(); SourceRange R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); edit::Commit commit(*Editor); std::string ClassString = "instancetype"; commit.replace(R, ClassString); Editor->commit(commit); }
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) { std::string I = OID->getNameAsString(); ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) Out << "@implementation " << I << " : " << SID->getNameAsString(); else Out << "@implementation " << I; // FIXME: Don't use a NULL context ASTContext *Context = 0; for (ObjCImplementationDecl::instmeth_iterator I = OID->instmeth_begin(*Context), E = OID->instmeth_end(*Context); I != E; ++I) { ObjCMethodDecl *OMD = *I; PrintObjCMethodDecl(OMD); if (OMD->getBody()) { Out << ' '; OMD->getBody()->printPretty(Out); Out << '\n'; } } for (ObjCImplementationDecl::classmeth_iterator I = OID->classmeth_begin(*Context), E = OID->classmeth_end(*Context); I != E; ++I) { ObjCMethodDecl *OMD = *I; PrintObjCMethodDecl(OMD); if (OMD->getBody()) { Out << ' '; OMD->getBody()->printPretty(Out); Out << '\n'; } } for (ObjCImplementationDecl::propimpl_iterator I = OID->propimpl_begin(*Context), E = OID->propimpl_end(*Context); I != E; ++I) PrintObjCPropertyImplDecl(*I); Out << "@end\n"; }
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; while (ClassDecl != NULL) { if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); CDecl; CDecl = CDecl->getNextClassExtension()) { if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } } ClassDecl = ClassDecl->getSuperClass(); } return NULL; }
bool VisitObjCMessageExpr(ObjCMessageExpr *objCMsgExpr) { string selectorString = objCMsgExpr->getSelector().getAsString(); vector<string> selectorStrings; selectorStrings.push_back("raise"); selectorStrings.push_back("raise:format:"); selectorStrings.push_back("raise:format:arguments:"); bool isRaiseMethod = vectorContains<string>(selectorString, selectorStrings); ObjCInterfaceDecl *objCInterfaceDecl = objCMsgExpr->getReceiverInterface(); bool isNSExceptionClass = objCInterfaceDecl && objCInterfaceDecl->getNameAsString() == "NSException"; if (isRaiseMethod && isNSExceptionClass) { _raisers->push_back(objCMsgExpr); } return true; }
ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized // properties). // // FIXME: This should really be asserting this: // (isa<ObjCCategoryDecl>(DC) && // cast<ObjCCategoryDecl>(DC)->IsClassExtension())) // but unfortunately we sometimes place ivars into non-class extension // categories on error. This breaks an AST invariant, and should not be // fixed. assert((isa<ObjCInterfaceDecl>(DC) || isa<ObjCImplementationDecl>(DC) || isa<ObjCCategoryDecl>(DC)) && "Invalid ivar decl context!"); // Once a new ivar is created in any of class/class-extension/implementation // decl contexts, the previously built IvarList must be rebuilt. ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(DC); if (!ID) { if (ObjCImplementationDecl *IM = dyn_cast<ObjCImplementationDecl>(DC)) { ID = IM->getClassInterface(); if (BW) IM->setHasSynthBitfield(true); } else { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(DC); ID = CD->getClassInterface(); if (BW) CD->setHasSynthBitfield(true); } } ID->setIvarList(0); } return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, ac, BW, synthesized); }
/// ClassImplementsProtocol - Checks that 'lProto' protocol /// has been implemented in IDecl class, its super class or categories (if /// lookupCategory is true). bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, bool lookupCategory, bool RHSIsQualifiedID) { ObjCInterfaceDecl *IDecl = this; // 1st, look up the class. const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), E = Protocols.end(); PI != E; ++PI) { if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) return true; // This is dubious and is added to be compatible with gcc. In gcc, it is // also allowed assigning a protocol-qualified 'id' type to a LHS object // when protocol in qualified LHS is in list of protocols in the rhs 'id' // object. This IMO, should be a bug. // FIXME: Treat this as an extension, and flag this as an error when GCC // extensions are not enabled. if (RHSIsQualifiedID && getASTContext().ProtocolCompatibleWithProtocol(*PI, lProto)) return true; } // 2nd, look up the category. if (lookupCategory) for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; CDecl = CDecl->getNextClassCategory()) { for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), E = CDecl->protocol_end(); PI != E; ++PI) if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) return true; } // 3rd, look up the super class(s) if (IDecl->getSuperClass()) return IDecl->getSuperClass()->ClassImplementsProtocol(lProto, lookupCategory, RHSIsQualifiedID); return false; }
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { switch (D->getKind()) { default: assert(false && "Invalid ObjC container."); case Decl::ObjCInterface: case Decl::ObjCImplementation: GenObjCClass(D->getName()); break; case Decl::ObjCCategory: { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); ObjCInterfaceDecl *ID = CD->getClassInterface(); if (!ID) { // Handle invalid code where the @interface might not // have been specified. // FIXME: We should be able to generate this USR even if the // @interface isn't available. IgnoreResults = true; return; } GenObjCCategory(ID->getName(), CD->getName()); break; } case Decl::ObjCCategoryImpl: { ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); ObjCInterfaceDecl *ID = CD->getClassInterface(); if (!ID) { // Handle invalid code where the @interface might not // have been specified. // FIXME: We should be able to generate this USR even if the // @interface isn't available. IgnoreResults = true; return; } GenObjCCategory(ID->getName(), CD->getName()); break; } case Decl::ObjCProtocol: GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName()); break; } }
/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info /// for the given Objective-C object type. void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) { // Drop qualifiers. const Type *T = OT->getBaseType().getTypePtr(); assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T)); // The builtin types are abi::__class_type_infos and don't require // extra fields. if (isa<BuiltinType>(T)) return; ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl(); ObjCInterfaceDecl *Super = Class->getSuperClass(); // Root classes are also __class_type_info. if (!Super) return; QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super); // Everything else is single inheritance. llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy); Fields.push_back(BaseTypeInfo); }
virtual bool VisitObjCMessageExpr(ObjCMessageExpr *E) { if (E->getReceiverKind() == ObjCMessageExpr::Class) { QualType ReceiverType = E->getClassReceiver(); Selector Sel = E->getSelector(); string TypeName = ReceiverType.getAsString(); string SelName = Sel.getAsString(); if (TypeName == "Observer" && SelName == "observerWithTarget:action:") { Expr *Receiver = E->getArg(0)->IgnoreParenCasts(); ObjCSelectorExpr* SelExpr = cast<ObjCSelectorExpr>(E->getArg(1)->IgnoreParenCasts()); Selector Sel = SelExpr->getSelector(); if (const ObjCObjectPointerType *OT = Receiver->getType()->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *decl = OT->getInterfaceDecl(); if (! decl->lookupInstanceMethod(Sel)) { errs() << "Warning: class " << TypeName << " does not implement selector " << Sel.getAsString() << "\n"; SourceLocation Loc = E->getExprLoc(); PresumedLoc PLoc = astContext->getSourceManager().getPresumedLoc(Loc); errs() << "in " << PLoc.getFilename() << " <" << PLoc.getLine() << ":" << PLoc.getColumn() << ">\n"; } } } } return true; }
/// 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; }
/// \param ReceiverType The type of the object receiving the /// message. When \p ReceiverTypeInfo is non-NULL, this is the same /// type as that refers to. For a superclass send, this is the type of /// the superclass. /// /// \param SuperLoc The location of the "super" keyword in a /// superclass message. /// /// \param Sel The selector to which the message is being sent. /// /// \param Method The method that this class message is invoking, if /// already known. /// /// \param LBracLoc The location of the opening square bracket ']'. /// /// \param RBrac The location of the closing square bracket ']'. /// /// \param Args The message arguments. ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, SourceLocation SelectorLoc, SourceLocation RBracLoc, MultiExprArg ArgsIn) { SourceLocation Loc = SuperLoc.isValid()? SuperLoc : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); if (LBracLoc.isInvalid()) { Diag(Loc, diag::err_missing_open_square_message_send) << FixItHint::CreateInsertion(Loc, "["); LBracLoc = Loc; } if (ReceiverType->isDependentType()) { // If the receiver type is dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, ReceiverType, VK_RValue, LBracLoc, ReceiverTypeInfo, Sel, SelectorLoc, /*Method=*/0, Args, NumArgs, RBracLoc)); } // Find the class to which we are sending this message. ObjCInterfaceDecl *Class = 0; const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>(); if (!ClassType || !(Class = ClassType->getInterface())) { Diag(Loc, diag::err_invalid_receiver_class_message) << ReceiverType; return ExprError(); } assert(Class && "We don't know which class we're messaging?"); (void)DiagnoseUseOfDecl(Class, Loc); // Find the method we are messaging. if (!Method) { if (Class->isForwardDecl()) { // A forward class used in messaging is treated as a 'Class' Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName(); Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); if (Method) Diag(Method->getLocation(), diag::note_method_sent_forward_class) << Method->getDeclName(); } if (!Method) Method = Class->lookupClassMethod(Sel); // If we have an implementation in scope, check "private" methods. if (!Method) Method = LookupPrivateClassMethod(Sel, Class); if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } // Check the argument types and determine the result type. QualType ReturnType; ExprValueKind VK = VK_RValue; unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); if (Method && !Method->getResultType()->isVoidType() && RequireCompleteType(LBracLoc, Method->getResultType(), diag::err_illegal_message_expr_incomplete_type)) return ExprError(); // Construct the appropriate ObjCMessageExpr. Expr *Result; if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false, ReceiverType, Sel, SelectorLoc, Method, Args, NumArgs, RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, ReceiverTypeInfo, Sel, SelectorLoc, Method, Args, NumArgs, RBracLoc); return MaybeBindToTemporary(Result); }
StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) { NamedDecl *ND = dyn_cast<NamedDecl>(DC); if (!ND) return StringRef(); // Check whether we've already cached the parent name. StringRef &CachedParentName = ParentNames[DC]; if (!CachedParentName.empty()) return CachedParentName; // If we already processed this DeclContext and assigned empty to it, the // data pointer will be non-null. if (CachedParentName.data() != 0) return StringRef(); // Find the interesting names. llvm::SmallVector<DeclContext *, 2> Contexts; while (DC && !DC->isFunctionOrMethod()) { if (NamedDecl *ND = dyn_cast<NamedDecl>(DC)) { if (ND->getIdentifier()) Contexts.push_back(DC); } DC = DC->getParent(); } { llvm::SmallString<128> S; llvm::raw_svector_ostream OS(S); bool First = true; for (unsigned I = Contexts.size(); I != 0; --I) { if (First) First = false; else { OS << "::"; } DeclContext *CurDC = Contexts[I-1]; if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC)) CurDC = CatImpl->getCategoryDecl(); if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) { ObjCInterfaceDecl *Interface = Cat->getClassInterface(); if (!Interface) { // Assign an empty StringRef but with non-null data to distinguish // between empty because we didn't process the DeclContext yet. CachedParentName = StringRef((const char *)~0U, 0); return StringRef(); } OS << Interface->getName() << '(' << Cat->getName() << ')'; } else { OS << cast<NamedDecl>(CurDC)->getName(); } } CachedParentName = AllocatorRef->CopyString(OS.str()); } return CachedParentName; }
ExprResult Sema:: ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc) { IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); if (IFace == 0) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. if (receiverNamePtr->isStr("super")) { if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) { if (CurMethod->isInstanceMethod()) { QualType T = Context.getObjCInterfaceType(CurMethod->getClassInterface()); T = Context.getObjCObjectPointerType(T); return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), /*BaseExpr*/0, &propertyName, propertyNameLoc, receiverNameLoc, T, true); } // Otherwise, if this is a class method, try dispatching to our // superclass. IFace = CurMethod->getClassInterface()->getSuperClass(); } } if (IFace == 0) { Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); return ExprError(); } } // Search for a declared property first. Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel); // If this reference is in an @implementation, check for 'private' methods. if (!Getter) if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) Getter = ImpDecl->getClassMethod(Sel); if (Getter) { // FIXME: refactor/share with ActOnMemberReference(). // Check if we can reference this property. if (DiagnoseUseOfDecl(Getter, propertyNameLoc)) return ExprError(); } // Look for the matching setter, in case it is needed. Selector SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName); ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) Setter = ImpDecl->getClassMethod(SetterSel); } // Look through local category implementations associated with the class. if (!Setter) Setter = IFace->getCategoryClassMethod(SetterSel); if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc)) return ExprError(); if (Getter || Setter) { QualType PType; ExprValueKind VK = VK_LValue; if (Getter) { PType = Getter->getSendResultType(); if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() && PType->isVoidType()) VK = VK_RValue; } else { for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), E = Setter->param_end(); PI != E; ++PI) PType = (*PI)->getType(); VK = VK_LValue; } ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, PType, VK, OK, propertyNameLoc, receiverNameLoc, IFace)); } return ExprError(Diag(propertyNameLoc, diag::err_property_not_found) << &propertyName << Context.getObjCInterfaceType(IFace)); }
/// 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(); }
/// \brief Build an Objective-C instance message expression. /// /// This routine takes care of both normal instance messages and /// instance messages to the superclass instance. /// /// \param Receiver The expression that computes the object that will /// receive this message. This may be empty, in which case we are /// sending to the superclass instance and \p SuperLoc must be a valid /// source location. /// /// \param ReceiverType The (static) type of the object receiving the /// message. When a \p Receiver expression is provided, this is the /// same type as that expression. For a superclass instance send, this /// is a pointer to the type of the superclass. /// /// \param SuperLoc The location of the "super" keyword in a /// superclass instance message. /// /// \param Sel The selector to which the message is being sent. /// /// \param Method The method that this instance message is invoking, if /// already known. /// /// \param LBracLoc The location of the opening square bracket ']'. /// /// \param RBrac The location of the closing square bracket ']'. /// /// \param Args The message arguments. ExprResult Sema::BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, SourceLocation SelectorLoc, SourceLocation RBracLoc, MultiExprArg ArgsIn) { // The location of the receiver. SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); if (LBracLoc.isInvalid()) { Diag(Loc, diag::err_missing_open_square_message_send) << FixItHint::CreateInsertion(Loc, "["); LBracLoc = Loc; } // If we have a receiver expression, perform appropriate promotions // and determine receiver type. if (Receiver) { if (Receiver->isTypeDependent()) { // If the receiver is type-dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, VK_RValue, LBracLoc, Receiver, Sel, SelectorLoc, /*Method=*/0, Args, NumArgs, RBracLoc)); } // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. DefaultFunctionArrayLvalueConversion(Receiver); ReceiverType = Receiver->getType(); } if (!Method) { // Handle messages to id. bool receiverIsId = ReceiverType->isObjCIdType(); if (receiverIsId || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), receiverIsId); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), receiverIsId); } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { // First check the public methods in the class interface. Method = ClassDecl->lookupClassMethod(Sel); if (!Method) Method = LookupPrivateClassMethod(Sel, ClassDecl); // FIXME: if we still haven't found a method, we need to look in // protocols (if we have qualifiers). } if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); if (!Method) { // If no class (factory) method was found, check if an _instance_ // method of the same name exists in the root class only. Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); if (Method) if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { if (ID->getSuperClass()) Diag(Loc, diag::warn_root_inst_method_not_found) << Sel << SourceRange(LBracLoc, RBracLoc); } } } } } else { ObjCInterfaceDecl* ClassDecl = 0; // We allow sending a message to a qualified ID ("id<foo>"), which is ok as // long as one of the protocols implements the selector (if not, warn). if (const ObjCObjectPointerType *QIdTy = ReceiverType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. Method = LookupMethodInQualifiedType(Sel, QIdTy, true); if (!Method) Method = LookupMethodInQualifiedType(Sel, QIdTy, false); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). ClassDecl = OCIType->getInterfaceDecl(); // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). // The idea is to add class info to MethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); if (!Method) // Search protocol qualifiers. Method = LookupMethodInQualifiedType(Sel, OCIType, true); bool forwardClass = false; if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); if (!Method && (!Receiver || !isSelfExpr(Receiver))) { // If we still haven't found a method, look in the global pool. This // behavior isn't very desirable, however we need it for GCC // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); forwardClass = OCIType->getInterfaceDecl()->isForwardDecl(); if (Method && !forwardClass) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; } } } if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && (ReceiverType->isPointerType() || ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) ImpCastExprToType(Receiver, Context.getObjCIdType(), CK_BitCast); else { // TODO: specialized warning on null receivers? bool IsNull = Receiver->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); ImpCastExprToType(Receiver, Context.getObjCIdType(), IsNull ? CK_NullToPointer : CK_IntegralToPointer); } ReceiverType = Receiver->getType(); } else if (getLangOptions().CPlusPlus && !PerformContextuallyConvertToObjCId(Receiver)) { if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { Receiver = ICE->getSubExpr(); ReceiverType = Receiver->getType(); } return BuildInstanceMessage(Receiver, ReceiverType, SuperLoc, Sel, Method, LBracLoc, SelectorLoc, RBracLoc, move(ArgsIn)); } else { // Reject other random receiver types (e.g. structs). Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); return ExprError(); } } } // Check the message arguments. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); QualType ReturnType; ExprValueKind VK = VK_RValue; bool ClassMessage = (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()); if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage, LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); if (Method && !Method->getResultType()->isVoidType() && RequireCompleteType(LBracLoc, Method->getResultType(), diag::err_illegal_message_expr_incomplete_type)) return ExprError(); // Construct the appropriate ObjCMessageExpr instance. Expr *Result; if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, ReceiverType, Sel, SelectorLoc, Method, Args, NumArgs, RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLoc, Method, Args, NumArgs, RBracLoc); return MaybeBindToTemporary(Result); }