diff options
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
| -rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 128 | 
1 files changed, 83 insertions, 45 deletions
| diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 7e3da941b339..38318791fd77 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -448,6 +448,19 @@ class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {  } +static void diagnoseUseOfProtocols(Sema &TheSema, +                                   ObjCContainerDecl *CD, +                                   ObjCProtocolDecl *const *ProtoRefs, +                                   unsigned NumProtoRefs, +                                   const SourceLocation *ProtoLocs) { +  assert(ProtoRefs); +  // Diagnose availability in the context of the ObjC container. +  Sema::ContextRAII SavedContext(TheSema, CD); +  for (unsigned i = 0; i < NumProtoRefs; ++i) { +    (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i]); +  } +} +  Decl *Sema::  ActOnStartClassInterface(SourceLocation AtInterfaceLoc,                           IdentifierInfo *ClassName, SourceLocation ClassLoc, @@ -535,6 +548,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,        ObjCInterfaceDecl *SuperClassDecl =                                  dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); +      // Diagnose availability in the context of the @interface. +      ContextRAII SavedContext(*this, IDecl);        // Diagnose classes that inherit from deprecated classes.        if (SuperClassDecl)          (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); @@ -591,6 +606,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,    // Check then save referenced protocols.    if (NumProtoRefs) { +    diagnoseUseOfProtocols(*this, IDecl, (ObjCProtocolDecl*const*)ProtoRefs, +                           NumProtoRefs, ProtoLocs);      IDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,                             ProtoLocs, Context);      IDecl->setEndOfDefinitionLoc(EndProtoLoc); @@ -617,8 +634,7 @@ void Sema::ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs,      QualType T = TDecl->getUnderlyingType();      if (T->isObjCObjectType())        if (const ObjCObjectType *OPT = T->getAs<ObjCObjectType>()) -        for (auto *I : OPT->quals()) -          ProtocolRefs.push_back(I); +        ProtocolRefs.append(OPT->qual_begin(), OPT->qual_end());    }  } @@ -752,6 +768,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,    if (!err && NumProtoRefs ) {      /// Check then save referenced protocols. +    diagnoseUseOfProtocols(*this, PDecl, (ObjCProtocolDecl*const*)ProtoRefs, +                           NumProtoRefs, ProtoLocs);      PDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,                             ProtoLocs, Context);    } @@ -779,7 +797,7 @@ static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,  /// issues an error if they are not declared. It returns list of  /// protocol declarations in its 'Protocols' argument.  void -Sema::FindProtocolDeclaration(bool WarnOnDeclarations, +Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer,                                const IdentifierLocPair *ProtocolId,                                unsigned NumProtocols,                                SmallVectorImpl<Decl *> &Protocols) { @@ -805,8 +823,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,      // If this is a forward protocol declaration, get its definition.      if (!PDecl->isThisDeclarationADefinition() && PDecl->getDefinition())        PDecl = PDecl->getDefinition(); -     -    (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second); + +    // For an objc container, delay protocol reference checking until after we +    // can set the objc decl as the availability context, otherwise check now. +    if (!ForObjCContainer) { +      (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second); +    }      // If this is a forward declaration and we are supposed to warn in this      // case, do it. @@ -935,7 +957,9 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,    CurContext->addDecl(CDecl);    if (NumProtoRefs) { -    CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,  +    diagnoseUseOfProtocols(*this, CDecl, (ObjCProtocolDecl*const*)ProtoRefs, +                           NumProtoRefs, ProtoLocs); +    CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,                             ProtoLocs, Context);      // Protocols in the class extension belong to the class.      if (CDecl->IsClassExtension()) @@ -2241,8 +2265,14 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List,      if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty())        continue; -    if (!MatchTwoMethodDeclarations(Method, List->getMethod())) +    if (!MatchTwoMethodDeclarations(Method, List->getMethod())) { +      // Even if two method types do not match, we would like to say +      // there is more than one declaration so unavailability/deprecated +      // warning is not too noisy. +      if (!Method->isDefined()) +        List->setHasMoreThanOneDecl(true);        continue; +    }      ObjCMethodDecl *PrevObjCMethod = List->getMethod(); @@ -2341,19 +2371,33 @@ bool Sema::CollectMultipleMethodsInGlobalPool(    return Methods.size() > 1;  } -bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, bool instance) { +bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, +                                          SourceRange R, +                                          bool receiverIdOrClass) {    GlobalMethodPool::iterator Pos = MethodPool.find(Sel);    // Test for no method in the pool which should not trigger any warning by    // caller.    if (Pos == MethodPool.end())      return true; -  ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; +  ObjCMethodList &MethList = +    BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second; +   +  // Diagnose finding more than one method in global pool +  SmallVector<ObjCMethodDecl *, 4> Methods; +  Methods.push_back(BestMethod); +  for (ObjCMethodList *ML = &MethList; ML; ML = ML->getNext()) +    if (ObjCMethodDecl *M = ML->getMethod()) +      if (!M->isHidden() && M != BestMethod && !M->hasAttr<UnavailableAttr>()) +        Methods.push_back(M); +  if (Methods.size() > 1) +    DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass); +    return MethList.hasMoreThanOneDecl();  }  ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,                                                 bool receiverIdOrClass, -                                               bool warn, bool instance) { +                                               bool instance) {    if (ExternalSource)      ReadMethodPool(Sel); @@ -2365,31 +2409,23 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,    ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;    SmallVector<ObjCMethodDecl *, 4> Methods;    for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { -    if (M->getMethod() && !M->getMethod()->isHidden()) { -      // If we're not supposed to warn about mismatches, we're done. -      if (!warn) -        return M->getMethod(); - -      Methods.push_back(M->getMethod()); -    } +    if (M->getMethod() && !M->getMethod()->isHidden()) +      return M->getMethod();    } +  return nullptr; +} -  // If there aren't any visible methods, we're done. -  // FIXME: Recover if there are any known-but-hidden methods? -  if (Methods.empty()) -    return nullptr; - -  if (Methods.size() == 1) -    return Methods[0]; - +void Sema::DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods, +                                              Selector Sel, SourceRange R, +                                              bool receiverIdOrClass) {    // We found multiple methods, so we may have to complain.    bool issueDiagnostic = false, issueError = false;    // We support a warning which complains about *any* difference in    // method signature.    bool strictSelectorMatch = -      receiverIdOrClass && warn && -      !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin()); +  receiverIdOrClass && +  !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());    if (strictSelectorMatch) {      for (unsigned I = 1, N = Methods.size(); I != N; ++I) {        if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) { @@ -2414,7 +2450,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,          break;        }      } - +      if (issueDiagnostic) {      if (issueError)        Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R; @@ -2422,16 +2458,15 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,        Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;      else        Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - +          Diag(Methods[0]->getLocStart(),           issueError ? diag::note_possibility : diag::note_using) -      << Methods[0]->getSourceRange(); +    << Methods[0]->getSourceRange();      for (unsigned I = 1, N = Methods.size(); I != N; ++I) {        Diag(Methods[I]->getLocStart(), diag::note_also_found) -        << Methods[I]->getSourceRange(); -  } +      << Methods[I]->getSourceRange(); +    }    } -  return Methods[0];  }  ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { @@ -2442,12 +2477,16 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {    GlobalMethods &Methods = Pos->second;    for (const ObjCMethodList *Method = &Methods.first; Method;         Method = Method->getNext()) -    if (Method->getMethod() && Method->getMethod()->isDefined()) +    if (Method->getMethod() && +        (Method->getMethod()->isDefined() || +         Method->getMethod()->isPropertyAccessor()))        return Method->getMethod();    for (const ObjCMethodList *Method = &Methods.second; Method;         Method = Method->getNext()) -    if (Method->getMethod() && Method->getMethod()->isDefined()) +    if (Method->getMethod() && +        (Method->getMethod()->isDefined() || +         Method->getMethod()->isPropertyAccessor()))        return Method->getMethod();    return nullptr;  } @@ -2571,10 +2610,9 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const {      case Decl::ObjCProtocol:        return Sema::OCK_Protocol;      case Decl::ObjCCategory: -      if (dyn_cast<ObjCCategoryDecl>(CurContext)->IsClassExtension()) +      if (cast<ObjCCategoryDecl>(CurContext)->IsClassExtension())          return Sema::OCK_ClassExtension; -      else -        return Sema::OCK_Category; +      return Sema::OCK_Category;      case Decl::ObjCImplementation:        return Sema::OCK_Implementation;      case Decl::ObjCCategoryImpl: @@ -3286,7 +3324,7 @@ Decl *Sema::ActOnMethodDeclaration(      case OMF_alloc:      case OMF_new: -      InferRelatedResultType = ObjCMethod->isClassMethod(); +        InferRelatedResultType = ObjCMethod->isClassMethod();        break;      case OMF_init: @@ -3297,7 +3335,8 @@ Decl *Sema::ActOnMethodDeclaration(        break;      } -    if (InferRelatedResultType) +    if (InferRelatedResultType && +        !ObjCMethod->getReturnType()->isObjCIndependentClassType())        ObjCMethod->SetRelatedResultType();    } @@ -3487,12 +3526,11 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() {    if (ReferencedSelectors.empty() ||         !Context.AnyObjCImplementation())      return; -  for (llvm::DenseMap<Selector, SourceLocation>::iterator S =  -        ReferencedSelectors.begin(), -       E = ReferencedSelectors.end(); S != E; ++S) { -    Selector Sel = (*S).first; +  for (auto &SelectorAndLocation : ReferencedSelectors) { +    Selector Sel = SelectorAndLocation.first; +    SourceLocation Loc = SelectorAndLocation.second;      if (!LookupImplementedMethodInGlobalPool(Sel)) -      Diag((*S).second, diag::warn_unimplemented_selector) << Sel; +      Diag(Loc, diag::warn_unimplemented_selector) << Sel;    }    return;  } | 
