[xtro] Report incorrect 'ArgumentSemantic' enum value usage (#5114)
- ⚠️ Rule deactivated until we have an `xcode10.2` branch where we'll fix the issues. - We only report `copy` mistakes since they're the ones we really care about fixing (we can end up with invalid pointers). - Fixes #4018: [xtro] Report incorrect 'ArgumentSemantic' enum value usage (https://github.com/xamarin/xamarin-macios/issues/4018). - Performance with the added test: - Extrospection.SelectorCheck: Elapsed=00:00:00.7263742 - Extrospection.SelectorCheck: Elapsed=00:00:01.2136911 - Extrospection.SelectorCheck: Elapsed=00:00:01.2747602 - Extrospection.SelectorCheck: Elapsed=00:00:01.7494063
This commit is contained in:
Родитель
ae13240b20
Коммит
9be55e2bf4
|
@ -397,5 +397,43 @@ namespace Extrospection {
|
||||||
else
|
else
|
||||||
return (o1, o2);
|
return (o1, o2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ArgumentSemantic {
|
||||||
|
None = -1,
|
||||||
|
Assign = 0,
|
||||||
|
Copy = 1,
|
||||||
|
Retain = 2,
|
||||||
|
Weak = 3,
|
||||||
|
Strong = Retain,
|
||||||
|
UnsafeUnretained = Assign,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArgumentSemantic ToArgumentSemantic (this ObjCPropertyAttributeKind attr)
|
||||||
|
{
|
||||||
|
if ((attr & ObjCPropertyAttributeKind.Retain) != 0)
|
||||||
|
return ArgumentSemantic.Retain;
|
||||||
|
else if ((attr & ObjCPropertyAttributeKind.Copy) != 0)
|
||||||
|
return ArgumentSemantic.Copy;
|
||||||
|
else if ((attr & ObjCPropertyAttributeKind.Assign) != 0)
|
||||||
|
return ArgumentSemantic.Assign;
|
||||||
|
else if ((attr & ObjCPropertyAttributeKind.Weak) != 0)
|
||||||
|
return ArgumentSemantic.Weak;
|
||||||
|
else if ((attr & ObjCPropertyAttributeKind.Strong) != 0)
|
||||||
|
return ArgumentSemantic.Strong;
|
||||||
|
else if ((attr & ObjCPropertyAttributeKind.UnsafeUnretained) != 0)
|
||||||
|
return ArgumentSemantic.UnsafeUnretained;
|
||||||
|
else
|
||||||
|
return ArgumentSemantic.Assign; // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToUsableString (this ArgumentSemantic argSem)
|
||||||
|
{
|
||||||
|
if (argSem == ArgumentSemantic.Retain)
|
||||||
|
return "Strong|Retain";
|
||||||
|
if (argSem == ArgumentSemantic.Assign)
|
||||||
|
return "UnsafeUnretained|Assign";
|
||||||
|
|
||||||
|
return argSem.ToString ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,6 @@
|
||||||
// !missing-selector!
|
// !missing-selector!
|
||||||
// if headers defines a selector for which we have no bindings
|
// if headers defines a selector for which we have no bindings
|
||||||
//
|
//
|
||||||
// !unknown-selector!
|
|
||||||
// if we have a selector that is not part of the header files
|
|
||||||
//
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -18,24 +15,9 @@ using Clang.Ast;
|
||||||
namespace Extrospection {
|
namespace Extrospection {
|
||||||
|
|
||||||
public class SelectorCheck : BaseVisitor {
|
public class SelectorCheck : BaseVisitor {
|
||||||
// Dictionary<string,List<MethodDefinition>> exports = new Dictionary<string, List<MethodDefinition>> ();
|
|
||||||
|
|
||||||
// missing
|
|
||||||
// -> it's not in the type or ancestor or their interface (protocols)
|
|
||||||
// -> it's not in a category
|
|
||||||
|
|
||||||
// unknown
|
|
||||||
// -> quick check (HashSet) to see if it's used anywhere
|
|
||||||
// ->
|
|
||||||
|
|
||||||
// duplicate
|
|
||||||
// -> the selector is defined more than once for the same type
|
|
||||||
|
|
||||||
HashSet<string> known_selectors = new HashSet<string> ();
|
|
||||||
|
|
||||||
HashSet<string> qualified_selectors = new HashSet<string> ();
|
HashSet<string> qualified_selectors = new HashSet<string> ();
|
||||||
|
Dictionary<string, Helpers.ArgumentSemantic> qualified_properties = new Dictionary<string, Helpers.ArgumentSemantic> ();
|
||||||
//Dictionary<TypeDefinition,HashSet<string>> type_exports = new Dictionary<TypeDefinition,HashSet<string>> ();
|
|
||||||
|
|
||||||
// most selectors will be found in [Export] attribtues
|
// most selectors will be found in [Export] attribtues
|
||||||
public override void VisitManagedMethod (MethodDefinition method)
|
public override void VisitManagedMethod (MethodDefinition method)
|
||||||
|
@ -51,24 +33,49 @@ namespace Extrospection {
|
||||||
foreach (var ca in method.CustomAttributes) {
|
foreach (var ca in method.CustomAttributes) {
|
||||||
switch (ca.Constructor.DeclaringType.Name) {
|
switch (ca.Constructor.DeclaringType.Name) {
|
||||||
case "ExportAttribute":
|
case "ExportAttribute":
|
||||||
string selector = ca.ConstructorArguments [0].Value as string;
|
var methodDefinition = method.GetName ();
|
||||||
if (!known_selectors.Contains (selector))
|
if (!string.IsNullOrEmpty (methodDefinition)) {
|
||||||
known_selectors.Add (selector);
|
var argumentSemantic = Helpers.ArgumentSemantic.Assign; // Default
|
||||||
|
if (ca.ConstructorArguments.Count > 1) {
|
||||||
|
argumentSemantic = (Helpers.ArgumentSemantic)ca.ConstructorArguments [1].Value;
|
||||||
|
qualified_properties.Add (methodDefinition, argumentSemantic);
|
||||||
|
}
|
||||||
|
|
||||||
|
qualified_selectors.Add (methodDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
qualified_selectors.Add (method.GetName ());
|
|
||||||
//
|
|
||||||
// TypeDefinition type = method.DeclaringType;
|
|
||||||
// HashSet<string> list;
|
|
||||||
// if (!type_exports.TryGetValue (type, out list)) {
|
|
||||||
// list = new HashSet<string> ();
|
|
||||||
// type_exports.Add (type, list);
|
|
||||||
// }
|
|
||||||
// list.Add (selector);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
|
||||||
|
{
|
||||||
|
// protocol members are checked in ObjCProtocolCheck
|
||||||
|
if (decl.DeclContext is ObjCProtocolDecl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check availability macros to see if the API is available on the OS and not deprecated
|
||||||
|
if (!decl.IsAvailable ())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var framework = Helpers.GetFramework (decl);
|
||||||
|
if (framework == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var nativeArgumentSemantic = decl.Attributes.ToArgumentSemantic ();
|
||||||
|
var nativeMethodDefinition = decl.QualifiedName;
|
||||||
|
|
||||||
|
bool found = qualified_properties.TryGetValue (nativeMethodDefinition, out var managedArgumentSemantic);
|
||||||
|
if (found && managedArgumentSemantic != nativeArgumentSemantic) {
|
||||||
|
// FIXME: only Copy mistakes are reported now
|
||||||
|
if (managedArgumentSemantic == Helpers.ArgumentSemantic.Copy || nativeArgumentSemantic == Helpers.ArgumentSemantic.Copy) {
|
||||||
|
// FIXME: rule disactivated for now
|
||||||
|
//Log.On (framework).Add ($"!incorrect-argument-semantic! Native '{nativeMethodDefinition}' is declared as ({nativeArgumentSemantic.ToUsableString ().ToLowerInvariant ()}) but mapped to 'ArgumentSemantic.{managedArgumentSemantic.ToUsableString ()}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
|
public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
|
||||||
{
|
{
|
||||||
if (visitKind != VisitKind.Enter)
|
if (visitKind != VisitKind.Enter)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче