1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 03:27:04 +09:00

Fix type parsing issues in ILLink and ILC (#104060)

- Fixes https://github.com/dotnet/runtime/issues/98955

   We will now produce a warning when a non-assembly-qualified type
   flows into a string location annotated with
   DynamicallyAccessedMembers, and we don't try to look up or mark the
   type (since we don't know which assemblies will be searched at
   runtime by the Type.GetType call).

- Fixes https://github.com/dotnet/runtime/issues/103906

   The ILLink intrinsic handling for `Type.GetType` will now look in
   corelib for generic arguments, matching native AOT.

This replaces the existing warning IL2105. This uses a new warning
instead of repurposing IL2105, because we already documented IL2105
and older versions of ILLink will produce it. Best to avoid any
confusion about them.
This commit is contained in:
Sven Boemer 2024-07-12 14:07:32 -07:00 committed by GitHub
parent 856a0a6f5e
commit 9407c9cfa8
Signed by: github
GPG key ID: B5690EEEBB952194
30 changed files with 308 additions and 136 deletions

View file

@ -1870,6 +1870,22 @@ void TestMethod()
} }
``` ```
#### `IL2122`: Type 'typeName' is not assembly qualified. Type name strings used for dynamically accessing a type should be assembly qualified.
- The type name string passed to a location with `DynamicallyAccessedMembers` requirements was not assembly-qualified, so the trimmer cannot guarantee that the type is preserved. Consider using an assembly-qualified name instead.
```C#
// warning IL2122: Type 'MyClass' is not assembly qualified. Type name strings used for dynamically accessing a type should be assembly qualified.
GetTypeWrapper("MyClass");
class MyClass { }
// May be defined in another assembly, so at runtime Type.GetType will look in that assembly for "MyClass".
void GetTypeWrapper([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] string typeName)
{
var type = Type.GetType(typeName);
}
```
## Single-File Warning Codes ## Single-File Warning Codes

View file

@ -29,7 +29,7 @@
<PublishTrimmed>true</PublishTrimmed> <PublishTrimmed>true</PublishTrimmed>
<!-- Suppress trimming warnings as these are tests --> <!-- Suppress trimming warnings as these are tests -->
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings> <SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<NoWarn>$(NoWarn);IL2103;IL2105;IL2025;IL2111</NoWarn> <NoWarn>$(NoWarn);IL2103;IL2025;IL2111;IL2122</NoWarn>
<!-- Reduce library test app size by trimming framework library features --> <!-- Reduce library test app size by trimming framework library features -->
<DebuggerSupport Condition="'$(DebuggerSupport)' == '' and '$(Configuration)' != 'Debug'">false</DebuggerSupport> <DebuggerSupport Condition="'$(DebuggerSupport)' == '' and '$(Configuration)' != 'Debug'">false</DebuggerSupport>

View file

@ -29,7 +29,7 @@
<IlcSdkPath>$(CoreCLRAotSdkDir)</IlcSdkPath> <IlcSdkPath>$(CoreCLRAotSdkDir)</IlcSdkPath>
<IlcFrameworkPath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkPath> <IlcFrameworkPath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkPath>
<IlcFrameworkNativePath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkNativePath> <IlcFrameworkNativePath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkNativePath>
<NoWarn>$(NoWarn);IL1005;IL2105;IL3000;IL3001;IL3002;IL3003;IL3050;IL3051;IL3052;IL3053</NoWarn> <NoWarn>$(NoWarn);IL1005;IL2122;IL3000;IL3001;IL3002;IL3003;IL3050;IL3051;IL3052;IL3053</NoWarn>
<TrimMode>partial</TrimMode> <TrimMode>partial</TrimMode>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings> <SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<TrimmerSingleWarn>false</TrimmerSingleWarn> <TrimmerSingleWarn>false</TrimmerSingleWarn>

View file

@ -36,13 +36,18 @@ namespace Internal.TypeSystem
} }
public static TypeDesc GetTypeByCustomAttributeTypeNameForDataFlow(string name, ModuleDesc callingModule, public static TypeDesc GetTypeByCustomAttributeTypeNameForDataFlow(string name, ModuleDesc callingModule,
TypeSystemContext context, List<ModuleDesc> referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) TypeSystemContext context, List<ModuleDesc> referencedModules, bool needsAssemblyName, out bool failedBecauseNotFullyQualified)
{ {
typeWasNotFoundInAssemblyNorBaseLibrary = false; failedBecauseNotFullyQualified = false;
if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed, s_typeNameParseOptions)) if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed, s_typeNameParseOptions))
return null; return null;
if (needsAssemblyName && !IsFullyQualified(parsed))
{
failedBecauseNotFullyQualified = true;
return null;
}
TypeNameResolver resolver = new() TypeNameResolver resolver = new()
{ {
_context = context, _context = context,
@ -52,8 +57,33 @@ namespace Internal.TypeSystem
TypeDesc type = resolver.Resolve(parsed); TypeDesc type = resolver.Resolve(parsed);
typeWasNotFoundInAssemblyNorBaseLibrary = resolver._typeWasNotFoundInAssemblyNorBaseLibrary;
return type; return type;
static bool IsFullyQualified(TypeName typeName)
{
if (typeName.AssemblyName is null)
{
return false;
}
if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef)
{
return IsFullyQualified(typeName.GetElementType());
}
if (typeName.IsConstructedGenericType)
{
foreach (var typeArgument in typeName.GetGenericArguments())
{
if (!IsFullyQualified(typeArgument))
{
return false;
}
}
}
return true;
}
} }
private struct TypeNameResolver private struct TypeNameResolver
@ -64,7 +94,6 @@ namespace Internal.TypeSystem
internal Func<ModuleDesc, string, MetadataType> _canonResolver; internal Func<ModuleDesc, string, MetadataType> _canonResolver;
internal List<ModuleDesc> _referencedModules; internal List<ModuleDesc> _referencedModules;
internal bool _typeWasNotFoundInAssemblyNorBaseLibrary;
internal TypeDesc Resolve(TypeName typeName) internal TypeDesc Resolve(TypeName typeName)
{ {
@ -136,8 +165,6 @@ namespace Internal.TypeSystem
return type; return type;
} }
} }
_typeWasNotFoundInAssemblyNorBaseLibrary = true;
} }
if (_throwIfNotFound) if (_throwIfNotFound)

View file

