зеркало из https://github.com/dotnet/infer.git
Fixes for RoslynDeclarationProvider and Conversion.TryFindConversion (#271)
* RoslynDeclarationProvider uses all available source codes to build the requested type declaration. * Conversion.TryFindConversion looks for casts defined on the toType as well. Co-authored-by: Dmitry Kats <ratkillerx@hotmail.com>
This commit is contained in:
Родитель
421507bb6e
Коммит
980f1e2513
|
@ -474,9 +474,9 @@ namespace Microsoft.ML.Probabilistic.Compiler.Reflection
|
|||
}
|
||||
}
|
||||
// check for custom conversions
|
||||
MemberInfo[] implicits = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
|
||||
MemberInfo[] implicitsOnFromType = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
|
||||
"op_Implicit");
|
||||
foreach (MemberInfo member in implicits)
|
||||
foreach (MemberInfo member in implicitsOnFromType)
|
||||
{
|
||||
MethodInfo method = (MethodInfo) member;
|
||||
if (method.ReturnType == toType)
|
||||
|
@ -489,9 +489,25 @@ namespace Microsoft.ML.Probabilistic.Compiler.Reflection
|
|||
return true;
|
||||
}
|
||||
}
|
||||
MemberInfo[] explicits = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
|
||||
MemberInfo[] implicitsOnToType = toType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
|
||||
"op_Implicit");
|
||||
foreach (MemberInfo member in implicitsOnToType)
|
||||
{
|
||||
MethodInfo method = (MethodInfo)member;
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
if (parameters.Length == 1 && parameters[0].ParameterType == fromType)
|
||||
{
|
||||
info.SubclassCount = 1000;
|
||||
info.Converter = delegate (object value)
|
||||
{
|
||||
return Util.Invoke(method, null, value);
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
MemberInfo[] explicitsOnFromType = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
|
||||
"op_Explicit");
|
||||
foreach (MemberInfo member in explicits)
|
||||
foreach (MemberInfo member in explicitsOnFromType)
|
||||
{
|
||||
MethodInfo method = (MethodInfo) member;
|
||||
if (method.ReturnType == toType)
|
||||
|
@ -504,6 +520,23 @@ namespace Microsoft.ML.Probabilistic.Compiler.Reflection
|
|||
return true;
|
||||
}
|
||||
}
|
||||
MemberInfo[] explicitsOnToType = toType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
|
||||
"op_Explicit");
|
||||
|
||||
foreach (MemberInfo member in explicitsOnToType)
|
||||
{
|
||||
MethodInfo method = (MethodInfo)member;
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
if (parameters.Length == 1 && parameters[0].ParameterType == fromType)
|
||||
{
|
||||
info.IsExplicit = true;
|
||||
info.Converter = delegate (object value)
|
||||
{
|
||||
return Util.Invoke(method, null, value);
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// lastly try the IConvertible interface
|
||||
if (toType.IsPrimitive)
|
||||
{
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
|
@ -17,17 +16,9 @@ namespace Microsoft.ML.Probabilistic.Compiler
|
|||
{
|
||||
public SourceCode TryGetSource(Type t)
|
||||
{
|
||||
var asm = t.Assembly;
|
||||
return asm.GetManifestResourceNames().Where(s => s.EndsWith(".cs")).Select(s =>
|
||||
bool IsPrimaryFile(SourceFile sf)
|
||||
{
|
||||
var stream = asm.GetManifestResourceStream(s);
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return new SourceCode(s, reader.ReadToEnd());
|
||||
}
|
||||
}).FirstOrDefault(code =>
|
||||
{
|
||||
var tree = CSharpSyntaxTree.ParseText(code.SourceText, null, code.FilePath);
|
||||
var tree = CSharpSyntaxTree.ParseText(sf.SourceText, null, sf.FilePath);
|
||||
var root = tree.GetRoot();
|
||||
var typeDecl = root.DescendantNodes()
|
||||
.OfType<NamespaceDeclarationSyntax>()
|
||||
|
@ -38,7 +29,24 @@ namespace Microsoft.ML.Probabilistic.Compiler
|
|||
.Where(md => md.Identifier.ValueText.Equals(t.Name))
|
||||
.FirstOrDefault();
|
||||
return typeDecl != null;
|
||||
});
|
||||
}
|
||||
var asm = t.Assembly;
|
||||
SourceFile primaryFile = null;
|
||||
List<SourceFile> additionalFiles = new List<SourceFile>();
|
||||
foreach (var s in asm.GetManifestResourceNames().Where(s => s.EndsWith(".cs")))
|
||||
{
|
||||
SourceFile sf;
|
||||
var stream = asm.GetManifestResourceStream(s);
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
sf = new SourceFile(s, reader.ReadToEnd());
|
||||
}
|
||||
if (primaryFile == null && IsPrimaryFile(sf))
|
||||
primaryFile = sf;
|
||||
else
|
||||
additionalFiles.Add(sf);
|
||||
}
|
||||
return primaryFile == null ? null : new SourceCode(primaryFile, additionalFiles.ToImmutableArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,25 +3,41 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Microsoft.ML.Probabilistic.Compiler
|
||||
{
|
||||
public class SourceCode
|
||||
public class SourceFile
|
||||
{
|
||||
public string FilePath { get; }
|
||||
public string SourceText { get; }
|
||||
|
||||
public SourceCode(string filePath, string sourceText)
|
||||
public SourceFile(string filePath, string sourceText)
|
||||
{
|
||||
FilePath = filePath;
|
||||
SourceText = sourceText;
|
||||
}
|
||||
}
|
||||
|
||||
public class SourceCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Source file that contains the primary definition.
|
||||
/// </summary>
|
||||
public SourceFile PrimaryFile { get; }
|
||||
/// <summary>
|
||||
/// Additional files that contain the definitions of some of the types referenced in the primary file.
|
||||
/// Should be used to build a more complete semantic model.
|
||||
/// </summary>
|
||||
public ImmutableArray<SourceFile> AddtionalFiles { get; }
|
||||
|
||||
public SourceCode(SourceFile primaryFile, ImmutableArray<SourceFile> additionalFiles)
|
||||
{
|
||||
PrimaryFile = primaryFile;
|
||||
AddtionalFiles = additionalFiles;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISourceProvider
|
||||
{
|
||||
SourceCode TryGetSource(Type t);
|
||||
|
|
|
@ -71,10 +71,12 @@ namespace Microsoft.ML.Probabilistic.Compiler
|
|||
var source = SourceProvider.TryGetSource(t);
|
||||
if (source == null)
|
||||
throw new InvalidOperationException($"Cannot find source code for the type {t.Name}");
|
||||
var tree = CSharpSyntaxTree.ParseText(source.SourceText, null, source.FilePath, Encoding.UTF8);
|
||||
var primaryTree = CSharpSyntaxTree.ParseText(source.PrimaryFile.SourceText, null, source.PrimaryFile.FilePath, Encoding.UTF8);
|
||||
var allTrees = source.AddtionalFiles.Select(f => CSharpSyntaxTree.ParseText(f.SourceText, null, f.FilePath, Encoding.UTF8)).ToList();
|
||||
allTrees.Add(primaryTree);
|
||||
|
||||
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
|
||||
var targetAssemblyName = Path.GetFileNameWithoutExtension(tree.FilePath);
|
||||
var targetAssemblyName = Path.GetFileNameWithoutExtension(primaryTree.FilePath);
|
||||
var asmName = t.Assembly.GetName();
|
||||
var pk = asmName.GetPublicKey();
|
||||
if (pk != null && pk.Length > 0)
|
||||
|
@ -86,8 +88,8 @@ namespace Microsoft.ML.Probabilistic.Compiler
|
|||
.WithPublicSign(true)
|
||||
.WithCryptoPublicKey(System.Collections.Immutable.ImmutableArray.Create(pk));
|
||||
}
|
||||
var compilation = CSharpCompilation.Create(targetAssemblyName, new[] { tree }, references, options);
|
||||
var model = compilation.GetSemanticModel(tree);
|
||||
var compilation = CSharpCompilation.Create(targetAssemblyName, allTrees, references, options);
|
||||
var model = compilation.GetSemanticModel(primaryTree);
|
||||
|
||||
var errors = compilation.GetDiagnostics().ToList();
|
||||
|
||||
|
|
|
@ -143,6 +143,14 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
Assert.True(Conversion.TryGetConversion(typeof (Tester), typeof (int[]), out conv));
|
||||
o = conv.Converter(t);
|
||||
Console.WriteLine("{0}: {1}", o.GetType(), o);
|
||||
Assert.True(Conversion.TryGetConversion(typeof(int), typeof(Tester), out conv));
|
||||
Assert.True(conv.IsExplicit);
|
||||
Assert.True(Conversion.TryGetConversion(typeof(int[]), typeof(Tester), out conv));
|
||||
Assert.True(conv.IsExplicit);
|
||||
Assert.True(Conversion.TryGetConversion(typeof(ImplicitlyConvertibleToTesterDefinesCast), typeof(Tester), out conv));
|
||||
Assert.False(conv.IsExplicit);
|
||||
Assert.True(Conversion.TryGetConversion(typeof(ImplicitlyConvertibleToTesterCastDefinedOnTester), typeof(Tester), out conv));
|
||||
Assert.False(conv.IsExplicit);
|
||||
|
||||
// conversion from null
|
||||
Assert.False(Conversion.TryGetConversion(typeof (Nullable), typeof (int), out conv));
|
||||
|
@ -842,8 +850,35 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
{
|
||||
return t.arrayField;
|
||||
}
|
||||
|
||||
public static explicit operator Tester(int x)
|
||||
{
|
||||
var tester = new Tester
|
||||
{
|
||||
intField = x
|
||||
};
|
||||
return tester;
|
||||
}
|
||||
|
||||
public static explicit operator Tester(int[] x)
|
||||
{
|
||||
var tester = new Tester
|
||||
{
|
||||
arrayField = x
|
||||
};
|
||||
return tester;
|
||||
}
|
||||
|
||||
public static implicit operator Tester(ImplicitlyConvertibleToTesterCastDefinedOnTester _) => new Tester();
|
||||
}
|
||||
|
||||
public class ImplicitlyConvertibleToTesterDefinesCast
|
||||
{
|
||||
public static implicit operator Tester(ImplicitlyConvertibleToTesterDefinesCast _) => new Tester();
|
||||
}
|
||||
|
||||
public class ImplicitlyConvertibleToTesterCastDefinedOnTester { }
|
||||
|
||||
/// <summary>
|
||||
/// Help class of dynamically invoking methods.
|
||||
/// </summary>
|
||||
|
|
|
@ -70,7 +70,6 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
|
||||
[Fact]
|
||||
[Trait("Category", "CsoftModel")]
|
||||
[Trait("Category", "OpenBug")]
|
||||
public void MethodInAnotherFileTest()
|
||||
{
|
||||
Assert.Throws<CompilationFailedException>(() =>
|
||||
|
|
Загрузка…
Ссылка в новой задаче