diff options
Diffstat (limited to 'lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 172 |
1 files changed, 142 insertions, 30 deletions
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 500233203c79..9c3b51c623d3 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -944,7 +944,11 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, return ExprError(); std::string Str; - Context.getObjCEncodingForType(EncodedType, Str); + QualType NotEncodedT; + Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT); + if (!NotEncodedT.isNull()) + Diag(AtLoc, diag::warn_incomplete_encoded_type) + << EncodedType << NotEncodedT; // The type of @encode is the same as the type of the corresponding string, // which is an array type. @@ -983,7 +987,7 @@ static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, ObjCMethodList *M = &MethList; bool Warned = false; for (M = M->getNext(); M; M=M->getNext()) { - ObjCMethodDecl *MatchingMethodDecl = M->Method; + ObjCMethodDecl *MatchingMethodDecl = M->getMethod(); if (MatchingMethodDecl == Method || isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) || MatchingMethodDecl->getSelector() != Method->getSelector()) @@ -1086,6 +1090,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, case OMF_mutableCopy: case OMF_new: case OMF_self: + case OMF_initialize: case OMF_performSelector: break; } @@ -1105,6 +1110,8 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; } + if (PDecl->hasDefinition()) + PDecl = PDecl->getDefinition(); QualType Ty = Context.getObjCProtoType(); if (Ty.isNull()) @@ -1222,12 +1229,8 @@ void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) { // 'instancetype'. if (const ObjCMethodDecl *overridden = findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) { - SourceLocation loc; - SourceRange range; - if (TypeSourceInfo *TSI = overridden->getReturnTypeSourceInfo()) { - range = TSI->getTypeLoc().getSourceRange(); - loc = range.getBegin(); - } + SourceRange range = overridden->getReturnTypeSourceRange(); + SourceLocation loc = range.getBegin(); if (loc.isInvalid()) loc = overridden->getLocation(); Diag(loc, diag::note_related_result_type_explicit) @@ -1276,6 +1279,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, + SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK) { SourceLocation SelLoc; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) @@ -1317,9 +1321,12 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, : diag::warn_instance_method_not_found_with_typo; Selector MatchedSel = OMD->getSelector(); SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back()); - Diag(SelLoc, DiagID) - << Sel<< isClassMessage << MatchedSel - << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); + if (MatchedSel.isUnarySelector()) + Diag(SelLoc, DiagID) + << Sel<< isClassMessage << MatchedSel + << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); + else + Diag(SelLoc, DiagID) << Sel<< isClassMessage << MatchedSel; } else Diag(SelLoc, DiagID) @@ -1327,9 +1334,15 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, SelectorLocs.back()); // Find the class to which we are sending this message. if (ReceiverType->isObjCObjectPointerType()) { - if (ObjCInterfaceDecl *Class = - ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) - Diag(Class->getLocation(), diag::note_receiver_class_declared); + if (ObjCInterfaceDecl *ThisClass = + ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) { + Diag(ThisClass->getLocation(), diag::note_receiver_class_declared); + if (!RecRange.isInvalid()) + if (ThisClass->lookupClassMethod(Sel)) + Diag(RecRange.getBegin(),diag::note_receiver_expr_here) + << FixItHint::CreateReplacement(RecRange, + ThisClass->getNameAsString()); + } } } @@ -1400,7 +1413,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, param); - ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, argExpr); + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr); if (ArgE.isInvalid()) IsError = true; else @@ -1434,7 +1447,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, // Do additional checkings on method. IsError |= CheckObjCMethodCall( - Method, SelLoc, makeArrayRef<const Expr *>(Args.data(), Args.size())); + Method, SelLoc, makeArrayRef(Args.data(), Args.size())); return IsError; } @@ -1651,6 +1664,22 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); + // Special warning if member name used in a property-dot for a setter accessor + // does not use a property with same name; e.g. obj.X = ... for a property with + // name 'x'. + if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() + && !IFace->FindPropertyDeclaration(Member)) { + if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) { + // Do not warn if user is using property-dot syntax to make call to + // user named setter. + if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter)) + Diag(MemberLoc, + diag::warn_property_access_suggest) + << MemberName << QualType(OPT, 0) << PDecl->getName() + << FixItHint::CreateReplacement(MemberLoc, PDecl->getName()); + } + } + if (Getter || Setter) { if (Super) return new (Context) @@ -1664,10 +1693,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Attempt to correct for typos in property names. - DeclFilterCCC<ObjCPropertyDecl> Validator; - if (TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, - nullptr, nullptr, Validator, CTK_ErrorRecovery, IFace, false, OPT)) { + if (TypoCorrection Corrected = + CorrectTypo(DeclarationNameInfo(MemberName, MemberLoc), + LookupOrdinaryName, nullptr, nullptr, + llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(), + CTK_ErrorRecovery, IFace, false, OPT)) { diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0)); DeclarationName TypoResult = Corrected.getCorrection(); @@ -1892,11 +1922,10 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } } - ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl()); - if (TypoCorrection Corrected = - CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, - nullptr, Validator, CTK_ErrorRecovery, nullptr, false, - nullptr, false)) { + if (TypoCorrection Corrected = CorrectTypo( + Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, + llvm::make_unique<ObjCInterfaceOrSuperCCC>(getCurMethodDecl()), + CTK_ErrorRecovery, nullptr, false, nullptr, false)) { if (Corrected.isKeyword()) { // If we've found the keyword "super" (the only keyword that would be // returned by CorrectTypo), this is a send to super. @@ -2034,6 +2063,45 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) { edit::rewriteObjCRedundantCallWithLiteral); } +/// \brief Diagnose use of %s directive in an NSString which is being passed +/// as formatting string to formatting method. +static void +DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S, + ObjCMethodDecl *Method, + Selector Sel, + Expr **Args, unsigned NumArgs) { + unsigned Idx = 0; + bool Format = false; + ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily(); + if (SFFamily == ObjCStringFormatFamily::SFF_NSString) { + Idx = 0; + Format = true; + } + else if (Method) { + for (const auto *I : Method->specific_attrs<FormatAttr>()) { + if (S.GetFormatNSStringIdx(I, Idx)) { + Format = true; + break; + } + } + } + if (!Format || NumArgs <= Idx) + return; + + Expr *FormatExpr = Args[Idx]; + if (ObjCStringLiteral *OSL = + dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) { + StringLiteral *FormatString = OSL->getString(); + if (S.FormatStringHasSArg(FormatString)) { + S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) + << "%s" << 0 << 0; + if (Method) + S.Diag(Method->getLocation(), diag::note_method_declared_at) + << Method->getDeclName(); + } + } +} + /// \brief Build an Objective-C class message expression. /// /// This routine takes care of both normal class messages and @@ -2146,7 +2214,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), Sel, SelectorLocs, Method, true, - SuperLoc.isValid(), LBracLoc, RBracLoc, + SuperLoc.isValid(), LBracLoc, RBracLoc, + SourceRange(), ReturnType, VK)) return ExprError(); @@ -2154,7 +2223,32 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, RequireCompleteType(LBracLoc, Method->getReturnType(), diag::err_illegal_message_expr_incomplete_type)) return ExprError(); - + + // Warn about explicit call of +initialize on its own class. But not on 'super'. + if (Method && Method->getMethodFamily() == OMF_initialize) { + if (!SuperLoc.isValid()) { + const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext()); + if (ID == Class) { + Diag(Loc, diag::warn_direct_initialize_call); + Diag(Method->getLocation(), diag::note_method_declared_at) + << Method->getDeclName(); + } + } + else if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + // [super initialize] is allowed only within an +initialize implementation + if (CurMeth->getMethodFamily() != OMF_initialize) { + Diag(Loc, diag::warn_direct_super_initialize_call); + Diag(Method->getLocation(), diag::note_method_declared_at) + << Method->getDeclName(); + Diag(CurMeth->getLocation(), diag::note_method_declared_at) + << CurMeth->getDeclName(); + } + } + } + + DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs); + // Construct the appropriate ObjCMessageExpr. ObjCMessageExpr *Result; if (SuperLoc.isValid()) @@ -2354,11 +2448,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc,RBracLoc), receiverIsId); + if (Method) { + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + Method = BestMethod; + if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod())) + DiagnoseUseOfDecl(Method, SelLoc); + } } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. - // We allow sending a message to a qualified Class ("Class<foo>"), which - // is ok as long as one of the protocols implements the selector (if not, warn). + // We allow sending a message to a qualified Class ("Class<foo>"), which + // is ok as long as one of the protocols implements the selector (if not, + // warn). if (const ObjCObjectPointerType *QClassTy = ReceiverType->getAsObjCQualifiedClassType()) { // Search protocols for class methods. @@ -2405,6 +2507,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Sel << SourceRange(LBracLoc, RBracLoc); } } + if (Method) + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + Method = BestMethod; } } } @@ -2543,7 +2649,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), Sel, SelectorLocs, Method, ClassMessage, SuperLoc.isValid(), - LBracLoc, RBracLoc, ReturnType, VK)) + LBracLoc, RBracLoc, RecRange, ReturnType, VK)) return ExprError(); if (Method && !Method->getReturnType()->isVoidType() && @@ -2568,6 +2674,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_mutableCopy: case OMF_new: case OMF_self: + case OMF_initialize: break; case OMF_dealloc: @@ -2630,6 +2737,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } + DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs); + // Construct the appropriate ObjCMessageExpr instance. ObjCMessageExpr *Result; if (SuperLoc.isValid()) @@ -3296,6 +3405,9 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { HadTheAttribute = true; + if (Parm->isStr("id")) + return true; + NamedDecl *Target = nullptr; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), |