@ -89,12 +89,13 @@ namespace ILCompiler.Dataflow
List<ModuleDesc> referencedModules = new(); List<ModuleDesc> referencedModules = new();
TypeDesc foundType = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeNameForDataFlow(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context, TypeDesc foundType = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeNameForDataFlow(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context,
referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary); referencedModules, needsAssemblyName, out bool failedBecauseNotFullyQualified);
if (foundType == null) if (foundType == null)
{ {
if (needsAssemblyName && typeWasNotFoundInAssemblyNorBaseLibrary) if (failedBecauseNotFullyQualified)
diagnosticContext.AddDiagnostic(DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeName); {
diagnosticContext.AddDiagnostic(DiagnosticId.TypeNameIsNotAssemblyQualified, typeName);
}
type = default; type = default;
return false; return false;
} }

View file

@ -12,6 +12,7 @@ using Internal.TypeSystem.Ecma;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers;
using Mono.Linker.Tests.Extensions; using Mono.Linker.Tests.Extensions;
using Xunit; using Xunit;
using MetadataType = Internal.TypeSystem.MetadataType; using MetadataType = Internal.TypeSystem.MetadataType;

View file

@ -14,7 +14,7 @@ class Program
/// </summary> /// </summary>
static int Main(string[] args) static int Main(string[] args)
{ {
TypeDescriptionProviderAttribute attr = new TypeDescriptionProviderAttribute("Program+MyTypeDescriptionProvider"); TypeDescriptionProviderAttribute attr = new TypeDescriptionProviderAttribute("Program+MyTypeDescriptionProvider, project");
if (!RunTest(attr)) if (!RunTest(attr))
{ {
return -1; return -1;

View file

@ -53,7 +53,7 @@ class Program
} }
} }
[DebuggerTypeProxy("Program+MyClassWithProxyStringProxy")] [DebuggerTypeProxy("Program+MyClassWithProxyStringProxy, project")]
public class MyClassWithProxyString public class MyClassWithProxyString
{ {
public string Name { get; set; } public string Name { get; set; }

View file

@ -113,8 +113,8 @@ class Program
} }
} }
[DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer")] [DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer, project")]
[DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer2", "Program+MyClassWithVisualizerStringVisualizerObjectSource")] [DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer2, project", "Program+MyClassWithVisualizerStringVisualizerObjectSource, project")]
public class MyClassWithVisualizerString public class MyClassWithVisualizerString
{ {
public string Name { get; set; } public string Name { get; set; }

View file

@ -37,7 +37,7 @@
<PropertyGroup Condition="'$(EnableAggressiveTrimming)' == 'true'"> <PropertyGroup Condition="'$(EnableAggressiveTrimming)' == 'true'">
<!-- Suppress trimming warnings as these are tests --> <!-- Suppress trimming warnings as these are tests -->
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings> <SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<NoWarn>$(NoWarn);IL2103;IL2105;IL2025;IL2111</NoWarn> <NoWarn>$(NoWarn);IL2103;IL2025;IL2111;IL2122</NoWarn>
</PropertyGroup> </PropertyGroup>
<!-- This .targets file is also imported by the runtime Trimming tests, and we want to be able to manually configure trimming in them so this <!-- This .targets file is also imported by the runtime Trimming tests, and we want to be able to manually configure trimming in them so this

View file

@ -83,7 +83,7 @@ namespace ILLink.Shared
_unused_RearrangedXmlWarning2 = 2021, _unused_RearrangedXmlWarning2 = 2021,
XmlCouldNotFindMatchingConstructorForCustomAttribute = 2022, XmlCouldNotFindMatchingConstructorForCustomAttribute = 2022,
XmlMoreThanOneReturnElementForMethod = 2023, XmlMoreThanOneReturnElementForMethod = 2023,
XmlMoreThanOneValyForParameterOfMethod = 2024, XmlMoreThanOneValueForParameterOfMethod = 2024,
XmlDuplicatePreserveMember = 2025, XmlDuplicatePreserveMember = 2025,
RequiresUnreferencedCode = 2026, RequiresUnreferencedCode = 2026,
AttributeShouldOnlyBeUsedOnceOnMember = 2027, AttributeShouldOnlyBeUsedOnceOnMember = 2027,
@ -169,7 +169,7 @@ namespace ILLink.Shared
InvalidIsTrimmableValue = 2102, InvalidIsTrimmableValue = 2102,
PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined = 2103, PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined = 2103,
AssemblyProducedTrimWarnings = 2104, AssemblyProducedTrimWarnings = 2104,
TypeWasNotFoundInAssemblyNorBaseLibrary = 2105, _unused_TypeWasNotFoundInAssemblyNorBaseLibrary = 2105,
DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings = 2106, DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings = 2106,
MethodsAreAssociatedWithStateMachine = 2107, MethodsAreAssociatedWithStateMachine = 2107,
InvalidScopeInUnconditionalSuppressMessage = 2108, InvalidScopeInUnconditionalSuppressMessage = 2108,
@ -186,6 +186,7 @@ namespace ILLink.Shared
DynamicallyAccessedMembersOnTypeReferencesCompilerGeneratedMember = 2119, DynamicallyAccessedMembersOnTypeReferencesCompilerGeneratedMember = 2119,
DynamicallyAccessedMembersOnTypeReferencesCompilerGeneratedMemberOnBase = 2120, DynamicallyAccessedMembersOnTypeReferencesCompilerGeneratedMemberOnBase = 2120,
RedundantSuppression = 2121, RedundantSuppression = 2121,
TypeNameIsNotAssemblyQualified = 2122,
// Single-file diagnostic ids. // Single-file diagnostic ids.
AvoidAssemblyLocationInSingleFile = 3000, AvoidAssemblyLocationInSingleFile = 3000,

View file

@ -525,10 +525,10 @@
<data name="XmlMoreThanOneReturnElementForMethodMessage" xml:space="preserve"> <data name="XmlMoreThanOneReturnElementForMethodMessage" xml:space="preserve">
<value>There is more than one 'return' child element specified for method '{0}'.</value> <value>There is more than one 'return' child element specified for method '{0}'.</value>
</data> </data>
<data name="XmlMoreThanOneValyForParameterOfMethodTitle" xml:space="preserve"> <data name="XmlMoreThanOneValueForParameterOfMethodTitle" xml:space="preserve">
<value>Method has more than one parameter for the XML element 'parameter'. There can only be one value specified for each parameter.</value> <value>Method has more than one parameter for the XML element 'parameter'. There can only be one value specified for each parameter.</value>
</data> </data>
<data name="XmlMoreThanOneValyForParameterOfMethodMessage" xml:space="preserve"> <data name="XmlMoreThanOneValueForParameterOfMethodMessage" xml:space="preserve">
<value>More than one value specified for parameter '{0}' of method '{1}'.</value> <value>More than one value specified for parameter '{0}' of method '{1}'.</value>
</data> </data>
<data name="XmlDuplicatePreserveMemberTitle" xml:space="preserve"> <data name="XmlDuplicatePreserveMemberTitle" xml:space="preserve">
@ -1209,4 +1209,10 @@
<data name="InvalidFeatureGuardTitle" xml:space="preserve"> <data name="InvalidFeatureGuardTitle" xml:space="preserve">
<value>Invalid FeatureGuardAttribute.</value> <value>Invalid FeatureGuardAttribute.</value>
</data> </data>
<data name="TypeNameIsNotAssemblyQualifiedMessage" xml:space="preserve">
<value>Type '{0}' is not assembly qualified. Type name strings used for dynamically accessing a type should be assembly qualified.</value>
</data>
<data name="TypeNameIsNotAssemblyQualifiedTitle" xml:space="preserve">
<value>Type name is not assembly qualified.</value>
</data>
</root> </root>

View file

@ -44,7 +44,7 @@ namespace ILLink.Shared.TrimAnalysis
} else if (uniqueValue is SystemTypeValue systemTypeValue) { } else if (uniqueValue is SystemTypeValue systemTypeValue) {
MarkTypeForDynamicallyAccessedMembers (systemTypeValue.RepresentedType, targetValue.DynamicallyAccessedMemberTypes); MarkTypeForDynamicallyAccessedMembers (systemTypeValue.RepresentedType, targetValue.DynamicallyAccessedMemberTypes);
} else if (uniqueValue is KnownStringValue knownStringValue) { } else if (uniqueValue is KnownStringValue knownStringValue) {
if (!TryResolveTypeNameAndMark (knownStringValue.Contents, true, out TypeProxy foundType)) { if (!TryResolveTypeNameAndMark (knownStringValue.Contents, needsAssemblyName: true, out TypeProxy foundType)) {
// Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back. // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
} else { } else {
MarkTypeForDynamicallyAccessedMembers (foundType, targetValue.DynamicallyAccessedMemberTypes); MarkTypeForDynamicallyAccessedMembers (foundType, targetValue.DynamicallyAccessedMemberTypes);

View file

@ -1509,6 +1509,12 @@
<Left>ref/net9.0/illink.dll</Left> <Left>ref/net9.0/illink.dll</Left>
<Right>lib/net9.0/illink.dll</Right> <Right>lib/net9.0/illink.dll</Right>
</Suppression> </Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Mono.Linker.LinkContext.get_SystemModuleName</Target>
<Left>ref/net9.0/illink.dll</Left>
<Right>lib/net9.0/illink.dll</Right>
</Suppression>
<Suppression> <Suppression>
<DiagnosticId>CP0002</DiagnosticId> <DiagnosticId>CP0002</DiagnosticId>
<Target>M:Mono.Linker.LinkContext.set_KeepComInterfaces(System.Boolean)</Target> <Target>M:Mono.Linker.LinkContext.set_KeepComInterfaces(System.Boolean)</Target>
@ -1521,6 +1527,12 @@
<Left>ref/net9.0/illink.dll</Left> <Left>ref/net9.0/illink.dll</Left>
<Right>lib/net9.0/illink.dll</Right> <Right>lib/net9.0/illink.dll</Right>
</Suppression> </Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Mono.Linker.LinkContext.set_SystemModuleName(System.String)</Target>
<Left>ref/net9.0/illink.dll</Left>
<Right>lib/net9.0/illink.dll</Right>
</Suppression>
<Suppression> <Suppression>
<DiagnosticId>CP0008</DiagnosticId> <DiagnosticId>CP0008</DiagnosticId>
<Target>T:Mono.Linker.LinkContext</Target> <Target>T:Mono.Linker.LinkContext</Target>

View file

@ -72,7 +72,7 @@ namespace Mono.Linker.Steps
continue; continue;
} }
CustomAttribute? customAttribute = CreateCustomAttribute (attributeNav, attributeType); CustomAttribute? customAttribute = CreateCustomAttribute (attributeNav, attributeType, provider);
if (customAttribute != null) { if (customAttribute != null) {
_context.LogMessage ($"Assigning external custom attribute '{FormatCustomAttribute (customAttribute)}' instance to '{provider}'."); _context.LogMessage ($"Assigning external custom attribute '{FormatCustomAttribute (customAttribute)}' instance to '{provider}'.");
customAttributesBuilder.Add (customAttribute); customAttributesBuilder.Add (customAttribute);
@ -153,9 +153,9 @@ namespace Mono.Linker.Steps
return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition = td; return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition = td;
} }
CustomAttribute? CreateCustomAttribute (XPathNavigator nav, TypeDefinition attributeType) CustomAttribute? CreateCustomAttribute (XPathNavigator nav, TypeDefinition attributeType, ICustomAttributeProvider provider)
{ {
CustomAttributeArgument[] arguments = ReadCustomAttributeArguments (nav, attributeType); CustomAttributeArgument[] arguments = ReadCustomAttributeArguments (nav, provider);
MethodDefinition? constructor = FindBestMatchingConstructor (attributeType, arguments); MethodDefinition? constructor = FindBestMatchingConstructor (attributeType, arguments);
if (constructor == null) { if (constructor == null) {
@ -223,12 +223,12 @@ namespace Mono.Linker.Steps
} }
} }
CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNavigator nav, TypeDefinition attributeType) CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNavigator nav, ICustomAttributeProvider provider)
{ {
ArrayBuilder<CustomAttributeArgument> args = default; ArrayBuilder<CustomAttributeArgument> args = default;
foreach (XPathNavigator argumentNav in nav.SelectChildren ("argument", string.Empty)) { foreach (XPathNavigator argumentNav in nav.SelectChildren ("argument", string.Empty)) {
CustomAttributeArgument? caa = ReadCustomAttributeArgument (argumentNav, attributeType); CustomAttributeArgument? caa = ReadCustomAttributeArgument (argumentNav, provider);
if (caa is not null) if (caa is not null)
args.Add (caa.Value); args.Add (caa.Value);
} }
@ -236,9 +236,9 @@ namespace Mono.Linker.Steps
return args.ToArray () ?? Array.Empty<CustomAttributeArgument> (); return args.ToArray () ?? Array.Empty<CustomAttributeArgument> ();
} }
CustomAttributeArgument? ReadCustomAttributeArgument (XPathNavigator nav, IMemberDefinition memberWithAttribute) CustomAttributeArgument? ReadCustomAttributeArgument (XPathNavigator nav, ICustomAttributeProvider provider)
{ {
TypeReference? typeref = ResolveArgumentType (nav, memberWithAttribute); TypeReference? typeref = ResolveArgumentType (nav, provider);
if (typeref is null) if (typeref is null)
return null; return null;
@ -295,8 +295,8 @@ namespace Mono.Linker.Steps
if (!typeref.IsTypeOf (WellKnownType.System_Type)) if (!typeref.IsTypeOf (WellKnownType.System_Type))
goto default; goto default;
var diagnosticContext = new DiagnosticContext (new MessageOrigin (memberWithAttribute), diagnosticsEnabled: true, _context); var diagnosticContext = new DiagnosticContext (new MessageOrigin (provider), diagnosticsEnabled: true, _context);
if (!_context.TypeNameResolver.TryResolveTypeName (svalue, diagnosticContext, out TypeReference? type, out _)) { if (!_context.TypeNameResolver.TryResolveTypeName (svalue, diagnosticContext, out TypeReference? type, out _, needsAssemblyName: false)) {
_context.LogError (GetMessageOriginForPosition (nav), DiagnosticId.CouldNotResolveCustomAttributeTypeValue, svalue); _context.LogError (GetMessageOriginForPosition (nav), DiagnosticId.CouldNotResolveCustomAttributeTypeValue, svalue);
return null; return null;
} }
@ -308,7 +308,7 @@ namespace Mono.Linker.Steps
var arrayArgumentIterator = nav.SelectChildren ("argument", string.Empty); var arrayArgumentIterator = nav.SelectChildren ("argument", string.Empty);
ArrayBuilder<CustomAttributeArgument> elements = default; ArrayBuilder<CustomAttributeArgument> elements = default;
foreach (XPathNavigator elementNav in arrayArgumentIterator) { foreach (XPathNavigator elementNav in arrayArgumentIterator) {
if (ReadCustomAttributeArgument (elementNav, memberWithAttribute) is CustomAttributeArgument arg) { if (ReadCustomAttributeArgument (elementNav, provider) is CustomAttributeArgument arg) {
// To match Cecil, elements of a list that are subclasses of the list type must be boxed in the base type // To match Cecil, elements of a list that are subclasses of the list type must be boxed in the base type
// e.g. object[] { 73 } translates to Cecil.CAA { Type: object[] : Value: CAA{ Type: object, Value: CAA{ Type: int, Value: 73} } } // e.g. object[] { 73 } translates to Cecil.CAA { Type: object[] : Value: CAA{ Type: object, Value: CAA{ Type: int, Value: 73} } }
if (arg.Type == elementType) { if (arg.Type == elementType) {
@ -338,14 +338,14 @@ namespace Mono.Linker.Steps
return null; return null;
} }
TypeReference? ResolveArgumentType (XPathNavigator nav, IMemberDefinition memberWithAttribute) TypeReference? ResolveArgumentType (XPathNavigator nav, ICustomAttributeProvider provider)
{ {
string typeName = GetAttribute (nav, "type"); string typeName = GetAttribute (nav, "type");
if (string.IsNullOrEmpty (typeName)) if (string.IsNullOrEmpty (typeName))
typeName = "System.String"; typeName = "System.String";
var diagnosticContext = new DiagnosticContext (new MessageOrigin (memberWithAttribute), diagnosticsEnabled: true, _context); var diagnosticContext = new DiagnosticContext (new MessageOrigin (provider), diagnosticsEnabled: true, _context);
if (!_context.TypeNameResolver.TryResolveTypeName (typeName, diagnosticContext, out TypeReference? typeref, out _)) { if (!_context.TypeNameResolver.TryResolveTypeName (typeName, diagnosticContext, out TypeReference? typeref, out _, needsAssemblyName: false)) {
_context.LogError (GetMessageOriginForPosition (nav), DiagnosticId.TypeUsedWithAttributeValueCouldNotBeFound, typeName, nav.Value); _context.LogError (GetMessageOriginForPosition (nav), DiagnosticId.TypeUsedWithAttributeValueCouldNotBeFound, typeName, nav.Value);
return null; return null;
} }
@ -501,7 +501,7 @@ namespace Mono.Linker.Steps
foreach (ParameterDefinition parameter in method.Parameters) { foreach (ParameterDefinition parameter in method.Parameters) {
if (paramName == parameter.Name) { if (paramName == parameter.Name) {
if (parameter.HasCustomAttributes || _attributeInfo.CustomAttributes.ContainsKey (parameter)) if (parameter.HasCustomAttributes || _attributeInfo.CustomAttributes.ContainsKey (parameter))
LogWarning (parameterNav, DiagnosticId.XmlMoreThanOneValyForParameterOfMethod, paramName, method.GetDisplayName ()); LogWarning (parameterNav, DiagnosticId.XmlMoreThanOneValueForParameterOfMethod, paramName, method.GetDisplayName ());
_attributeInfo.AddCustomAttributes (parameter, attributes, origins); _attributeInfo.AddCustomAttributes (parameter, attributes, origins);
break; break;
} }
@ -513,11 +513,15 @@ namespace Mono.Linker.Steps
void ProcessReturnParameters (MethodDefinition method, XPathNavigator nav) void ProcessReturnParameters (MethodDefinition method, XPathNavigator nav)
{ {
Debug.Assert (_attributeInfo != null);
bool firstAppearance = true; bool firstAppearance = true;
foreach (XPathNavigator returnNav in nav.SelectChildren ("return", string.Empty)) { foreach (XPathNavigator returnNav in nav.SelectChildren ("return", string.Empty)) {
if (firstAppearance) { if (firstAppearance) {
firstAppearance = false; firstAppearance = false;
PopulateAttributeInfo (method.MethodReturnType, returnNav); var (attributes, origins) = ProcessAttributes (returnNav, method);
if (attributes != null && origins != null) {
_attributeInfo.AddCustomAttributes (method.MethodReturnType, attributes, origins);
}
} else { } else {
LogWarning (returnNav, DiagnosticId.XmlMoreThanOneReturnElementForMethod, method.GetDisplayName ()); LogWarning (returnNav, DiagnosticId.XmlMoreThanOneReturnElementForMethod, method.GetDisplayName ());
} }

View file

@ -45,10 +45,6 @@ using Mono.Cecil.Cil;
using Mono.Collections.Generic; using Mono.Collections.Generic;
using Mono.Linker.Dataflow; using Mono.Linker.Dataflow;
using AssemblyNameInfo = System.Reflection.Metadata.AssemblyNameInfo;
using TypeName = System.Reflection.Metadata.TypeName;
using TypeNameParseOptions = System.Reflection.Metadata.TypeNameParseOptions;
namespace Mono.Linker.Steps namespace Mono.Linker.Steps
{ {

View file

@ -68,7 +68,7 @@ namespace Mono.Linker
int? _targetRuntime; int? _targetRuntime;
readonly AssemblyResolver _resolver; readonly AssemblyResolver _resolver;
readonly TypeNameResolver _typeNameResolver; TypeNameResolver? _typeNameResolver;
readonly AnnotationStore _annotations; readonly AnnotationStore _annotations;
readonly CustomAttributeSource _customAttributes; readonly CustomAttributeSource _customAttributes;
@ -146,9 +146,8 @@ namespace Mono.Linker
get { return _resolver; } get { return _resolver; }
} }
internal TypeNameResolver TypeNameResolver { internal TypeNameResolver TypeNameResolver
get { return _typeNameResolver; } => _typeNameResolver ??= new TypeNameResolver (this, this);
}
public ISymbolReaderProvider SymbolReaderProvider { get; set; } public ISymbolReaderProvider SymbolReaderProvider { get; set; }
@ -205,7 +204,6 @@ namespace Mono.Linker
_logger = logger ?? throw new ArgumentNullException (nameof (logger)); _logger = logger ?? throw new ArgumentNullException (nameof (logger));
_resolver = factory.CreateResolver (this); _resolver = factory.CreateResolver (this);
_typeNameResolver = new TypeNameResolver (this, this);
_actions = new Dictionary<string, AssemblyAction> (); _actions = new Dictionary<string, AssemblyAction> ();
_parameters = new Dictionary<string, string> (StringComparer.Ordinal); _parameters = new Dictionary<string, string> (StringComparer.Ordinal);
_customAttributes = new CustomAttributeSource (this); _customAttributes = new CustomAttributeSource (this);
@ -973,7 +971,7 @@ namespace Mono.Linker
public TypeDefinition? TryResolve (AssemblyDefinition assembly, string typeNameString) public TypeDefinition? TryResolve (AssemblyDefinition assembly, string typeNameString)
{ {
// It could be cached if it shows up on fast path // It could be cached if it shows up on fast path
return _typeNameResolver.TryResolveTypeName (assembly, typeNameString, out TypeReference? typeReference, out _) return TypeNameResolver.TryResolveTypeName (assembly, typeNameString, out TypeReference? typeReference, out _)
? TryResolve (typeReference) ? TryResolve (typeReference)
: null; : null;
} }

View file

@ -7,10 +7,8 @@ using System.Diagnostics.CodeAnalysis;
using ILLink.Shared; using ILLink.Shared;
using ILLink.Shared.TrimAnalysis; using ILLink.Shared.TrimAnalysis;
using Mono.Cecil; using Mono.Cecil;
using Mono.Linker;
using TypeName = System.Reflection.Metadata.TypeName; using TypeName = System.Reflection.Metadata.TypeName;
using AssemblyNameInfo = System.Reflection.Metadata.AssemblyNameInfo;
namespace Mono.Linker namespace Mono.Linker
{ {
@ -21,7 +19,7 @@ namespace Mono.Linker
in DiagnosticContext diagnosticContext, in DiagnosticContext diagnosticContext,
[NotNullWhen (true)] out TypeReference? typeReference, [NotNullWhen (true)] out TypeReference? typeReference,
[NotNullWhen (true)] out List<TypeResolutionRecord>? typeResolutionRecords, [NotNullWhen (true)] out List<TypeResolutionRecord>? typeResolutionRecords,
bool needsAssemblyName = true) bool needsAssemblyName)
{ {
typeReference = null; typeReference = null;
typeResolutionRecords = null; typeResolutionRecords = null;
@ -31,28 +29,16 @@ namespace Mono.Linker
if (!TypeName.TryParse (typeNameString, out TypeName? parsedTypeName, s_typeNameParseOptions)) if (!TypeName.TryParse (typeNameString, out TypeName? parsedTypeName, s_typeNameParseOptions))
return false; return false;
typeResolutionRecords = new List<TypeResolutionRecord> (); if (needsAssemblyName && !IsFullyQualified (parsedTypeName)) {
AssemblyDefinition? typeAssembly; diagnosticContext.AddDiagnostic (DiagnosticId.TypeNameIsNotAssemblyQualified, typeNameString);
if (parsedTypeName.AssemblyName is AssemblyNameInfo assemblyName) { return false;
typeAssembly = _assemblyResolver.TryResolve (assemblyName.Name);
if (typeAssembly is null) {
typeResolutionRecords = null;
return false;
}
typeReference = ResolveTypeName (typeAssembly, parsedTypeName, typeResolutionRecords);
if (typeReference == null) {
typeResolutionRecords = null;
}
return typeReference != null;
} }
// If parsedTypeName doesn't have an assembly name in it but it does have a namespace, // If parsedTypeName doesn't have an assembly name in it but it does have a namespace,
// search for the type in the calling object's assembly. If not found, look in the core // search for the type in the calling object's assembly. If not found, look in the core
// assembly. // assembly.
ICustomAttributeProvider? provider = diagnosticContext.Origin.Provider; ICustomAttributeProvider? provider = diagnosticContext.Origin.Provider;
typeAssembly = provider switch { AssemblyDefinition? referencingAssembly = provider switch {
AssemblyDefinition asm => asm, AssemblyDefinition asm => asm,
TypeDefinition type => type.Module?.Assembly, TypeDefinition type => type.Module?.Assembly,
IMemberDefinition member => member.DeclaringType.Module.Assembly, IMemberDefinition member => member.DeclaringType.Module.Assembly,
@ -60,30 +46,29 @@ namespace Mono.Linker
_ => throw new NotSupportedException () _ => throw new NotSupportedException ()
}; };
if (typeAssembly != null && TryResolveTypeName (typeAssembly, parsedTypeName, out typeReference, typeResolutionRecords)) if (referencingAssembly is null)
return true; return false;
// If type is not found in the caller's assembly, try in core assembly. typeResolutionRecords = new List<TypeResolutionRecord> ();
typeAssembly = _assemblyResolver.TryResolve (PlatformAssemblies.CoreLib); typeReference = ResolveTypeName (referencingAssembly, parsedTypeName, typeResolutionRecords);
if (typeAssembly != null && TryResolveTypeName (typeAssembly, parsedTypeName, out typeReference, typeResolutionRecords)) return typeReference != null;
return true;
// It is common to use Type.GetType for looking if a type is available. static bool IsFullyQualified (TypeName typeName)
// If no type was found only warn and return null.
if (needsAssemblyName && provider != null)
diagnosticContext.AddDiagnostic (DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeNameString);
typeResolutionRecords = null;
return false;
bool TryResolveTypeName (AssemblyDefinition assemblyDefinition, TypeName? typeName, [NotNullWhen (true)] out TypeReference? typeReference, List<TypeResolutionRecord> typeResolutionRecords)
{ {
typeReference = null; if (typeName.AssemblyName is null)
if (assemblyDefinition == null)
return false; return false;
typeReference = ResolveTypeName (assemblyDefinition, typeName, typeResolutionRecords); if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef)
return typeReference != null; return IsFullyQualified (typeName.GetElementType ());
if (typeName.IsConstructedGenericType) {
foreach (var typeArgument in typeName.GetGenericArguments ()) {
if (!IsFullyQualified (typeArgument))
return false;
}
}
return true;
} }
} }
} }

View file

@ -107,6 +107,19 @@ namespace Mono.Linker
return resolvedType; return resolvedType;
} }
// If it didn't resolve and wasn't assembly-qualified, we also try core library
var coreLibrary = _metadataResolver.TryResolve (originalAssembly.MainModule.TypeSystem.Object)?.Module.Assembly;
if (coreLibrary is null)
return null;
if (topLevelTypeName.AssemblyName == null && assembly != coreLibrary) {
resolvedType = GetSimpleTypeFromModule (typeName, coreLibrary.MainModule);
if (resolvedType != null) {
typeResolutionRecords.Add (new (coreLibrary, resolvedType));
return resolvedType;
}
}
return null; return null;
TypeDefinition? GetSimpleTypeFromModule (TypeName typeName, ModuleDefinition module) TypeDefinition? GetSimpleTypeFromModule (TypeName typeName, ModuleDefinition module)

View file

@ -45,8 +45,8 @@ namespace Mono.Linker.Tests.Cases.ComponentModel
[Kept] [Kept]
[KeptAttributeAttribute (typeof (TypeConverterAttribute))] [KeptAttributeAttribute (typeof (TypeConverterAttribute))]
[KeptBackingField] [KeptBackingField]
[ExpectedWarning ("IL2105", [ExpectedWarning ("IL2122",
"Type 'NonExistentType' was not found in the caller assembly nor in the base library. " + "Type 'NonExistentType' is not assembly qualified. " +
"Type name strings used for dynamically accessing a type should be assembly qualified.")] "Type name strings used for dynamically accessing a type should be assembly qualified.")]
public string Bar { [Kept] get; set; } public string Bar { [Kept] get; set; }

View file

@ -78,7 +78,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[Kept] [Kept]
static void TestFromStringContantWithAnnotation () static void TestFromStringContantWithAnnotation ()
{ {
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithAnnotationTestType"); RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithAnnotationTestType, test");
} }
[Kept] [Kept]
@ -188,10 +188,19 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[UnconditionalSuppressMessage("test", "IL3050", Justification = "The test applies DAM on System.Array, which contains CreateInstance method which has RDC on it.")] [UnconditionalSuppressMessage("test", "IL3050", Justification = "The test applies DAM on System.Array, which contains CreateInstance method which has RDC on it.")]
static void TestFromStringConstantWithGeneric () static void TestFromStringConstantWithGeneric ()
{ {
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1[[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInner]]"); RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1["
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericTwoParameters`2[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerOne`1[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerInner],Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerTwo]"); + "[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInner, test]"
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1[[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWitGenericInnerMultiDimArray[,]]]"); + "], test");
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithMultiDimArray[,]"); RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericTwoParameters`2["
+ "[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerOne`1["
+ "[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerInner, test]"
+ "], test],"
+ "[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerTwo, test]"
+ "], test");
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1["
+ "[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWitGenericInnerMultiDimArray[,], test]"
+ "], test");
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithMultiDimArray[,], test");
} }
[Kept] [Kept]
@ -205,7 +214,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[Kept] [Kept]
static void TestFromStringConstantWithGenericAndAssemblyQualified () static void TestFromStringConstantWithGenericAndAssemblyQualified ()
{ {
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericAndAssemblyQualified`1[[Mono.Linker.Tests.Cases.Expectations.Assertions.KeptAttribute,Mono.Linker.Tests.Cases.Expectations]]"); RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericAndAssemblyQualified`1["
+ "[Mono.Linker.Tests.Cases.Expectations.Assertions.KeptAttribute, Mono.Linker.Tests.Cases.Expectations]"
+ "], test");
} }
class InvalidAssemblyNameType class InvalidAssemblyNameType

View file

@ -58,7 +58,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
RequireNothing (type); RequireNothing (type);
} }
[ExpectedWarning ("IL2105", "Type 'System.Invalid.TypeName' was not found in the caller assembly nor in the base library. " + "Type name strings used for dynamically accessing a type should be assembly qualified.", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] [ExpectedWarning ("IL2122", "Type 'System.Invalid.TypeName' is not assembly qualified. " + "Type name strings used for dynamically accessing a type should be assembly qualified.", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestUnqualifiedTypeNameWarns () static void TestUnqualifiedTypeNameWarns ()
{ {
RequirePublicConstructors ("System.Invalid.TypeName"); RequirePublicConstructors ("System.Invalid.TypeName");

View file

@ -22,7 +22,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))]
[KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeptAttributeAttribute (typeof (TypeArrayAttribute))]
[KeepsPublicConstructor (typeof (ClassWithKeptPublicConstructor))] [KeepsPublicConstructor (typeof (ClassWithKeptPublicConstructor))]
[KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributeConstructorDataflow+ClassWithKeptPublicMethods")] [KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributeConstructorDataflow+ClassWithKeptPublicMethods, test")]
[KeepsPublicFields (null, null)] [KeepsPublicFields (null, null)]
[TypeArray (new Type[] { typeof (AttributeConstructorDataflow) })] [TypeArray (new Type[] { typeof (AttributeConstructorDataflow) })]
[ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2273")] [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2273")]

View file

@ -40,9 +40,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[Kept] [Kept]
[KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))]
// Trimmer/NativeAot only for now - https://github.com/dotnet/linker/issues/2273
[ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods")] [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods, test")]
public static void TestKeepsPublicMethodsString () public static void TestKeepsPublicMethodsString ()
{ {
typeof (AttributeFieldDataflow).GetMethod (nameof (TestKeepsPublicMethodsString)).GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); typeof (AttributeFieldDataflow).GetMethod (nameof (TestKeepsPublicMethodsString)).GetCustomAttribute (typeof (KeepsPublicMethodsAttribute));

View file

@ -57,7 +57,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))]
// Trimmer/NativeAot only for now // Trimmer/NativeAot only for now
[ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethodsKeptByName--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethodsKeptByName--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributesOnMethod+ClassWithKeptPublicMethodsKeptByName")] [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributesOnMethod+ClassWithKeptPublicMethodsKeptByName, test")]
public static void TestKeepsPublicMethodsByName () public static void TestKeepsPublicMethodsByName ()
{ {
typeof (AttributesOnMethod).GetMethod (nameof (TestKeepsPublicMethodsByName)).GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); typeof (AttributesOnMethod).GetMethod (nameof (TestKeepsPublicMethodsByName)).GetCustomAttribute (typeof (KeepsPublicMethodsAttribute));
@ -213,7 +213,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))]
// Trimmer/NativeAot only for now // Trimmer/NativeAot only for now
[ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethods" : null)] [KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethodsKeptByName, test" : null)]
public static void Test () public static void Test ()
{ {
typeof (AttributeWithConditionalExpression).GetMethod ("Test").GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); typeof (AttributeWithConditionalExpression).GetMethod ("Test").GetCustomAttribute (typeof (KeepsPublicMethodsAttribute));
@ -225,11 +225,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[Kept] [Kept]
[KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))]
[ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethods" : null)] [KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethodsKeptByName, test" : null)]
public static int field; public static int field;
[Kept] [Kept]
class ClassWithKeptPublicMethods class ClassWithKeptPublicMethodsKeptByName
{ {
[Kept] [Kept]
[KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]

View file

@ -1372,29 +1372,32 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{ {
static void MethodWithAnnotatedParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] string typeName) { } static void MethodWithAnnotatedParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] string typeName) { }
// Analyzer: https://github.com/dotnet/runtime/issues/95118 [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")]
static void AnnotatedParameter () static void AnnotatedParameter ()
{ {
MethodWithAnnotatedParameter ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"); MethodWithAnnotatedParameter ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[["
+ "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod, test"
+ "]], test");
} }
// Analyzer: https://github.com/dotnet/runtime/issues/95118 [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
static string AnnotatedReturnValue () static string AnnotatedReturnValue ()
{ {
return "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"; return "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[["
+ "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod, test"
+ "]], test";
} }
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
static string _annotatedField; static string _annotatedField;
// Analyzer: https://github.com/dotnet/runtime/issues/95118 [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")]
static void AnnotatedField () static void AnnotatedField ()
{ {
_annotatedField = "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"; _annotatedField = "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[["
+ "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod, test"
+ "]], test";
} }
public static void Test () public static void Test ()
@ -1407,11 +1410,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class TypeGetType class TypeGetType
{ {
// Analyzer: https://github.com/dotnet/runtime/issues/95118 [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")]
static void SpecificType () static void SpecificType ()
{ {
Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"); Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[["
+ "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod"
+ "]]");
} }
public static void Test () public static void Test ()

View file

@ -3,12 +3,12 @@
{ {
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
} }
.assembly 'library' .assembly 'EscapedTypeNames'
{ {
.hash algorithm 0x00008004 .hash algorithm 0x00008004
.ver 1:0:0:0 .ver 1:0:0:0
} }
.module library.dll .module EscapedTypeNames.dll
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================

View file

@ -0,0 +1,14 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace Mono.Linker.Tests.Cases.Reflection.Dependencies
{
public class RequireHelper
{
public static Type RequireType ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] string type) {
return Type.GetType (type);
}
}
public class TypeDefinedInSameAssemblyAsGetType {}
}

