diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaDeclObjC.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaDeclObjC.cpp | 196 | 
1 files changed, 184 insertions, 12 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm-project/clang/lib/Sema/SemaDeclObjC.cpp index e629837eb71d..5fdf6aeed5b4 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaDeclObjC.cpp @@ -512,7 +512,7 @@ class ObjCInterfaceValidatorCCC final : public CorrectionCandidateCallback {    }    std::unique_ptr<CorrectionCandidateCallback> clone() override { -    return llvm::make_unique<ObjCInterfaceValidatorCCC>(*this); +    return std::make_unique<ObjCInterfaceValidatorCCC>(*this);    }   private: @@ -586,7 +586,7 @@ ActOnSuperClassOfClassInterface(Scope *S,            dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {          QualType T = TDecl->getUnderlyingType();          if (T->isObjCObjectType()) { -          if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { +          if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) {              SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);              SuperClassType = Context.getTypeDeclType(TDecl); @@ -1151,7 +1151,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,          dyn_cast_or_null<TypedefNameDecl>(CDeclU)) {      QualType T = TDecl->getUnderlyingType();      if (T->isObjCObjectType()) { -      if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { +      if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) {          ClassName = IDecl->getIdentifier();          CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,                                    LookupOrdinaryName, @@ -1387,7 +1387,7 @@ class ObjCTypeArgOrProtocolValidatorCCC final    }    std::unique_ptr<CorrectionCandidateCallback> clone() override { -    return llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this); +    return std::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this);    }  };  } // end anonymous namespace @@ -2275,9 +2275,7 @@ static bool isObjCTypeSubstitutable(ASTContext &Context,    // stricter definition so it is not substitutable for id<A>.    if (B->isObjCQualifiedIdType()) {      return A->isObjCQualifiedIdType() && -           Context.ObjCQualifiedIdTypesAreCompatible(QualType(A, 0), -                                                     QualType(B,0), -                                                     false); +           Context.ObjCQualifiedIdTypesAreCompatible(A, B, false);    }    /* @@ -2830,6 +2828,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,               "Expected to find the method through lookup as well");        // ImpMethodDecl may be null as in a @dynamic property.        if (ImpMethodDecl) { +        // Skip property accessor function stubs. +        if (ImpMethodDecl->isSynthesizedAccessorStub()) +          continue;          if (!WarnCategoryMethodImpl)            WarnConflictingTypedMethods(ImpMethodDecl, I,                                        isa<ObjCProtocolDecl>(CDecl)); @@ -2856,6 +2857,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,               "Expected to find the method through lookup as well");        // ImpMethodDecl may be null as in a @dynamic property.        if (ImpMethodDecl) { +        // Skip property accessor function stubs. +        if (ImpMethodDecl->isSynthesizedAccessorStub()) +          continue;          if (!WarnCategoryMethodImpl)            WarnConflictingTypedMethods(ImpMethodDecl, I,                                        isa<ObjCProtocolDecl>(CDecl)); @@ -3235,6 +3239,9 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,    if (left->isHidden() || right->isHidden())      return false; +  if (left->isDirectMethod() != right->isDirectMethod()) +    return false; +    if (getLangOpts().ObjCAutoRefCount &&        (left->hasAttr<NSReturnsRetainedAttr>()           != right->hasAttr<NSReturnsRetainedAttr>() || @@ -3426,6 +3433,9 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,    if (!chosen->isInstanceMethod())      return false; +  if (chosen->isDirectMethod() != other->isDirectMethod()) +    return false; +    Selector sel = chosen->getSelector();    if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")      return false; @@ -3905,6 +3915,25 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,           || isa<ObjCProtocolDecl>(ClassDecl);    bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); +  // Make synthesized accessor stub functions visible. +  // ActOnPropertyImplDecl() creates them as not visible in case +  // they are overridden by an explicit method that is encountered +  // later. +  if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) { +    for (auto PropImpl : OID->property_impls()) { +      if (auto *Getter = PropImpl->getGetterMethodDecl()) +        if (Getter->isSynthesizedAccessorStub()) { +          OID->makeDeclVisibleInContext(Getter); +          OID->addDecl(Getter); +        } +      if (auto *Setter = PropImpl->getSetterMethodDecl()) +        if (Setter->isSynthesizedAccessorStub()) { +          OID->makeDeclVisibleInContext(Setter); +          OID->addDecl(Setter); +        } +    } +  } +    // FIXME: Remove these and use the ObjCContainerDecl/DeclContext.    llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;    llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap; @@ -4003,8 +4032,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,                continue;            for (const auto *Ext : IDecl->visible_extensions()) { -            if (ObjCMethodDecl *GetterMethod -                  = Ext->getInstanceMethod(Property->getGetterName())) +            if (ObjCMethodDecl *GetterMethod = +                    Ext->getInstanceMethod(Property->getGetterName()))                GetterMethod->setPropertyAccessor(true);              if (!Property->isReadOnly())                if (ObjCMethodDecl *SetterMethod @@ -4316,6 +4345,18 @@ private:  };  } // end anonymous namespace +void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method, +                                          ObjCMethodDecl *overridden) { +  if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) { +    Diag(method->getLocation(), diag::err_objc_override_direct_method); +    Diag(attr->getLocation(), diag::note_previous_declaration); +  } else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) { +    Diag(attr->getLocation(), diag::err_objc_direct_on_override) +        << isa<ObjCProtocolDecl>(overridden->getDeclContext()); +    Diag(overridden->getLocation(), diag::note_previous_declaration); +  } +} +  void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,                                      ObjCInterfaceDecl *CurrentClass,                                      ResultTypeCompatibilityKind RTC) { @@ -4334,8 +4375,8 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,        if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||            CurrentClass != overridden->getClassInterface() ||            overridden->isOverriding()) { +        CheckObjCMethodDirectOverrides(ObjCMethod, overridden);          hasOverriddenMethodsInBaseOrProtocol = true; -        } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {          // OverrideSearch will return as "overridden" the same method in the          // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to @@ -4359,6 +4400,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,                for (ObjCMethodDecl *SuperOverridden : overrides) {                  if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||                      CurrentClass != SuperOverridden->getClassInterface()) { +                  CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);                    hasOverriddenMethodsInBaseOrProtocol = true;                    overridden->setOverriding(true);                    break; @@ -4553,6 +4595,7 @@ Decl *Sema::ActOnMethodDeclaration(      Diag(MethodLoc, diag::err_missing_method_context);      return nullptr;    } +    Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext);    QualType resultDeclType; @@ -4576,7 +4619,7 @@ Decl *Sema::ActOnMethodDeclaration(    ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create(        Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext,        MethodType == tok::minus, isVariadic, -      /*isPropertyAccessor=*/false, +      /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,        /*isImplicitlyDeclared=*/false, /*isDefined=*/false,        MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional                                             : ObjCMethodDecl::Required, @@ -4668,6 +4711,41 @@ Decl *Sema::ActOnMethodDeclaration(        ImpDecl->addClassMethod(ObjCMethod);      } +    // If this method overrides a previous @synthesize declaration, +    // register it with the property.  Linear search through all +    // properties here, because the autosynthesized stub hasn't been +    // made visible yet, so it can be overriden by a later +    // user-specified implementation. +    for (ObjCPropertyImplDecl *PropertyImpl : ImpDecl->property_impls()) { +      if (auto *Setter = PropertyImpl->getSetterMethodDecl()) +        if (Setter->getSelector() == Sel && +            Setter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { +          assert(Setter->isSynthesizedAccessorStub() && "autosynth stub expected"); +          PropertyImpl->setSetterMethodDecl(ObjCMethod); +        } +      if (auto *Getter = PropertyImpl->getGetterMethodDecl()) +        if (Getter->getSelector() == Sel && +            Getter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { +          assert(Getter->isSynthesizedAccessorStub() && "autosynth stub expected"); +          PropertyImpl->setGetterMethodDecl(ObjCMethod); +          break; +        } +    } + +    // A method is either tagged direct explicitly, or inherits it from its +    // canonical declaration. +    // +    // We have to do the merge upfront and not in mergeInterfaceMethodToImpl() +    // because IDecl->lookupMethod() returns more possible matches than just +    // the canonical declaration. +    if (!ObjCMethod->isDirectMethod()) { +      const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl(); +      if (const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>()) { +        ObjCMethod->addAttr( +            ObjCDirectAttr::CreateImplicit(Context, attr->getLocation())); +      } +    } +      // Merge information from the @interface declaration into the      // @implementation.      if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) { @@ -4675,12 +4753,64 @@ Decl *Sema::ActOnMethodDeclaration(                                            ObjCMethod->isInstanceMethod())) {          mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD); +        // The Idecl->lookupMethod() above will find declarations for ObjCMethod +        // in one of these places: +        // +        // (1) the canonical declaration in an @interface container paired +        //     with the ImplDecl, +        // (2) non canonical declarations in @interface not paired with the +        //     ImplDecl for the same Class, +        // (3) any superclass container. +        // +        // Direct methods only allow for canonical declarations in the matching +        // container (case 1). +        // +        // Direct methods overriding a superclass declaration (case 3) is +        // handled during overrides checks in CheckObjCMethodOverrides(). +        // +        // We deal with same-class container mismatches (Case 2) here. +        if (IDecl == IMD->getClassInterface()) { +          auto diagContainerMismatch = [&] { +            int decl = 0, impl = 0; + +            if (auto *Cat = dyn_cast<ObjCCategoryDecl>(IMD->getDeclContext())) +              decl = Cat->IsClassExtension() ? 1 : 2; + +            if (isa<ObjCCategoryImplDecl>(ImpDecl)) +              impl = 1 + (decl != 0); + +            Diag(ObjCMethod->getLocation(), +                 diag::err_objc_direct_impl_decl_mismatch) +                << decl << impl; +            Diag(IMD->getLocation(), diag::note_previous_declaration); +          }; + +          if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) { +            if (ObjCMethod->getCanonicalDecl() != IMD) { +              diagContainerMismatch(); +            } else if (!IMD->isDirectMethod()) { +              Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl); +              Diag(IMD->getLocation(), diag::note_previous_declaration); +            } +          } else if (const auto *attr = IMD->getAttr<ObjCDirectAttr>()) { +            if (ObjCMethod->getCanonicalDecl() != IMD) { +              diagContainerMismatch(); +            } else { +              ObjCMethod->addAttr( +                  ObjCDirectAttr::CreateImplicit(Context, attr->getLocation())); +            } +          } +        } +          // Warn about defining -dealloc in a category.          if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() &&              ObjCMethod->getSelector().getMethodFamily() == OMF_dealloc) {            Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)              << ObjCMethod->getDeclName();          } +      } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) { +        ObjCMethod->addAttr( +            ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));        }        // Warn if a method declared in a protocol to which a category or @@ -4700,6 +4830,42 @@ Decl *Sema::ActOnMethodDeclaration(            }      }    } else { +    if (!isa<ObjCProtocolDecl>(ClassDecl)) { +      if (!ObjCMethod->isDirectMethod() && +          ClassDecl->hasAttr<ObjCDirectMembersAttr>()) { +        ObjCMethod->addAttr( +            ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); +      } + +      // There can be a single declaration in any @interface container +      // for a given direct method, look for clashes as we add them. +      // +      // For valid code, we should always know the primary interface +      // declaration by now, however for invalid code we'll keep parsing +      // but we won't find the primary interface and IDecl will be nil. +      ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl); +      if (!IDecl) +        IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface(); + +      if (IDecl) +        if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), +                                            ObjCMethod->isInstanceMethod(), +                                            /*shallowCategoryLookup=*/false, +                                            /*followSuper=*/false)) { +          if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) { +            // Do not emit a diagnostic for the Protocol case: +            // diag::err_objc_direct_on_protocol has already been emitted +            // during parsing for these with a nicer diagnostic. +          } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) { +            Diag(ObjCMethod->getLocation(), +                 diag::err_objc_direct_duplicate_decl) +                << ObjCMethod->isDirectMethod() << IMD->isDirectMethod() +                << ObjCMethod->getDeclName(); +            Diag(IMD->getLocation(), diag::note_previous_declaration); +          } +        } +    } +      cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);    } @@ -4785,6 +4951,9 @@ Decl *Sema::ActOnMethodDeclaration(      }    } +  // Insert the invisible arguments, self and _cmd! +  ObjCMethod->createImplicitParams(Context, ObjCMethod->getClassInterface()); +    ActOnDocumentableDecl(ObjCMethod);    return ObjCMethod; @@ -4878,7 +5047,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,    } else if (!T->isObjCObjectPointerType()) {      Invalid = true;      Diag(IdLoc, diag::err_catch_param_not_objc_type); -  } else if (!T->getAs<ObjCObjectPointerType>()->getInterfaceType()) { +  } else if (!T->castAs<ObjCObjectPointerType>()->getInterfaceType()) {      Invalid = true;      Diag(IdLoc, diag::err_catch_param_not_objc_type);    } @@ -5065,6 +5234,9 @@ void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S,      if (!IV)        continue; +    if (CurMethod->isSynthesizedAccessorStub()) +      continue; +      UnusedBackingIvarChecker Checker(*this, CurMethod, IV);      Checker.TraverseStmt(CurMethod->getBody());      if (Checker.AccessedIvar)  | 
