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"); } }
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"); } } }
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); }
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."); }
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; } }