Пример #1
0
        void Visit(ObjCMethodDecl decl)
        {
            // don't process methods (or types) that are unavailable for the current platform
            if (!decl.IsAvailable() || !(decl.DeclContext as Decl).IsAvailable())
            {
                return;
            }

            var method = GetMethod(decl);

            if (method == null)
            {
                return;
            }

            var framework = Helpers.GetFramework(decl);

            if (framework == null)
            {
                return;
            }

            if (!decl.HasAttr <ObjCRequiresSuperAttr> ())
            {
                if (method.RequiresSuper())
                {
                    Log.On(framework).Add($"!extra-requires-super! {method.GetName ()} is incorrectly decorated with an [RequiresSuper] attribute");
                }
            }
            else if (!method.RequiresSuper())
            {
                Log.On(framework).Add($"!missing-requires-super! {method.GetName ()} is missing an [RequiresSuper] attribute");
            }
        }
Пример #2
0
        public override void VisitObjCMethodDecl(ObjCMethodDecl decl, VisitKind visitKind)
        {
            if (visitKind != VisitKind.Enter)
            {
                return;
            }

            // protocol members are checked in ObjCProtocolCheck
            if (decl.DeclContext is ObjCProtocolDecl)
            {
                return;
            }

            // don't process methods (or types) that are unavailable for the current platform
            if (!decl.IsAvailable() || !(decl.DeclContext as Decl).IsAvailable())
            {
                return;
            }

            var framework = Helpers.GetFramework(decl);

            if (framework == null)
            {
                return;
            }

            string selector = decl.GetSelector();

            if (String.IsNullOrEmpty(selector))
            {
                return;
            }

            var  name  = (decl.IsClassMethod ? "+" : String.Empty) + decl.QualifiedName;
            bool found = qualified_selectors.Contains(name);

            if (!found)
            {
                // a category could be inlined into the type it extend
                var category = decl.DeclContext as ObjCCategoryDecl;
                if (category != null)
                {
                    var cname = category.Name;
                    if (cname == null)
                    {
                        name = GetCategoryBase(category) + name;
                    }
                    else
                    {
                        name = name.ReplaceFirstInstance(cname, GetCategoryBase(category));
                    }
                    found = qualified_selectors.Contains(name);
                }
            }
            if (!found)
            {
                Log.On(framework).Add($"!missing-selector! {name} not bound");
            }
        }
        public override void VisitObjCMethodDecl(ObjCMethodDecl decl, VisitKind visitKind)
        {
            if (visitKind != VisitKind.Enter)
            {
                return;
            }

            // don't process methods (or types) that are unavailable for the current platform
            if (!decl.IsAvailable() || !(decl.DeclContext as Decl).IsAvailable())
            {
                return;
            }

            var method = GetMethod(decl);

            // don't report missing [DesignatedInitializer] for types that are not bound - that's a different problem
            if (method == null)
            {
                return;
            }

            var framework = Helpers.GetFramework(decl);

            if (framework == null)
            {
                return;
            }

            var designated_initializer = method.IsDesignatedInitializer();

            if (!method.IsConstructor)
            {
                if (designated_initializer)
                {
                    Log.On(framework).Add($"!incorrect-designated-initializer! {method.GetName ()} is not a constructor");
                }
            }
            else if (decl.IsDesignatedInitializer)
            {
                if (!designated_initializer)
                {
                    Log.On(framework).Add($"!missing-designated-initializer! {method.GetName ()} is missing an [DesignatedInitializer] attribute");
                }
            }
            else
            {
                if (designated_initializer)
                {
                    Log.On(framework).Add($"!extra-designated-initializer! {method.GetName ()} is incorrectly decorated with an [DesignatedInitializer] attribute");
                }
            }
        }
Пример #4
0
        public override void VisitObjCMethodDecl(ObjCMethodDecl decl, VisitKind visitKind)
        {
            if (visitKind != VisitKind.Enter)
            {
                return;
            }

            // don't process methods (or types) that are unavailable for the current platform
            if (!decl.IsAvailable() || !(decl.DeclContext as Decl).IsAvailable())
            {
                return;
            }

            // does not look exposed, but part of the dump
            if (decl.DumpToString().IndexOf("UI_APPEARANCE_SELECTOR", StringComparison.OrdinalIgnoreCase) < 0)
            {
                return;
            }

            VisitObjCMethodDecl(decl);
        }