View file

@ -4,16 +4,19 @@ using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers; using Mono.Linker.Tests.Cases.Expectations.Helpers;
using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.Expectations.Metadata;
using Mono.Linker.Tests.Cases.Reflection.Dependencies;
namespace Mono.Linker.Tests.Cases.Reflection namespace Mono.Linker.Tests.Cases.Reflection
{ {
[KeptMember (".cctor()")] [KeptMember (".cctor()")]
[ExpectedNoWarnings ()] [ExpectedNoWarnings ()]
[Define ("IL_ASSEMBLY_AVAILABLE")] [Define ("IL_ASSEMBLY_AVAILABLE")]
[SetupCompileBefore ("library.dll", new[] { "Dependencies/EscapedTypeNames.il" })] [SetupCompileBefore ("EscapedTypeNames.dll", new[] { "Dependencies/EscapedTypeNames.il" })]
[KeptTypeInAssembly ("library", "Library.Not\\+Nested")] [SetupCompileBefore ("RequireHelper.dll", new[] { "Dependencies/RequireHelper.cs" })]
[KeptTypeInAssembly ("library", "Library.Not\\+Nested+Nes\\\\ted")] [KeptTypeInAssembly ("EscapedTypeNames", "Library.Not\\+Nested")]
[KeptTypeInAssembly ("library", "Library.Not\\+Nested+Nes/ted")] [KeptTypeInAssembly ("EscapedTypeNames", "Library.Not\\+Nested+Nes\\\\ted")]
[KeptTypeInAssembly ("EscapedTypeNames", "Library.Not\\+Nested+Nes/ted")]
[RemovedTypeInAssembly ("RequireHelper", typeof (TypeDefinedInSameAssemblyAsGetType))]
[KeptDelegateCacheField ("0", nameof (AssemblyResolver))] [KeptDelegateCacheField ("0", nameof (AssemblyResolver))]
[KeptDelegateCacheField ("1", nameof (GetTypeFromAssembly))] [KeptDelegateCacheField ("1", nameof (GetTypeFromAssembly))]
public class TypeUsedViaReflection public class TypeUsedViaReflection
@ -31,8 +34,9 @@ namespace Mono.Linker.Tests.Cases.Reflection
TestReference (); TestReference ();
TestArray (); TestArray ();
TestArrayOfArray (); TestArrayOfArray ();
TestGenericArray (); TestGenericInstantiation ();
TestGenericArrayFullString (); TestGenericInstantiationFullString ();
TestGenericInstantiationOverCoreLib ();
TestMultiDimensionalArray (); TestMultiDimensionalArray ();
TestMultiDimensionalArrayFullString (); TestMultiDimensionalArrayFullString ();
TestMultiDimensionalArrayAsmName (); TestMultiDimensionalArrayAsmName ();
@ -55,6 +59,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
TestInvalidTypeCombination (); TestInvalidTypeCombination ();
TestEscapedTypeName (); TestEscapedTypeName ();
AssemblyTypeResolutionBehavior.Test ();
} }
[Kept] [Kept]
@ -92,30 +97,42 @@ namespace Mono.Linker.Tests.Cases.Reflection
} }
[Kept] [Kept]
public class GenericArray<T> { } public class GenericInstantiation<T> { }
[Kept] [Kept]
public class GenericArgument { } public class GenericArgument { }
[Kept] [Kept]
public static void TestGenericArray () public static void TestGenericInstantiation ()
{ {
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArray`1[[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArgument]]"; const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiation`1[[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArgument]]";
var typeKept = Type.GetType (reflectionTypeKeptString, false); var typeKept = Type.GetType (reflectionTypeKeptString, false);
} }
[Kept] [Kept]
public class GenericArrayFullString<T> { } public class GenericInstantiationFullString<T> { }
[Kept] [Kept]
public class GenericArgumentFullString { } public class GenericArgumentFullString { }
[Kept] [Kept]
public static void TestGenericArrayFullString () public static void TestGenericInstantiationFullString ()
{ {
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArrayFullString`1" + const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiationFullString`1["
"[[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArgumentFullString, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]," + + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArgumentFullString, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]"
" test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; + "], test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
var typeKept = Type.GetType (reflectionTypeKeptString, false);
}
[Kept]
public class GenericInstantiationOverCoreLib<T> { }
[Kept]
public static void TestGenericInstantiationOverCoreLib ()
{
// Note: the argument type should not be assembly-qualified for this test, which is checking that
// we can resolve non-assembly-qualified generic argument types from corelib.
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiationOverCoreLib`1[[System.String]], test";
var typeKept = Type.GetType (reflectionTypeKeptString, false); var typeKept = Type.GetType (reflectionTypeKeptString, false);
} }
@ -420,9 +437,9 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept] [Kept]
static void TestGenericTypeWithAnnotations () static void TestGenericTypeWithAnnotations ()
{ {
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericTypeWithAnnotations_OuterType`1" + const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericTypeWithAnnotations_OuterType`1["
"[[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericTypeWithAnnotations_InnerType, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]," + + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericTypeWithAnnotations_InnerType, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]"
" test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; + "], test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
Type.GetType (reflectionTypeKeptString); Type.GetType (reflectionTypeKeptString);
} }
@ -475,9 +492,75 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept] [Kept]
static void TestEscapedTypeName () static void TestEscapedTypeName ()
{ {
var typeKept = Type.GetType ("Library.Not\\+Nested, library"); var typeKept = Type.GetType ("Library.Not\\+Nested, EscapedTypeNames");
typeKept = Type.GetType ("Library.Not\\+Nested+Nes\\\\ted, library"); typeKept = Type.GetType ("Library.Not\\+Nested+Nes\\\\ted, EscapedTypeNames");
typeKept = Type.GetType ("Library.Not\\+Nested+Nes/ted, library"); typeKept = Type.GetType ("Library.Not\\+Nested+Nes/ted, EscapedTypeNames");
}
[Kept]
class AssemblyTypeResolutionBehavior
{
[Kept]
[ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestRequireTypeInSameAssemblyAsGetType () {
RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.Dependencies.TypeDefinedInSameAssemblyAsGetType");
}
[Kept]
[ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestRequireTypeInSameAssemblyAsCallToRequireType () {
RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+TypeDefinedInSameAssemblyAsCallToRequireType");
}
[Kept]
[ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestRequireTypeWithNonAssemblyQualifiedGenericArguments () {
RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1[[System.Int32]], test");
}
[Kept]
[ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestRequireTypeWithNonAssemblyQualifiedArrayType () {
RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1["
+ "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+ArrayElementGenericArgumentType]"
+ "][], test");
}
[Kept]
[ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestRequireTypeWithNonAssemblyQualifiedPointerType () {
RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1["
+ "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+PointerElementGenericArgumentType]"
+ "]*, test");
}
[Kept]
[ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
static void TestRequireTypeWithNonAssemblyQualifiedByRefType () {
RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1["
+ "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+ByRefElementGenericArgumentType]"
+ "]&, test");
}
[Kept]
public static void Test () {
TestRequireTypeInSameAssemblyAsGetType ();
TestRequireTypeInSameAssemblyAsCallToRequireType ();
TestRequireTypeWithNonAssemblyQualifiedGenericArguments ();
TestRequireTypeWithNonAssemblyQualifiedArrayType ();
TestRequireTypeWithNonAssemblyQualifiedPointerType ();
TestRequireTypeWithNonAssemblyQualifiedByRefType ();
}
class TypeDefinedInSameAssemblyAsCallToRequireType {}
class Generic<T> {}
class ArrayElementGenericArgumentType {}
class PointerElementGenericArgumentType {}
class ByRefElementGenericArgumentType {}
} }
} }
} }

View file

@ -14,6 +14,7 @@ using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Linker; using Mono.Linker;
using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers;
using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.Expectations.Metadata;
using Mono.Linker.Tests.Extensions; using Mono.Linker.Tests.Extensions;
using Mono.Linker.Tests.TestCasesRunner.ILVerification; using Mono.Linker.Tests.TestCasesRunner.ILVerification;