未验证 提交 43acdf98 编写于 作者: V Vitek Karas 提交者: GitHub

Produce IL3000 and IL3001 from NativeAOT compiler (#83253)

This also implements the suppression of the IL3002 on the affected methods both in the NativeAOT compiler and the analyzer.

Adds single-file specific tests which are skipped for the trimmer.

Fixes: https://github.com/dotnet/runtime/issues/83088
Fixes: https://github.com/dotnet/runtime/issues/82475
上级 186587ed
......@@ -29,7 +29,7 @@
<IlcSdkPath>$(CoreCLRAotSdkDir)</IlcSdkPath>
<IlcFrameworkPath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkPath>
<IlcFrameworkNativePath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkNativePath>
<NoWarn>$(NoWarn);IL1005;IL3002;IL3003</NoWarn>
<NoWarn>$(NoWarn);IL1005;IL3000;IL3001;IL3002;IL3003</NoWarn>
<TrimMode>partial</TrimMode>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<SuppressAotAnalysisWarnings>true</SuppressAotAnalysisWarnings>
......
......@@ -533,6 +533,27 @@ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMet
}
break;
//
// string System.Reflection.Assembly.Location getter
// string System.Reflection.AssemblyName.CodeBase getter
// string System.Reflection.AssemblyName.EscapedCodeBase getter
//
case IntrinsicId.Assembly_get_Location:
case IntrinsicId.AssemblyName_get_CodeBase:
case IntrinsicId.AssemblyName_get_EscapedCodeBase:
diagnosticContext.AddDiagnostic(DiagnosticId.AvoidAssemblyLocationInSingleFile, calledMethod.GetDisplayName());
break;
//
// string System.Reflection.Assembly.GetFile(string)
// string System.Reflection.Assembly.GetFiles()
// string System.Reflection.Assembly.GetFiles(bool)
//
case IntrinsicId.Assembly_GetFile:
case IntrinsicId.Assembly_GetFiles:
diagnosticContext.AddDiagnostic(DiagnosticId.AvoidAssemblyGetFilesInSingleFile, calledMethod.GetDisplayName());
break;
default:
throw new NotImplementedException("Unhandled intrinsic");
}
......
......@@ -44,6 +44,11 @@ public static IEnumerable<object[]> RequiresCapability ()
return TestNamesBySuiteName ();
}
public static IEnumerable<object[]> SingleFile ()
{
return TestNamesBySuiteName ();
}
public static IEnumerable<object[]> Warnings ()
{
return TestNamesBySuiteName ();
......
......@@ -51,6 +51,13 @@ public void RequiresCapability(string t)
Run(t);
}
[Theory]
[MemberData (nameof (TestDatabase.SingleFile), MemberType = typeof (TestDatabase))]
public void SingleFile (string t)
{
Run (t);
}
[Theory]
[MemberData (nameof (TestDatabase.Warnings), MemberType = typeof (TestDatabase))]
public void Warnings (string t)
......
......@@ -80,9 +80,19 @@ protected override ImmutableArray<ISymbol> GetSpecialIncompatibleMembers (Compil
protected override bool ReportSpecialIncompatibleMembersDiagnostic (OperationAnalysisContext operationContext, ImmutableArray<ISymbol> dangerousPatterns, ISymbol member)
{
if (member is IMethodSymbol && ImmutableArrayOperations.Contains (dangerousPatterns, member, SymbolEqualityComparer.Default)) {
operationContext.ReportDiagnostic (Diagnostic.Create (s_getFilesRule, operationContext.Operation.Syntax.GetLocation (), member.GetDisplayName ()));
return true;
if (member is IMethodSymbol method) {
if (ImmutableArrayOperations.Contains (dangerousPatterns, member, SymbolEqualityComparer.Default)) {
operationContext.ReportDiagnostic (Diagnostic.Create (s_getFilesRule, operationContext.Operation.Syntax.GetLocation (), member.GetDisplayName ()));
return true;
}
else if (method.AssociatedSymbol is ISymbol associatedSymbol &&
ImmutableArrayOperations.Contains (dangerousPatterns, associatedSymbol, SymbolEqualityComparer.Default)) {
// The getters for CodeBase and EscapedCodeBase have RAF attribute on them
// so our caller will produce the RAF warning (IL3002) by default. Since we handle these properties specifically
// here and produce different warning (IL3000) we don't want the caller to produce IL3002.
// So we need to return true from here for the getters, to suppress the RAF warning.
return true;
}
} else if (member is IPropertySymbol && ImmutableArrayOperations.Contains (dangerousPatterns, member, SymbolEqualityComparer.Default)) {
operationContext.ReportDiagnostic (Diagnostic.Create (s_locationRule, operationContext.Operation.Syntax.GetLocation (), member.GetDisplayName ()));
return true;
......
......@@ -288,6 +288,27 @@ internal enum IntrinsicId
/// </summary>
Assembly_CreateInstance,
/// <summary>
/// <see cref="System.Reflection.Assembly.Location"/>
/// </summary>
Assembly_get_Location,
/// <summary>
/// <see cref="System.Reflection.Assembly.GetFile(string)"/>
/// </summary>
Assembly_GetFile,
/// <summary>
/// <see cref="System.Reflection.Assembly.GetFiles()"/>
/// <see cref="System.Reflection.Assembly.GetFiles(bool)"/>
/// </summary>
Assembly_GetFiles,
/// <summary>
/// <see cref="System.Reflection.AssemblyName.CodeBase"/>
/// </summary>
AssemblyName_get_CodeBase,
/// <summary>
/// <see cref="System.Reflection.AssemblyName.EscapedCodeBase"/>
/// </summary>
AssemblyName_get_EscapedCodeBase,
/// <summary>
/// <see cref="System.Reflection.RuntimeReflectionExtensions.GetRuntimeEvent(System.Type, string)"/>
/// </summary>
RuntimeReflectionExtensions_GetRuntimeEvent,
......
......@@ -356,6 +356,29 @@ public static IntrinsicId GetIntrinsicIdForMethod (MethodProxy calledMethod)
&& calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Assembly_CreateInstance,
// System.Reflection.Assembly.Location getter
"get_Location" when calledMethod.IsDeclaredOnType ("System.Reflection.Assembly")
=> IntrinsicId.Assembly_get_Location,
// System.Reflection.Assembly.GetFile (string)
"GetFile" when calledMethod.IsDeclaredOnType ("System.Reflection.Assembly")
&& calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Assembly_GetFile,
// System.Reflection.Assembly.GetFiles ()
// System.Reflection.Assembly.GetFiles (bool)
"GetFiles" when calledMethod.IsDeclaredOnType ("System.Reflection.Assembly")
&& (calledMethod.HasMetadataParametersCount (0) || calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Boolean"))
=> IntrinsicId.Assembly_GetFiles,
// System.Reflection.AssemblyName.CodeBase getter
"get_CodeBase" when calledMethod.IsDeclaredOnType ("System.Reflection.AssemblyName")
=> IntrinsicId.AssemblyName_get_CodeBase,
// System.Reflection.AssemblyName.EscapedCodeBase getter
"get_EscapedCodeBase" when calledMethod.IsDeclaredOnType ("System.Reflection.AssemblyName")
=> IntrinsicId.AssemblyName_get_EscapedCodeBase,
// System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type)
"RunClassConstructor" when calledMethod.IsDeclaredOnType ("System.Runtime.CompilerServices.RuntimeHelpers")
&& calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.RuntimeTypeHandle")
......
......@@ -269,6 +269,11 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c
case IntrinsicId.Marshal_PtrToStructure:
case IntrinsicId.Marshal_DestroyStructure:
case IntrinsicId.Marshal_GetDelegateForFunctionPointer:
case IntrinsicId.Assembly_get_Location:
case IntrinsicId.Assembly_GetFile:
case IntrinsicId.Assembly_GetFiles:
case IntrinsicId.AssemblyName_get_CodeBase:
case IntrinsicId.AssemblyName_get_EscapedCodeBase:
// These intrinsics are not interesting for trimmer (they are interesting for AOT and that's why they are recognized)
break;
......@@ -339,7 +344,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c
// For all other cases, the trimming tools would have already produced a warning.
default:
throw new NotImplementedException ("Unhandled intrinsic");
throw new NotImplementedException ($"Unhandled intrinsic: {intrinsicId}");
}
// If we get here, we handled this as an intrinsic. As a convenience, if the code above
......
......@@ -291,8 +291,6 @@ public void M()
DiagnosticResult.CompilerWarning ("SYSLIB0044").WithSpan (7, 7, 7, 17).WithArguments ("System.Reflection.AssemblyName.CodeBase", "AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported."),
// (8,7): warning SYSLIB0044: 'AssemblyName.EscapedCodeBase' is obsolete: 'AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported.'
DiagnosticResult.CompilerWarning ("SYSLIB0044").WithSpan (8, 7, 8, 24).WithArguments ("System.Reflection.AssemblyName.EscapedCodeBase", "AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported."),
// (7,7): warning IL3002: Using member 'System.Reflection.AssemblyName.CodeBase.get' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. The code will return an empty string for assemblies embedded in a single-file app.
VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (7, 7, 7, 17).WithArguments ("System.Reflection.AssemblyName.CodeBase.get", " The code will return an empty string for assemblies embedded in a single-file app.", ""),
// (7,7): warning IL3000: 'System.Reflection.AssemblyName.CodeBase' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
VerifyCS.Diagnostic (DiagnosticId.AvoidAssemblyLocationInSingleFile).WithSpan (7, 7, 7, 17).WithArguments ("System.Reflection.AssemblyName.CodeBase"),
// (8,7): warning IL3000: 'System.Reflection.AssemblyName.EscapedCodeBase' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
......
using System;
using System.Threading.Tasks;
using Xunit;
namespace ILLink.RoslynAnalyzer.Tests
{
public sealed partial class SingleFileTests : LinkerTestBase
{
protected override string TestSuiteName => "SingleFile";
[Fact]
public Task SingleFileIntrinsics ()
{
return RunTest (allowMissingWarnings: true);
}
}
}
\ No newline at end of file
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics.CodeAnalysis;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
namespace Mono.Linker.Tests.Cases.SingleFile
{
[IgnoreTestCase ("Ignore in illink since it doesn't implement any single-file related functionality", IgnoredBy = Tool.Trimmer)]
[SkipKeptItemsValidation]
[ExpectedNoWarnings]
public class SingleFileIntrinsics
{
// Some of the test methods have RAF on them, it's not the point of this test to verify that behavior
[UnconditionalSuppressMessage("test", "IL3002")]
public static void Main ()
{
TestAssemblyLocation ();
TestAssemblyLocationSuppressedByRAF ();
TestAssemblyNameCodeBase ();
TestAssemblyNameCodeBaseSuppressedByRAF ();
TestAssemblyNameEscapedCodeBase ();
TestAssemblyNameEscapedCodeBaseSuppressedByRAF ();
TestAssemblyGetFile ();
TestAssemblyGetFileSuppressedByRAF ();
TestAssemblyGetFiles ();
TestAssemblyGetFilesSuppressedByRAF ();
}
[ExpectedWarning("IL3000", ProducedBy = Tool.Analyzer | Tool.NativeAot)]
static void TestAssemblyLocation()
{
var a = typeof (SingleFileIntrinsics).Assembly.Location;
}
[RequiresAssemblyFiles("test")]
static void TestAssemblyLocationSuppressedByRAF()
{
var a = typeof (SingleFileIntrinsics).Assembly.Location;
}
[ExpectedWarning ("IL3000", ProducedBy = Tool.Analyzer | Tool.NativeAot)]
static void TestAssemblyNameCodeBase()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetName ().CodeBase;
}
[RequiresAssemblyFiles ("test")]
static void TestAssemblyNameCodeBaseSuppressedByRAF ()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetName ().CodeBase;
}
[ExpectedWarning ("IL3000", ProducedBy = Tool.Analyzer | Tool.NativeAot)]
static void TestAssemblyNameEscapedCodeBase ()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetName ().EscapedCodeBase;
}
[RequiresAssemblyFiles ("test")]
static void TestAssemblyNameEscapedCodeBaseSuppressedByRAF ()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetName ().EscapedCodeBase;
}
[ExpectedWarning ("IL3001", ProducedBy = Tool.Analyzer | Tool.NativeAot)]
static void TestAssemblyGetFile()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetFile ("unknown");
}
[RequiresAssemblyFiles ("test")]
static void TestAssemblyGetFileSuppressedByRAF ()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetFile ("unknown");
}
[ExpectedWarning ("IL3001", ProducedBy = Tool.Analyzer | Tool.NativeAot)]
[ExpectedWarning ("IL3001", ProducedBy = Tool.Analyzer | Tool.NativeAot)]
static void TestAssemblyGetFiles ()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetFiles ();
a = typeof (SingleFileIntrinsics).Assembly.GetFiles (true);
}
[RequiresAssemblyFiles ("test")]
static void TestAssemblyGetFilesSuppressedByRAF ()
{
var a = typeof (SingleFileIntrinsics).Assembly.GetFiles ();
a = typeof (SingleFileIntrinsics).Assembly.GetFiles (true);
}
}
}
......@@ -174,6 +174,11 @@ public static IEnumerable<TestCaseData> SerializationTests ()
return NUnitCasesBySuiteName ("Serialization");
}
public static IEnumerable<TestCaseData> SingleFileTests ()
{
return NUnitCasesBySuiteName ("SingleFile");
}
public static IEnumerable<TestCaseData> StaticsTests ()
{
return NUnitCasesBySuiteName ("Statics");
......
......@@ -208,6 +208,12 @@ public void SerializationTests (TestCase testCase)
Run (testCase);
}
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.SingleFileTests))]
public void SingleFileTests (TestCase testCase)
{
Run (testCase);
}
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.StaticsTests))]
public void StaticsTests (TestCase testCase)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册