xamarin-macios/tests/xtro-sharpie/DllImportCheck.cs

111 строки
3.1 KiB
C#

//
// The rule reports
//
// !missing-pinvoke!
// if headers defines functions that we have not bound with [DllImport]
//
// !unknown-pinvoke!
// if we have [DllImport] that were not found in headers
// NOTE: introspection tests checks if those exists at runtime, i.e. they might
// just be undocumented (or not in the headers)
//
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Clang.Ast;
namespace Extrospection {
// track all [DllImport]
class DllImportCheck : BaseVisitor {
// dupes :|
Dictionary<string,MethodDefinition> dllimports = new Dictionary<string, MethodDefinition> ();
public override void VisitManagedMethod (MethodDefinition method)
{
if (!method.IsPInvokeImpl || !method.HasPInvokeInfo)
return;
var info = method.PInvokeInfo;
if (info.Module.Name == "__Internal")
return;
// there are duplicates declarations
// TODO: right now we only check the first one, as the priority is knowing if we have (or not) bindings for them
var name = info.EntryPoint;
if (!dllimports.ContainsKey (name))
dllimports.Add (name, method);
}
public override void VisitFunctionDecl (FunctionDecl decl, VisitKind visitKind)
{
if (visitKind != VisitKind.Enter)
return;
// skip macros : we generally implement them but their name is lost (so no matching is possible)
if (!decl.IsExternC)
return;
var name = decl.Name;
// do not consider _* or __* as public API that should be bound
if (name [0] == '_')
return;
// exclude non-framework code (e.g. all unix headers)
var header_file = decl.PresumedLoc.FileName;
var fxh = header_file.IndexOf (".framework/Headers/", StringComparison.Ordinal);
var framework = String.Empty;
if (fxh > 0) {
var start = header_file.LastIndexOf ('/', fxh) + 1;
framework = header_file.Substring (start, fxh - start);
} else {
// FIXME: we only process the headers in Frameworks, not all the UNIX headers
// that still miss a few things (like objc runtime) but nothing that *requires* binding
return;
}
// check availability macros to see if the API is available on the OS and not deprecated
if (!decl.IsAvailable ())
return;
MethodDefinition md;
if (!dllimports.TryGetValue (name, out md)) {
// FIXME: we ignore some frameworks we have not bound (too many entries for our data files)
// we do this late because, in some cases like vImage, we do bind a few API
switch (framework) {
// Accelerate and friends
case "vImage":
case "vecLib":
return;
// security
case "GSS":
return;
// exposed in OpenTK-1.dll
case "OpenAL":
case "OpenGLES":
return;
}
// if we find functions without matching DllImport then we report them
Console.WriteLine ("!missing-pinvoke! {0} is not bound", name);
return;
}
dllimports.Remove (name);
}
public override void End ()
{
// at this stage anything else we have is not something we could find in Apple's headers
// e.g. a typo in the name
foreach (var extra in dllimports.Keys) {
Console.WriteLine ("!unknown-pinvoke! {0} bound", extra);
}
}
}
}