Пример #5
0
        public override void VisitObjCMethodDecl(ObjCMethodDecl decl, VisitKind visitKind)
        {
            if (visitKind != VisitKind.Enter)
            {
                return;
            }

            // don't process methods (or types) that are unavailable for the current platform
            if (!decl.IsAvailable() || !(decl.DeclContext as Decl).IsAvailable())
            {
                return;
            }

            var framework = Helpers.GetFramework(decl);

            if (framework == null)
            {
                return;
            }

            var simd_type = string.Empty;
            var requires_marshal_directive = false;
            var native_simd = ContainsSimdTypes(decl, ref simd_type, ref requires_marshal_directive);

            ManagedSimdInfo info;

            managed_methods.TryGetValue(decl.GetName(), out info);
            var method = info?.Method;

            if (!native_simd)
            {
                if (method != null)
                {
                    // The managed method uses types that were incorrectly used in place of the correct Simd types,
                    // but the native method doesn't use the native Simd types. This means the binding is correct.
                }
                else
                {
                    // Neither the managed nor the native method have anything to do with Simd types.
                }
                return;
            }

            if (method == null)
            {
                // Could not map the native method to a managed method.
                // This needs investigation, to see why the native method couldn't be mapped.

                // Check if this is new API, in which case it probably couldn't be mapped because we haven't bound it.
                var is_new      = false;
                var attrs       = decl.Attrs.ToList();
                var parentClass = decl.DeclContext as Decl;
                if (parentClass != null)
                {
                    attrs.AddRange(parentClass.Attrs);
                }

                foreach (var attr in attrs)
                {
                    var av_attr = attr as AvailabilityAttr;
                    if (av_attr == null)
                    {
                        continue;
                    }
                    if (av_attr.Platform.Name != "ios")
                    {
                        continue;
                    }
                    if (av_attr.Introduced.Major >= 11)
                    {
                        is_new = true;
                        break;
                    }
                }
                if (is_new && !very_strict)
                {
                    return;
                }
                if (!strict)
                {
                    return;
                }
                Log.On(framework).Add($"!missing-simd-managed-method! {decl}: could not find a managed method for the native method {decl.GetName ()} (selector: {decl.Selector}). Found the simd type '{simd_type}' in the native signature.");
                return;
            }

            if (!info.ContainsInvalidMappingForSimd)
            {
                // The managed method does not have any types that are incorrect for Simd.
                if (requires_marshal_directive)
                {
                    CheckMarshalDirective(method, simd_type);
                }
                return;
            }

            if (method.IsObsolete())
            {
                // We have a potentially broken managed method, but it's obsolete. That's fine.
                return;
            }

            if (requires_marshal_directive)
            {
                CheckMarshalDirective(method, simd_type);
            }

            // We have a potentially broken managed method. This needs fixing/investigation.
            Log.On(framework).Add($"!unknown-simd-type-in-signature! {method}: the native signature has a simd type ({simd_type}), while the corresponding managed method is using an incorrect (non-simd) type.");
        }
