Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Linq;
using System.Reflection.Metadata;
using ILVerify;
using Internal.TypeSystem.Ecma;
using Xunit;

namespace ILVerification.Tests
{
public class ILMetadataReferenceTester
{
[Fact]
public static void ReportsUnusedMetadataReferences()
{
(EcmaModule module, VerificationResult[] results) =
VerifyMetadataReferences("UnusedMetadataReferenceTests.dll");

var verifier = new Verifier((ILVerifyTypeSystemContext)module.Context, new VerifierOptions());
Assert.Empty(verifier.Verify(module.PEReader));

AssertResult(results, HandleKind.AssemblyReference, "ILVerifyAssemblyThatDoesNotExist");
AssertResult(results, HandleKind.ModuleReference, "ILVerifyManagedModuleThatDoesNotExist.netmodule");
AssertResult(results, HandleKind.ExportedType, "ILVerifyAssemblyThatDoesNotExist");

// The P/Invoke ModuleRef and resolvable references should not produce additional errors.
Assert.Equal(3, results.Length);
}

[Fact]
public static void ReportsInvalidMetadataReferenceKinds()
{
(_, VerificationResult[] results) =
VerifyMetadataReferences("InvalidMetadataReferenceTests.dll");

Assert.Equal(13, results.Length);
Assert.Equal(1, results.Count(result => result.MetadataHandle.Kind == HandleKind.AssemblyReference));
Assert.Equal(6, results.Count(result => result.MetadataHandle.Kind == HandleKind.TypeReference));
Assert.Equal(2, results.Count(result => result.MetadataHandle.Kind == HandleKind.MemberReference));
Assert.Equal(1, results.Count(result => result.MetadataHandle.Kind == HandleKind.TypeSpecification));
Assert.Equal(1, results.Count(result => result.MetadataHandle.Kind == HandleKind.MethodSpecification));
Assert.Equal(2, results.Count(result => result.MetadataHandle.Kind == HandleKind.StandaloneSignature));

AssertResult(results, HandleKind.AssemblyReference, "ILVerifyAssemblyThatDoesNotExist");
AssertResult(results, HandleKind.TypeReference, "ILVerifyAssemblyThatDoesNotExist");
AssertResult(results, HandleKind.TypeReference, "ILVerifyTypeThatDoesNotExist");
AssertResult(results, HandleKind.MemberReference, "ILVerifyMethodThatDoesNotExist");
AssertResult(results, HandleKind.MemberReference, "ILVerifyFieldThatDoesNotExist");
AssertResult(results, HandleKind.TypeSpecification, "ILVerifyTypeSpecTypeThatDoesNotExist");
AssertResult(results, HandleKind.MethodSpecification, "ILVerifyMethodSpecTypeThatDoesNotExist");
AssertResult(results, HandleKind.StandaloneSignature, "ILVerifyStandaloneMethodTypeThatDoesNotExist");
AssertResult(results, HandleKind.StandaloneSignature, "ILVerifyStandaloneLocalTypeThatDoesNotExist");

Assert.All(results, result =>
{
Assert.False(result.MetadataHandle.IsNil);
Assert.True(result.Code != VerifierError.None || result.ExceptionID != null);
});
}

private static (EcmaModule Module, VerificationResult[] Results) VerifyMetadataReferences(string assemblyName)
{
EcmaModule module = TestDataLoader.GetModuleForTestAssembly(assemblyName);
var verifier = new Verifier((ILVerifyTypeSystemContext)module.Context, new VerifierOptions());

return (module, verifier.VerifyMetadataReferences(module.PEReader).ToArray());
}

private static void AssertResult(
VerificationResult[] results,
HandleKind kind,
string messagePart)
{
Assert.Single(results, result =>
result.MetadataHandle.Kind == kind &&
result.Message.Contains(messagePart, StringComparison.Ordinal));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

.assembly extern System.Private.CoreLib
{
}

.assembly extern ILVerifyAssemblyThatDoesNotExist
{
}

.assembly InvalidMetadataReferenceTests
{
}

.class public auto ansi abstract sealed beforefieldinit InvalidMetadataReferenceTestsType
extends [System.Private.CoreLib]System.Object
{
.method private static void MissingTypeInMissingAssembly() cil managed
{
ldnull
castclass [ILVerifyAssemblyThatDoesNotExist]ILVerifyTypeInMissingAssembly
pop
ret
}

.method private static void MissingTypeInResolvedAssembly() cil managed
{
ldnull
castclass [System.Private.CoreLib]ILVerifyTypeThatDoesNotExist
pop
ret
}

.method private static void MissingMethodReference() cil managed
{
call void [System.Private.CoreLib]System.Object::ILVerifyMethodThatDoesNotExist()
ret
}

.method private static void MissingFieldReference() cil managed
{
ldsfld int32 [System.Private.CoreLib]System.String::ILVerifyFieldThatDoesNotExist
pop
ret
}

.method private static void MissingTypeSpecification() cil managed
{
ldnull
castclass class [System.Private.CoreLib]System.Collections.Generic.List`1<
class [System.Private.CoreLib]ILVerifyTypeSpecTypeThatDoesNotExist>
pop
ret
}

.method private static void GenericMethod<T>() cil managed
{
ret
}

.method private static void MissingMethodSpecification() cil managed
{
call void InvalidMetadataReferenceTestsType::GenericMethod<
class [System.Private.CoreLib]ILVerifyMethodSpecTypeThatDoesNotExist>()
ret
}

.method private static void MissingStandaloneMethodSignature() cil managed
{
ldnull
calli void(class [System.Private.CoreLib]ILVerifyStandaloneMethodTypeThatDoesNotExist)
ret
}

.method private static void MissingStandaloneLocalSignature() cil managed
{
.locals init (
[0] class [System.Private.CoreLib]ILVerifyStandaloneLocalTypeThatDoesNotExist
)

ret
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(MSBuildProjectName).il" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

.assembly extern System.Private.CoreLib
{
}

// Deliberately unresolved. This AssemblyRef is also used by the ExportedType below.
.assembly extern ILVerifyAssemblyThatDoesNotExist
{
}

.assembly UnusedMetadataReferenceTests
{
}

.module extern ILVerifyManagedModuleThatDoesNotExist.netmodule
.module extern ValidMetadataReferenceModule.netmodule

.file ValidMetadataReferenceModule.netmodule

.class extern forwarder MissingForwardedType
{
.assembly extern ILVerifyAssemblyThatDoesNotExist
}

// Provides a resolvable TypeRef to System.Object and contains the P/Invoke method whose
// native-library ModuleRef must not be treated as a managed netmodule dependency.
.class public auto ansi beforefieldinit UnusedMetadataReferenceTestsType
extends [System.Private.CoreLib]System.Object
{
.method public static pinvokeimpl("ILVerifyNativeLibraryThatDoesNotExist" as "NativeMethod")
void NativeMethod() cil managed preservesig
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(MSBuildProjectName).il" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

.assembly extern System.Private.CoreLib
{
}

.module ValidMetadataReferenceModule.netmodule

.class public auto ansi beforefieldinit ValidMetadataReferenceModuleType
extends [System.Private.CoreLib]System.Object
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
<TargetExt>.netmodule</TargetExt>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(MSBuildProjectName).il" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<ItemGroup>
<Compile Include="ILMethodTester.cs" />
<Compile Include="ILMetadataReferenceTester.cs" />
<Compile Include="ILTypeVerificationTester.cs" />
<Compile Include="TestDataLoader.cs" />
<Compile Include="JsonContext.cs" />
Expand All @@ -21,5 +22,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>Tests\%(Filename).dll</TargetPath>
</ProjectReference>

<ProjectReference Update="ILTests\ValidMetadataReferenceModule.ilproj">
<TargetPath>Tests\%(Filename).netmodule</TargetPath>
</ProjectReference>
</ItemGroup>
</Project>
8 changes: 6 additions & 2 deletions src/coreclr/tools/ILVerification.Tests/TestDataLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,13 @@ public static EcmaModule GetModuleForTestAssembly(string assemblyName)
{
var simpleNameToPathMap = new Dictionary<string, string>();

foreach (var fileName in GetAllTestDlls())
foreach (var fileName in Directory.GetFiles(TestAssemblyPath))
{
simpleNameToPathMap.Add(Path.GetFileNameWithoutExtension(fileName), Path.Combine(TestAssemblyPath, fileName));
string name = fileName.ToLower();
if (name.EndsWith(".dll") || name.EndsWith(".netmodule"))
{
simpleNameToPathMap.Add(Path.GetFileNameWithoutExtension(fileName), fileName);
}
}

Assembly coreAssembly = typeof(object).GetTypeInfo().Assembly;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/ILVerification/VerificationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class VerificationResult
public ExceptionStringID? ExceptionID { get; internal set; }
public TypeDefinitionHandle Type { get; internal set; }
public MethodDefinitionHandle Method { get; internal set; }
internal EntityHandle MetadataHandle { get; set; }
public string Message { get; internal set; }
public object[] Args { get; internal set; }
public ErrorArgument[] ErrorArguments { get; set; }
Expand Down
Loading
Loading