forked from microsoft/vstest
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed bugs in ManagedMethod parsing, and updated hierarchies. (micros…
…oft#3704) * Fixed bugs in ManagedMethod parsing, and updated hierarchies.
- Loading branch information
Showing
50 changed files
with
773 additions
and
150 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
playground/AdapterUtilitiesPlayground/AdapterUtilitiesPlayground.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<TestPlatformRoot Condition="$(TestPlatformRoot) == ''">..\..\</TestPlatformRoot> | ||
</PropertyGroup> | ||
<Import Project="$(TestPlatformRoot)scripts/build/TestPlatform.Settings.targets" /> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Microsoft.TestPlatform.AdapterUtilities\Microsoft.TestPlatform.AdapterUtilities.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Newtonsoft.Json" Version="$(JsonNetVersion)" /> | ||
<PackageReference Include="Microsoft.CodeAnalysis" Version="$(MicrosoftCodeAnalysisVersion)" /> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisVersion)" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Compile Update="TestClasses.cs"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
</Compile> | ||
</ItemGroup> | ||
|
||
<Import Project="$(TestPlatformRoot)scripts\build\TestPlatform.targets" /> | ||
</Project> |
101 changes: 101 additions & 0 deletions
101
playground/AdapterUtilitiesPlayground/FindMethodExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.UnitTests; | ||
|
||
[DebuggerStepThrough] | ||
internal static class FindMethodExtensions | ||
{ | ||
private const BindingFlags PrivateBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; | ||
|
||
internal static MethodInfo? FindMethod(this Type type, string signature) | ||
=> type.FindMembers(MemberTypes.Method, PrivateBindingFlags, | ||
(mbr, sig) => mbr.ToString() == (string?)sig, signature).FirstOrDefault() as MethodInfo; | ||
|
||
internal static IMethodSymbol FindMethod( | ||
this INamedTypeSymbol type, | ||
string methodName, | ||
int methodGenericArity = -1, | ||
params ITypeSymbol[] methodParameterTypes) | ||
{ | ||
var candidates = GetCandidateMethods(type, methodName); | ||
if (candidates.Any() && !candidates.Skip(1).Any()) | ||
{ | ||
return candidates.Single(); | ||
} | ||
|
||
if (methodGenericArity != -1) | ||
{ | ||
candidates = candidates.Where(m => m.Arity == methodGenericArity); | ||
if (candidates.Any() && !candidates.Skip(1).Any()) | ||
{ | ||
return candidates.Single(); | ||
} | ||
} | ||
|
||
if (methodParameterTypes != null && methodParameterTypes.Length >= 0) | ||
{ | ||
candidates = candidates.Where(m => m.Parameters.Length == methodParameterTypes.Length); | ||
if (candidates.Any() && !candidates.Skip(1).Any()) | ||
{ | ||
return candidates.Single(); | ||
} | ||
|
||
candidates = candidates.Where(m => m.Parameters.Select(p => p.Type).SequenceEqual(methodParameterTypes)); | ||
} | ||
|
||
Debug.Assert(candidates.Any() && !candidates.Skip(1).Any()); | ||
return candidates.Single(); | ||
} | ||
|
||
internal static IMethodSymbol FindMethod( | ||
this INamedTypeSymbol type, | ||
string methodName, | ||
int methodGenericArity, | ||
int methodParameterCount, | ||
Func<IMethodSymbol, bool> selector) | ||
{ | ||
var candidates = GetCandidateMethods(type, methodName); | ||
if (candidates.Any() && !candidates.Skip(1).Any()) | ||
{ | ||
return candidates.Single(); | ||
} | ||
|
||
candidates = candidates.Where(m => m.Arity == methodGenericArity); | ||
if (candidates.Any() && !candidates.Skip(1).Any()) | ||
{ | ||
return candidates.Single(); | ||
} | ||
|
||
candidates = candidates.Where(m => m.Parameters.Length == methodParameterCount); | ||
if (candidates.Any() && !candidates.Skip(1).Any()) | ||
{ | ||
return candidates.Single(); | ||
} | ||
|
||
candidates = candidates.Where(selector); | ||
|
||
Debug.Assert(candidates.Any() && !candidates.Skip(1).Any()); | ||
return candidates.Single(); | ||
} | ||
|
||
private static IEnumerable<IMethodSymbol> GetCandidateMethods(INamedTypeSymbol type, string methodName) | ||
{ | ||
var candidates = type.GetMembers(methodName).OfType<IMethodSymbol>(); | ||
|
||
if (type.BaseType != null && type.BaseType.SpecialType != SpecialType.System_Object) | ||
{ | ||
candidates = candidates.Union(GetCandidateMethods(type.BaseType, methodName)); | ||
} | ||
|
||
return candidates; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System.Reflection; | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities; | ||
using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.UnitTests; | ||
|
||
namespace AdapterUtilitiesPlayground; | ||
|
||
internal class Program | ||
{ | ||
private const BindingFlags PrivateBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; | ||
private static readonly Compilation _compilation = CSharpCompilation.Create( | ||
"Test.dll", | ||
new[] { CSharpSyntaxTree.ParseText(File.ReadAllText("TestClasses.cs")) }, | ||
new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }); | ||
|
||
static void Main(string[] args) | ||
{ | ||
var derivedClass = typeof(TestClasses.DerivedClass); | ||
var baseClass = typeof(TestClasses.BaseClass); | ||
|
||
var derivedMethods = derivedClass.GetMethods(PrivateBindingFlags).ToArray(); | ||
var baseMethods = baseClass.GetMethods(PrivateBindingFlags).ToArray(); | ||
var derivedMethod0 = derivedMethods.Single(i => i.Name == "Method0" && i.DeclaringType == derivedClass); | ||
var derivedbaseMethod0 = derivedMethods.Single(i => i.Name == "Method0" && i.DeclaringType == baseClass); | ||
var baseMethod0 = baseMethods.Single(i => i.Name == "Method0" && i.DeclaringType == baseClass); | ||
|
||
// { | ||
// ManagedNameHelper.GetManagedName(derivedMethod0, out var managedType, out var managedMethod, out var hierarchies); | ||
// var methodBase = ManagedNameHelper.GetMethod(derivedClass.Assembly, managedType, managedMethod); | ||
// } | ||
// | ||
// { | ||
// ManagedNameHelper.GetManagedName(derivedbaseMethod0, out var managedType, out var managedMethod, out var hierarchies); | ||
// var methodBase = ManagedNameHelper.GetMethod(derivedClass.Assembly, managedType, managedMethod); | ||
// } | ||
|
||
//{ | ||
// ManagedNameHelper.GetManagedName(baseMethod0, out var managedType, out var managedMethod, out var hierarchies); | ||
// var methodBase = ManagedNameHelper.GetMethod(derivedClass.Assembly, managedType, managedMethod); | ||
//} | ||
|
||
{ | ||
var method = typeof(TestClasses.IImplementation<string>).GetMethods(PrivateBindingFlags).SingleOrDefault(i => i.Name == "ImplMethod2")!; | ||
method = method.MakeGenericMethod(typeof(int)); | ||
|
||
ManagedNameHelper.GetManagedName(method, out var managedType, out var managedMethod, out var hierarchies); | ||
var methodBase = ManagedNameHelper.GetMethod(derivedClass.Assembly, managedType, managedMethod); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace TestClasses; | ||
|
||
#pragma warning disable IDE0060 // Remove unused parameter | ||
#pragma warning disable CA1822 // Mark members as static | ||
|
||
internal class DerivedClass : BaseClass | ||
{ | ||
public new void Method0(int i) { } | ||
} | ||
|
||
internal class BaseClass | ||
{ | ||
public void Method0(int i) { } | ||
public void Method1(int i) { } | ||
} | ||
|
||
internal class Outer | ||
{ | ||
public void Method0() { } | ||
public void Method1(int i) { } | ||
public void Method2(List<string> ls) { } | ||
public void Method3(string p, int l) { } | ||
internal class Inner | ||
{ | ||
public void Method0() { } | ||
public void Method1(int i) { } | ||
public void Method2<U>(int i) { } | ||
public void Method3<U, T>(int i) { } | ||
} | ||
} | ||
|
||
internal class OuterPrime : Outer { } | ||
|
||
internal class Outer<T> | ||
{ | ||
public void Method0() { } | ||
public void Method1(T t) { } | ||
public void Method2<U>(U[] u) { } | ||
public void Method3<U>(T t, U u) { } | ||
|
||
internal class Inner<V> | ||
{ | ||
public void Method0() { } | ||
public void Method1(T t) { } | ||
public void Method2(V v) { } | ||
public void Method3<U>(T t, U u, V v) { } | ||
public void Method4<U, X>(X x, U u) { } | ||
public void Method5<U, X>(List<X> x, U u) { } | ||
|
||
internal class MoreInner<I> | ||
{ | ||
public void Method0<U>(T t, V v, I i, U u) { } | ||
} | ||
} | ||
} | ||
|
||
internal class OuterPrime<Z> : Outer<Z> { } | ||
|
||
internal class OuterPrime<Y, Z> : Outer<Z> { } | ||
|
||
internal class OuterString : Outer<string> { } | ||
|
||
internal interface IImplementation | ||
{ | ||
void ImplMethod0(); | ||
void ImplMethod1(int i); | ||
} | ||
|
||
internal class Impl : IImplementation | ||
{ | ||
void IImplementation.ImplMethod0() { } | ||
void IImplementation.ImplMethod1(int i) { } | ||
} | ||
|
||
internal interface IImplementation<T> | ||
{ | ||
void ImplMethod0(); | ||
void ImplMethod1(T t); | ||
void ImplMethod2<U>(T t, U u, string s); | ||
} | ||
|
||
internal class Impl<T> : IImplementation<T> | ||
{ | ||
void IImplementation<T>.ImplMethod0() { } | ||
void IImplementation<T>.ImplMethod1(T t) { } | ||
void IImplementation<T>.ImplMethod2<U>(T t, U u, string s) { } | ||
} | ||
|
||
internal class Overloads | ||
{ | ||
public void Overload0() { } | ||
public void Overload0(int i) { } | ||
public void Overload0(int i, Overloads c) { } | ||
public unsafe void Overload0(int* p) { } | ||
public void Overload0(dynamic d) { } | ||
public void Overload0<U>(U u) { } | ||
public void Overload0<U>() { } | ||
public void Overload0<U, T>() { } | ||
public void Overload0<U>(U[] u) { } | ||
public void Overload0<U>(U[][] u) { } | ||
public void Overload0<U>(U[,] u) { } | ||
public void Overload0<U>(U[,,] u) { } | ||
public void Overload0<U>(List<int> l) { } | ||
public void Overload0<U>(List<U> l) { } | ||
public void Overload0<U, V>(Tuple<U, V> t0, Tuple<V, U> t1) { } | ||
public void Overload0(Tuple<Tuple<string[,], int>> t0) { } | ||
public void Overload0(Tuple<Tuple<string>, Tuple<int>> t) { } | ||
public void Overload0<U>(Tuple<Tuple<Outer<U>.Inner<U>>> t) { } | ||
} | ||
#pragma warning restore IDE0060 // Remove unused parameter | ||
#pragma warning restore CA1822 // Mark members as static |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.