Пример #6
0
        public override void VisitObjCMethodDecl(ObjCMethodDecl decl, VisitKind visitKind)
        {
            if (visitKind != VisitKind.Enter)
            {
                return;
            }

            // don't process methods (or types) that are unavailable for the current platform
            if (!decl.IsAvailable() || !(decl.DeclContext as Decl).IsAvailable())
            {
                return;
            }

            var method = GetMethod(decl);

            // don't report missing nullability on types that are not bound - that's a different problem
            if (method == null)
            {
                return;
            }

            var framework = Helpers.GetFramework(decl);

            if (framework == null)
            {
                return;
            }

            var t = method.DeclaringType;
            // look for [NullableContext] for defaults
            var managed_default_nullability = GetNullableContext(method);

            if (managed_default_nullability == Null.Oblivious)
            {
                managed_default_nullability = GetNullableContext(t);
            }

            // check parameters
            // categories have an offset of 1 for the extension method type (spotted as static types)
            int i = t.IsSealed && t.IsAbstract ? 1 : 0;

            foreach (var p in decl.Parameters)
            {
                var mp = method.Parameters [i++];
                // a managed `out` value does not need to be inialized, won't be null (but can be ignored)
                if (mp.IsOut)
                {
                    continue;
                }

                var pt = mp.ParameterType;
                // if bound as `IntPtr` then nullability attributes won't be present
                if (pt.IsValueType)
                {
                    continue;
                }

                Null parameter_nullable;

                // if we used a type by reference (e.g. `ref float foo`); or a nullable type (e.g. `[BindAs]`)
                // then assume it's meant as a nullable type) without additional decorations
                if (pt.IsByReference || pt.FullName.StartsWith("System.Nullable`1<", StringComparison.Ordinal))
                {
                    parameter_nullable = Null.Annotated;
                }
                else
                {
                    // check C# 8 compiler attributes
                    var nullable = GetNullable(mp);
                    if (nullable.Length > 1)
                    {
                        // check the type itself, TODO check the generics (don't think we have such cases yet)
                        parameter_nullable = nullable [0];
                    }
                    else if (nullable.Length == 0)
                    {
                        parameter_nullable = managed_default_nullability;
                    }
                    else
                    {
                        parameter_nullable = nullable [0];
                    }
                }

                // match with native and, if needed, report discrepancies
                p.QualType.Type.GetNullability(p.AstContext, out var nullability);
                switch (nullability)
                {
                case NullabilityKind.NonNull:
                    if (parameter_nullable == Null.Annotated)
                    {
                        Log.On(framework).Add($"!extra-null-allowed! '{method.FullName}' has a extraneous [NullAllowed] on parameter #{i-1}");
                    }
                    break;

                case NullabilityKind.Nullable:
                    if (parameter_nullable != Null.Annotated)
                    {
                        Log.On(framework).Add($"!missing-null-allowed! '{method.FullName}' is missing an [NullAllowed] on parameter #{i-1}");
                    }
                    break;

                case NullabilityKind.Unspecified:
                    break;
                }
            }

            // with .net a constructor will always return something (or throw)
            // that's not the case in ObjC where `init*` can return `nil`
            if (method.IsConstructor)
            {
                return;
            }

            var mrt = method.ReturnType;

            // if bound as an `IntPtr` then the nullability will not be visible in the metadata
            if (mrt.IsValueType)
            {
                return;
            }

            Null return_nullable;

            // if we used a nullable type (e.g. [BindAs] then assume it's meant as a nullable type) without additional decorations
            if (mrt.FullName.StartsWith("System.Nullable`1<", StringComparison.Ordinal))
            {
                return_nullable = Null.Annotated;
            }
            else
            {
                ICustomAttributeProvider cap;
                // the managed attributes are on the property, not the special methods
                if (method.IsGetter)
                {
                    var property = method.FindProperty();
                    // also `null_resettable` will only show something (natively) on the setter (since it does not return null, but accept it)
                    // in this case we'll trust xtro checking the setter only (if it exists, if not then it can't be `null_resettable`)
                    if (property.SetMethod != null)
                    {
                        return;
                    }
                    cap = property;
                }
                else
                {
                    cap = method.MethodReturnType;
                }
                Null [] mrt_nullable = GetNullable(cap);

                if (mrt_nullable.Length > 1)
                {
                    // check the type itself, TODO check the generics (don't think we have such cases yet)
                    return_nullable = mrt_nullable [0];
                }
                else if (mrt_nullable.Length == 0)
                {
                    return_nullable = managed_default_nullability;
                }
                else
                {
                    return_nullable = mrt_nullable [0];
                }
            }

            var rt = decl.ReturnQualType;

            rt.Type.GetNullability(decl.AstContext, out var rnull);
            switch (rnull)
            {
            case NullabilityKind.NonNull:
                if (return_nullable == Null.Annotated)
                {
                    Log.On(framework).Add($"!extra-null-allowed! '{method}' has a extraneous [NullAllowed] on return type");
                }
                break;

            case NullabilityKind.Nullable:
                if (return_nullable != Null.Annotated)
                {
                    Log.On(framework).Add($"!missing-null-allowed! '{method}' is missing an [NullAllowed] on return type");
                }
                break;

            case NullabilityKind.Unspecified:
                break;
            }
        }