diff --git a/docs/error-codes.md b/docs/error-codes.md index 643422ff26c0..a70354d563c4 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -791,7 +791,7 @@ This is technically possible if a custom assembly defines `DynamicDependencyAttr } ``` -#### `IL2046` Trim analysis: Presence of 'RequiresUnreferencedCodeAttribute' on method '' doesn't match overridden method 'base method'. All overridden methods must have 'RequiresUnreferencedCodeAttribute'. +#### `IL2046` Trim analysis: Presence of 'RequiresUnreferencedCodeAttribute' on method 'method' doesn't match overridden method 'base method'. All overridden methods must have 'RequiresUnreferencedCodeAttribute'. - All overrides of a virtual method including the base method must either have or not have the `RequiresUnreferencedCodeAttribute`. @@ -828,7 +828,7 @@ This is technically possible if a custom assembly defines `DynamicDependencyAttr #### `IL2048`: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'member type' 'member' -- Internal attribute 'RemoveAttributeInstances' is a special attribute that should only be used on custom attribute types and is being used on'member type' 'member'. +- Internal attribute 'RemoveAttributeInstances' is a special attribute that should only be used on custom attribute types and is being used on 'member'. #### `IL2049`: Unrecognized internal attribute 'attribute' @@ -837,9 +837,25 @@ This is technically possible if a custom assembly defines `DynamicDependencyAttr #### `IL2050`: Correctness of COM interop cannot be guaranteed - P/invoke method 'method' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed. -- The internal attribute name 'attribute' being used in the xml is not supported by the linker, check the spelling and the supported internal attributes. -#### `IL2051` Trim analysis: Call to 'System.Reflection.MethodInfo.MakeGenericType' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. +#### `IL2051`: Property element does not contain attribute 'name' + +- An attribute element declares a property but this does not specify its name or is empty. + +#### `IL2052`: Property 'propertyName' could not be found + +- An attribute element has property 'propertyName' but this could not be found. + +#### `IL2053`: Invalid value 'propertyValue' for property 'propertyName' + +- The value 'propertyValue' used in a custom attribute annotation does not match the type of the attribute's property 'propertyName'. + +#### `IL2054`: Invalid argument value 'argumentValue' for attribute 'attribute' + +- The value 'argumentValue' used in a custom attribute annotation does not match the type of one of the attribute's constructor arguments. The arguments used for a custom attribute annotation should be declared in the same order the constructor uses. + + +#### `IL2055` Trim analysis: Call to 'System.Reflection.MethodInfo.MakeGenericType' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. - This can be either that the type on which the `MakeGenericType` is called can't be statically determined, or that the type parameters to be used for generic arguments can't be statically determined. If the open generic type has `DynamicallyAccessedMembersAttribute` on any of its generic parameters, ILLink currently can't validate that the requirements are fulfilled by the calling method. @@ -851,19 +867,19 @@ This is technically possible if a custom assembly defines `DynamicDependencyAttr void TestMethod(Type unknownType) { - // IL2051 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericType(Type[])` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. + // IL2055 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericType(Type[])` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. typeof(Lazy<>).MakeGenericType(new Type[] { typeof(TestType) }); - // IL2051 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericType(Type[])` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. + // IL2055 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericType(Type[])` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. unknownType.MakeGenericType(new Type[] { typeof(TestType) }); } ``` -#### `IL2052` Trim analysis: Trying to propagate 'DynamicallyAccessedMemberAttribute' from property 'property' to its backing field 'field', but it already has such attribute. +#### `IL2056` Trim analysis: Trying to propagate 'DynamicallyAccessedMemberAttribute' from property 'property' to its backing field 'field', but it already has such attribute. - Propagating `DynamicallyAccessedMembersAttribute` from property 'property' to its backing field 'field' found that the field already has such an attribute. The existing attribute will be used. -#### `IL2053` Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(Type typeName)'. It's not possible to guarantee the availability of the target type. +#### `IL2057` Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(Type typeName)'. It's not possible to guarantee the availability of the target type. - If the type name passed to the `System.Type.GetType` is statically known ILLink can make sure it's preserved and the application code will work after trimming. But if the type name is unknown, it could point to a type which ILLink will not see being used anywhere else and would remove it from the application, potentially breaking the application. @@ -872,74 +888,74 @@ This is technically possible if a custom assembly defines `DynamicDependencyAttr { string typeName = ReadName(); - // IL2053 Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(Type typeName)' + // IL2057 Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(Type typeName)' Type.GetType(typeName); } ``` -#### `IL2054` Trim analysis: Parameters passed to method 'Assembly.CreateInstance' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. +#### `IL2058` Trim analysis: Parameters passed to method 'Assembly.CreateInstance' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. -- ILLink currently doesn't analyze assembly instances and thus it doesn't know on which assembly the `Assembly.CreateInstance` was called. ILLink has support for `Type.GetType` instead, for cases where the parameter is a string literal. The result of which can be passed to `Activator.CreateInstance` to create an instance of the type. +- ILLink currently doesn't analyze assembly instances and thus it doesn't know on which assembly the `Assembly.CreateInstance` was called. ILLink has support for `Type.GetType` instead, for cases where the parameter is a string literal. The result of which can be passed to `Activator.CreateInstance` to create an instance of the type. ``` C# void TestMethod() { - // IL2054 Trim analysis: Parameters passed to method 'Assembly.CreateInstance(string)' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. + // IL2058 Trim analysis: Parameters passed to method 'Assembly.CreateInstance(string)' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. AssemblyLoadContext.Default.Assemblies.First(a => a.Name == "MyAssembly").CreateInstance("MyType"); // This can be replaced by Activator.CreateInstance(Type.GetType("MyType, MyAssembly")); } ``` - -#### `IL2055` Trim analysis: Unrecognized value passed to the parameter 'type' of method 'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor'. It's not possible to guarantee the availability of the target static constructor. + +#### `IL2059` Trim analysis: Unrecognized value passed to the parameter 'type' of method 'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor'. It's not possible to guarantee the availability of the target static constructor. - If the type passed to the `RunClassConstructor` is not statically known, ILLink can't make sure that its static constructor is available. ``` C# void TestMethod(Type type) { - // IL2055 Trim analysis: Unrecognized value passed to the parameter 'type' of method 'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(RuntimeTypeHandle type)'. + // IL2059 Trim analysis: Unrecognized value passed to the parameter 'type' of method 'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(RuntimeTypeHandle type)'. // It's not possible to guarantee the availability of the target static constructor. RuntimeHelpers.RunClassConstructor(type.TypeHandle); } ``` -#### `IL2056` Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericMethod` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. +#### `IL2060` Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericMethod` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. - ILLink currently doesn't analyze `MethodInfo` values and thus can't statically determine the generic method the `MakeGenericMethod` operates on. If the actual method has generic parameters with `DynamicallyAccessedMembersAttribute` ILLink would be required to fulfill the requirements declared by those attributes, but since the ILLink doesn't know the method, it can't determine if such requirements exist. ``` C# void TestMethod() { - // IL2056 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericMethod` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. + // IL2060 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericMethod` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. typeof(MyType).GetMethod("MyMethod").MakeGenericMethod(new Type[] { typeof(MyType) }); } ``` -#### `IL2057` Trim analysis: The assembly name 'assembly name' passed to method 'method' references assembly which is not available. +#### `IL2061` Trim analysis: The assembly name 'assembly name' passed to method 'method' references assembly which is not available. - Calling `CreateInstance` with assembly name 'assembly name' which can't be resolved. ``` C# void TestMethod() { - // IL2057 Trim analysis: The assembly name 'NonExistentAssembly' passed to method 'System.Activator.CreateInstance(string, string)' references assembly which is not available. + // IL2061 Trim analysis: The assembly name 'NonExistentAssembly' passed to method 'System.Activator.CreateInstance(string, string)' references assembly which is not available. Activator.CreateInstance("NonExistentAssembly", "MyType"); } ``` -#### `IL2058` Trim analysis: Unrecognized value passed to the parameter 'parameter' of method 'CreateInstance'. It's not possible to guarantee the availability of the target type. +#### `IL2062` Trim analysis: Unrecognized value passed to the parameter 'parameter' of method 'CreateInstance'. It's not possible to guarantee the availability of the target type. - The value passed as the assembly name or type name to the `CreateInstance` method can't be statically analyzed, ILLink can't make sure that the type is available. ``` C# void TestMethod(string assemblyName, string typeName) { - // IL2058 Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Activator.CreateInstance(string, string)'. It's not possible to guarantee the availability of the target type. + // IL2062 Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Activator.CreateInstance(string, string)'. It's not possible to guarantee the availability of the target type. Activator.CreateInstance("MyAssembly", typeName); - // IL2058 Trim analysis: Unrecognized value passed to the parameter 'assemblyName' of method 'System.Activator.CreateInstance(string, string)'. It's not possible to guarantee the availability of the target type. + // IL2062 Trim analysis: Unrecognized value passed to the parameter 'assemblyName' of method 'System.Activator.CreateInstance(string, string)'. It's not possible to guarantee the availability of the target type. Activator.CreateInstance(assemblyName, "MyType"); } ``` diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b5dff8aeb74f..0b482e132aa1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,17 +3,17 @@ - + https://github.com/dotnet/arcade - ff5d4b6c8dbdaeacb6e6159d3f8185118dffd915 + f6192d1e284a08ac05041d05fa6e60dec74b24f5 - + https://github.com/dotnet/arcade - ff5d4b6c8dbdaeacb6e6159d3f8185118dffd915 + f6192d1e284a08ac05041d05fa6e60dec74b24f5 - + https://github.com/dotnet/runtime - d8cf13e0ba9b369a15a83472b6b97463c6d07fe2 + ca70fc9903e68d36ee16f7d10a9a491251ea8f20 diff --git a/eng/Versions.props b/eng/Versions.props index d7ce4af8f280..0c1c8da814ef 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -13,14 +13,14 @@ true - 5.0.0-rc.1.20371.13 + 5.0.0-rc.1.20402.3 $(MicrosoftNETSdkILPackageVersion) 1.5.0 15.4.8 15.4.8 - 5.0.0-beta.20364.3 + 5.0.0-beta.20374.1 0.11.2 diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index 88a758afb19c..b9fe796f0da7 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -127,29 +127,40 @@ endif() # Specify link flags +function(add_toolchain_linker_flag Flag) + set(Config "${ARGV1}") + set(CONFIG_SUFFIX "") + if (NOT Config STREQUAL "") + set(CONFIG_SUFFIX "_${Config}") + endif() + set("CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE) + set("CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE) +endfunction() + + if(TARGET_ARCH_NAME STREQUAL "armel") if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only - add_link_options("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") - add_link_options("-L${CROSS_ROOTFS}/lib") - add_link_options("-L${CROSS_ROOTFS}/usr/lib") - add_link_options("-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") + add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") endif() elseif(TARGET_ARCH_NAME STREQUAL "arm64") if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only - add_link_options("-B${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") - add_link_options("-L${CROSS_ROOTFS}/lib64") - add_link_options("-L${CROSS_ROOTFS}/usr/lib64") - add_link_options("-L${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") - - add_link_options("-Wl,--rpath-link=${CROSS_ROOTFS}/lib64") - add_link_options("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64") - add_link_options("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") + add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib64") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") + + add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/lib64") + add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64") + add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") endif() elseif(TARGET_ARCH_NAME STREQUAL "x86") - add_link_options(-m32) + add_toolchain_linker_flag(-m32) elseif(ILLUMOS) - add_link_options("-L${CROSS_ROOTFS}/lib/amd64") - add_link_options("-L${CROSS_ROOTFS}/usr/amd64/lib") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib/amd64") + add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/amd64/lib") endif() # Specify compile options diff --git a/global.json b/global.json index ad19e99f7dea..1326251f8c68 100644 --- a/global.json +++ b/global.json @@ -8,7 +8,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20364.3", - "Microsoft.NET.Sdk.IL": "5.0.0-rc.1.20371.13" + "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20374.1", + "Microsoft.NET.Sdk.IL": "5.0.0-rc.1.20402.3" } } diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index 94dc4fb8635a..f3c31714084d 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -162,14 +162,14 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } } else if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) { _context.LogWarning ( - $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.", + $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.", 2041, method, subcategory: MessageSubCategory.TrimAnalysis); } } else { offset = 0; if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) { _context.LogWarning ( - $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.", + $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.", 2041, method, subcategory: MessageSubCategory.TrimAnalysis); } } @@ -305,7 +305,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (backingField != null) { if (annotatedFields.Any (a => a.Field == backingField)) { _context.LogWarning ($"Trying to propagate 'DynamicallyAccessedMembersAttribute' from property '{property.FullName}' to its field '{backingField}', but it already has such attribute.", - 2052, backingField, subcategory: MessageSubCategory.TrimAnalysis); + 2056, backingField, subcategory: MessageSubCategory.TrimAnalysis); } else { annotatedFields.Add (new FieldAnnotation (backingField, annotation)); } diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index e40b52cbb3d3..bfbe1ed72ddf 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -562,7 +562,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // There is a generic parameter which has some requirements on the input types. // For now we don't support tracking actual array elements, so we can't validate that the requirements are fulfilled. reflectionContext.RecordUnrecognizedPattern ( - 2051, + 2055, $"Call to '{calledMethodDefinition.GetDisplayName ()}' can not be statically analyzed. " + $"It's not possible to guarantee the availability of requirements of the generic type."); } @@ -575,7 +575,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c else { // We have no way to "include more" to fix this if we don't know, so we have to warn reflectionContext.RecordUnrecognizedPattern ( - 2051, + 2055, $"Call to '{calledMethodDefinition.GetDisplayName ()}' can not be statically analyzed. " + $"It's not possible to guarantee the availability of requirements of the generic type."); } @@ -811,7 +811,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c SourceContext = calledMethodDefinition }); } else { - reflectionContext.RecordUnrecognizedPattern (2053, $"Unrecognized value passed to the parameter 'typeName' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); + reflectionContext.RecordUnrecognizedPattern (2057, $"Unrecognized value passed to the parameter 'typeName' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); } } @@ -1197,7 +1197,7 @@ methodParams[argsParam] is ArrayValue arrayValue && // TODO: This could be supported for "this" only calls // reflectionContext.AnalyzingPattern (); - reflectionContext.RecordUnrecognizedPattern (2054, $"Parameters passed to method '{calledMethodDefinition.GetDisplayName ()}' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead."); + reflectionContext.RecordUnrecognizedPattern (2058, $"Parameters passed to method '{calledMethodDefinition.GetDisplayName ()}' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead."); break; // @@ -1214,7 +1214,7 @@ methodParams[argsParam] is ArrayValue arrayValue && } else if (typeHandleValue == NullValue.Instance) reflectionContext.RecordHandledPattern (); else { - reflectionContext.RecordUnrecognizedPattern (2055, $"Unrecognized value passed to the parameter 'type' of method '{calledMethodDefinition.GetDisplayName ()}'. It's not possible to guarantee the availability of the target static constructor."); + reflectionContext.RecordUnrecognizedPattern (2059, $"Unrecognized value passed to the parameter 'type' of method '{calledMethodDefinition.GetDisplayName ()}'. It's not possible to guarantee the availability of the target static constructor."); } } } @@ -1230,7 +1230,7 @@ methodParams[argsParam] is ArrayValue arrayValue && // We don't track MethodInfo values, so we can't determine if the MakeGenericMethod is problematic or not. // Since some of the generic parameters may have annotations, all calls are potentially dangerous. - reflectionContext.RecordUnrecognizedPattern (2056, $"Call to `{calledMethod.GetDisplayName ()}` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method."); + reflectionContext.RecordUnrecognizedPattern (2060, $"Call to `{calledMethod.GetDisplayName ()}` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method."); } break; @@ -1333,7 +1333,7 @@ void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext if (typeNameValue is KnownStringValue typeNameStringValue) { var resolvedAssembly = _context.GetLoadedAssembly (assemblyNameStringValue.Contents); if (resolvedAssembly == null) { - reflectionContext.RecordUnrecognizedPattern (2057, $"The assembly name '{assemblyNameStringValue.Contents}' passed to method '{calledMethod.GetDisplayName ()}' references assembly which is not available."); + reflectionContext.RecordUnrecognizedPattern (2061, $"The assembly name '{assemblyNameStringValue.Contents}' passed to method '{calledMethod.GetDisplayName ()}' references assembly which is not available."); continue; } @@ -1349,11 +1349,11 @@ void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext MarkConstructorsOnType (ref reflectionContext, resolvedType, parameterlessConstructor ? m => m.Parameters.Count == 0 : (Func) null, bindingFlags); } else { - reflectionContext.RecordUnrecognizedPattern (2058, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[1].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); + reflectionContext.RecordUnrecognizedPattern (2062, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[1].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); } } } else { - reflectionContext.RecordUnrecognizedPattern (2058, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[0].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); + reflectionContext.RecordUnrecognizedPattern (2062, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[0].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); } } } diff --git a/src/linker/Linker.Steps/BlacklistStep.cs b/src/linker/Linker.Steps/BlacklistStep.cs index 0db345190e12..87cd8f7545c5 100644 --- a/src/linker/Linker.Steps/BlacklistStep.cs +++ b/src/linker/Linker.Steps/BlacklistStep.cs @@ -91,10 +91,10 @@ protected override void Process () .Where (res => res.Name.Equals ("ILLink.LinkAttributes.xml", StringComparison.OrdinalIgnoreCase)) .Cast ()) { try { - Context.LogMessage (MessageContainer.CreateInfoMessage ($"Processing embedded {rsc.Name} from {asm.Name}")); + Context.LogMessage ($"Processing embedded {rsc.Name} from {asm.Name}"); steps_to_add.Push (GetExternalLinkAttributesStep (rsc, asm)); } catch (XmlException ex) { - Context.LogMessage (MessageContainer.CreateErrorMessage ($"Error processing {rsc.Name} from {asm.Name}: {ex}", 1003)); + Context.LogError ($"Error processing {rsc.Name} from {asm.Name}: {ex}", 1003); } } } diff --git a/src/linker/Linker.Steps/BodySubstituterStep.cs b/src/linker/Linker.Steps/BodySubstituterStep.cs index a43a505e9890..773af56f605b 100644 --- a/src/linker/Linker.Steps/BodySubstituterStep.cs +++ b/src/linker/Linker.Steps/BodySubstituterStep.cs @@ -167,107 +167,6 @@ void ProcessResources (AssemblyDefinition assembly, XPathNodeIterator iterator) } } - static bool TryConvertValue (string value, TypeReference target, out object result) - { - switch (target.MetadataType) { - case MetadataType.Boolean: - if (bool.TryParse (value, out bool bvalue)) { - result = bvalue ? 1 : 0; - return true; - } - - goto case MetadataType.Int32; - - case MetadataType.Byte: - if (!byte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult)) - break; - - result = (int) byteresult; - return true; - - case MetadataType.SByte: - if (!sbyte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult)) - break; - - result = (int) sbyteresult; - return true; - - case MetadataType.Int16: - if (!short.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult)) - break; - - result = (int) shortresult; - return true; - - case MetadataType.UInt16: - if (!ushort.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult)) - break; - - result = (int) ushortresult; - return true; - - case MetadataType.Int32: - if (!int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult)) - break; - - result = iresult; - return true; - - case MetadataType.UInt32: - if (!uint.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult)) - break; - - result = (int) uresult; - return true; - - case MetadataType.Double: - if (!double.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult)) - break; - - result = dresult; - return true; - - case MetadataType.Single: - if (!float.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult)) - break; - - result = fresult; - return true; - - case MetadataType.Int64: - if (!long.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult)) - break; - - result = lresult; - return true; - - case MetadataType.UInt64: - if (!ulong.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult)) - break; - - result = (long) ulresult; - return true; - - case MetadataType.Char: - if (!char.TryParse (value, out char chresult)) - break; - - result = (int) chresult; - return true; - - case MetadataType.String: - if (value is string || value == null) { - result = value; - return true; - } - - break; - } - - result = null; - return false; - } - static MethodDefinition FindMethod (TypeDefinition type, string signature) { if (!type.HasMethods) diff --git a/src/linker/Linker.Steps/LinkAttributesStep.cs b/src/linker/Linker.Steps/LinkAttributesStep.cs index 5823d6b059a4..7c29ff166064 100644 --- a/src/linker/Linker.Steps/LinkAttributesStep.cs +++ b/src/linker/Linker.Steps/LinkAttributesStep.cs @@ -32,116 +32,152 @@ IEnumerable ProcessAttributes (XPathNavigator nav, ICustomAttri if (!ShouldProcessElement (iterator.Current)) continue; - AssemblyDefinition assembly; - TypeDefinition attributeType; - string internalAttribute = GetAttribute (iterator.Current, "internal"); - if (internalAttribute != String.Empty) { - if (internalAttribute == "RemoveAttributeInstances") { - if (provider.MetadataToken.TokenType == TokenType.TypeDef) { - if (!Annotations.IsMarked (provider)) { - IEnumerable removeAttributeInstance = new List { new RemoveAttributeInstancesAttribute () }; - Context.CustomAttributes.AddInternalAttributes (provider, removeAttributeInstance); - } - continue; - } else { - Context.LogWarning ($"Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on '{nav.Name}' '{provider}'", 2048, _xmlDocumentLocation); - continue; - } - } else { - Context.LogWarning ($"Unrecognized internal attribute '{internalAttribute}'", 2049, _xmlDocumentLocation); - continue; - } + if (!string.IsNullOrEmpty (internalAttribute)) { + ProcessInternalAttribute (provider, internalAttribute); + continue; } string attributeFullName = GetFullName (iterator.Current); - if (attributeFullName == String.Empty) { - Context.LogWarning ($"'attribute' element does not contain required attribute 'fullname' or it's empty", 2029, _xmlDocumentLocation); + if (attributeFullName == string.Empty) { + Context.LogWarning ($"'attribute' element does not contain attribute 'fullname' or it's empty", 2029, _xmlDocumentLocation); continue; } - string assemblyName = GetAttribute (iterator.Current, "assembly"); - if (assemblyName == String.Empty) - attributeType = Context.GetType (attributeFullName); - else { - try { - assembly = GetAssembly (Context, AssemblyNameReference.Parse (assemblyName)); - if (assembly == null) { - Context.LogWarning ($"Could not resolve assembly '{assemblyName}' for attribute '{attributeFullName}'", 2030, _xmlDocumentLocation); - continue; - } - } catch (Exception) { - Context.LogWarning ($"Could not resolve assembly '{assemblyName}' for attribute '{attributeFullName}'", 2030, _xmlDocumentLocation); - continue; - } - attributeType = assembly.FindType (attributeFullName); - } - if (attributeType == null) { - Context.LogWarning ($"Attribute type '{attributeFullName}' could not be found", 2031, _xmlDocumentLocation); + + if (!GetAttributeType (iterator, attributeFullName, out TypeDefinition attributeType)) + continue; + + CustomAttribute customAttribute = CreateCustomAttribute (iterator, attributeType); + if (customAttribute != null) + attributes.Add (customAttribute); + } + + return attributes; + } + + CustomAttribute CreateCustomAttribute (XPathNodeIterator iterator, TypeDefinition attributeType) + { + string[] attributeArguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)).ToArray (); + var attributeArgumentCount = attributeArguments == null ? 0 : attributeArguments.Length; + MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == attributeArgumentCount); + if (constructor == null) { + Context.LogWarning ( + $"Could not find a constructor for type '{attributeType}' that has '{attributeArgumentCount}' arguments", + 2022, + _xmlDocumentLocation); + return null; + } + + CustomAttribute customAttribute = new CustomAttribute (constructor); + var arguments = ProcessAttributeArguments (constructor, attributeArguments); + if (arguments != null) + foreach (var argument in arguments) + customAttribute.ConstructorArguments.Add (argument); + + var properties = ProcessAttributeProperties (iterator.Current.SelectChildren ("property", string.Empty), attributeType); + if (properties != null) + foreach (var property in properties) + customAttribute.Properties.Add (property); + + return customAttribute; + } + + List ProcessAttributeProperties (XPathNodeIterator iterator, TypeDefinition attributeType) + { + List attributeProperties = new List (); + while (iterator.MoveNext ()) { + string propertyName = GetName (iterator.Current); + if (propertyName == string.Empty) { + Context.LogWarning ($"Property element does not contain attribute 'name'", 2051, _xmlDocumentLocation); continue; } - ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)); - MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == arguments.Count); - if (constructor == null) { - Context.LogWarning ( - $"Could not find a constructor for type '{attributeType}' that has '{arguments.Count}' arguments", - 2022, _xmlDocumentLocation); + PropertyDefinition property = attributeType.Properties.Where (prop => prop.Name == propertyName).FirstOrDefault (); + if (property == null) { + Context.LogWarning ($"Property '{propertyName}' could not be found", 2052, _xmlDocumentLocation); continue; } - string[] xmlArguments = arguments.ToArray (); - bool recognizedArgument = true; - CustomAttribute attribute = new CustomAttribute (constructor); - if (xmlArguments == null) { - attributes.Add (attribute); + var propertyValue = iterator.Current.Value; + if (!TryConvertValue (propertyValue, property.PropertyType, out object value)) { + Context.LogWarning ($"Invalid value '{propertyValue}' for property '{propertyName}'", 2053, _xmlDocumentLocation); continue; } - for (int i = 0; i < xmlArguments.Length; i++) { - object argumentValue = null; - - if (constructor.Parameters[i].ParameterType.Resolve ().IsEnum) { - foreach (var field in constructor.Parameters[i].ParameterType.Resolve ().Fields) { - if (field.IsStatic && field.Name == xmlArguments[i]) { - argumentValue = Convert.ToInt32 (field.Constant); - break; - } - } - if (argumentValue == null) { - Context.LogWarning ( - $"Could not parse argument value '{xmlArguments[i]}' for attribute '{attributeType.GetDisplayName ()}' as a '{constructor.Parameters[i].ParameterType.GetDisplayName ()}'", - 2021, _xmlDocumentLocation); - recognizedArgument = false; - } - } else { - switch (constructor.Parameters[i].ParameterType.MetadataType) { - case MetadataType.String: - argumentValue = xmlArguments[i]; - break; - case MetadataType.Int32: - int result; - if (int.TryParse (xmlArguments[i], out result)) - argumentValue = result; - else { - Context.LogWarning ( - $"Could not parse argument value '{xmlArguments[i]}' for attribute '{attributeType.GetDisplayName ()}' as a '{constructor.Parameters[i].ParameterType.GetDisplayName ()}'", - 2021, _xmlDocumentLocation); - } - break; - default: - Context.LogWarning ( - $"Parameter '{constructor.Parameters[i].Name}' of attribute '{attributeType.GetDisplayName ()}' " + - $"is of unsupported type '{constructor.Parameters[i].ParameterType.GetDisplayName ()}'", - 2020, _xmlDocumentLocation); - recognizedArgument = false; - break; - } + + attributeProperties.Add (new CustomAttributeNamedArgument (property.Name, + new CustomAttributeArgument (property.PropertyType, value))); + } + + return attributeProperties; + } + + List ProcessAttributeArguments (MethodDefinition attributeConstructor, string[] arguments) + { + if (arguments == null) + return null; + + List attributeArguments = new List (); + for (int i = 0; i < arguments.Length; i++) { + object argValue; + TypeDefinition parameterType = attributeConstructor.Parameters[i].ParameterType.Resolve (); + if (!TryConvertValue (arguments[i], parameterType, out argValue)) { + Context.LogWarning ($"Invalid argument value '{arguments[i]}' for attribute '{attributeConstructor.DeclaringType.GetDisplayName ()}'", 2054, _xmlDocumentLocation); + return null; + } + + attributeArguments.Add (new CustomAttributeArgument (parameterType, argValue)); + } + + return attributeArguments; + } + + void ProcessInternalAttribute (ICustomAttributeProvider provider, string internalAttribute) + { + if (internalAttribute != "RemoveAttributeInstances") { + Context.LogWarning ($"Unrecognized internal attribute '{internalAttribute}'", 2049, _xmlDocumentLocation); + return; + } + + if (provider.MetadataToken.TokenType != TokenType.TypeDef) { + Context.LogWarning ($"Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on '{provider}'", 2048, _xmlDocumentLocation); + return; + } + + if (!Annotations.IsMarked (provider)) { + IEnumerable removeAttributeInstance = new List { new RemoveAttributeInstancesAttribute () }; + Context.CustomAttributes.AddInternalAttributes (provider, removeAttributeInstance); + } + } + + bool GetAttributeType (XPathNodeIterator iterator, string attributeFullName, out TypeDefinition attributeType) + { + string assemblyName = GetAttribute (iterator.Current, "assembly"); + if (string.IsNullOrEmpty (assemblyName)) { + attributeType = Context.GetType (attributeFullName); + } else { + AssemblyDefinition assembly; + try { + assembly = GetAssembly (Context, AssemblyNameReference.Parse (assemblyName)); + if (assembly == null) { + Context.LogWarning ($"Could not resolve assembly '{assemblyName}' for attribute '{attributeFullName}'", 2030, _xmlDocumentLocation); + attributeType = default; + return false; } - attribute.ConstructorArguments.Add (new CustomAttributeArgument (constructor.Parameters[i].ParameterType, argumentValue)); + } catch (Exception) { + Context.LogWarning ($"Could not resolve assembly '{assemblyName}' for attribute '{attributeFullName}'", 2030, _xmlDocumentLocation); + attributeType = default; + return false; } - if (recognizedArgument) - attributes.Add (attribute); + + attributeType = assembly.FindType (attributeFullName); } - return attributes; + + if (attributeType == null) { + Context.LogWarning ($"Attribute type '{attributeFullName}' could not be found", 2031, _xmlDocumentLocation); + return false; + } + + return true; } ArrayBuilder GetAttributeChildren (XPathNodeIterator iterator) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index fa97f19dc3fe..8468e2e97617 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -558,6 +558,9 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo continue; } + if (UnconditionalSuppressMessageAttributeState.TypeRefHasUnconditionalSuppressions (ca.Constructor.DeclaringType)) + _context.Suppressions.AddSuppression (ca, provider); + if (_context.Annotations.HasLinkerAttribute (ca.AttributeType.Resolve ()) && providerInLinkedAssembly) continue; @@ -1593,8 +1596,6 @@ bool MarkSpecialCustomAttributeDependencies (CustomAttribute ca, ICustomAttribut provider, sourceLocationMember); return true; - } else if (UnconditionalSuppressMessageAttributeState.TypeRefHasUnconditionalSuppressions (dt)) { - _context.Suppressions.AddSuppression (ca, provider); } return false; @@ -2900,6 +2901,9 @@ protected virtual bool ShouldMarkInterfaceImplementation (TypeDefinition type, I protected virtual void MarkInterfaceImplementation (InterfaceImplementation iface, TypeDefinition type) { + if (Annotations.IsMarked (iface)) + return; + // Blame the type that has the interfaceimpl, expecting the type itself to get marked for other reasons. MarkCustomAttributes (iface, new DependencyInfo (DependencyKind.CustomAttribute, iface), type); // Blame the interface type on the interfaceimpl itself. diff --git a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs index f41d596d6c6a..264bd821b2f7 100644 --- a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs +++ b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.Linq; using System.Text.RegularExpressions; using System.Xml.XPath; using Mono.Cecil; @@ -416,6 +418,11 @@ protected static string GetFullName (XPathNavigator nav) return GetAttribute (nav, FullNameAttributeName); } + protected static string GetName (XPathNavigator nav) + { + return GetAttribute (nav, NameAttributeName); + } + protected static string GetSignature (XPathNavigator nav) { return GetAttribute (nav, SignatureAttributeName); @@ -427,5 +434,119 @@ protected static string GetAttribute (XPathNavigator nav, string attribute) } public override string ToString () => GetType ().Name + ": " + _xmlDocumentLocation; + + public static bool TryConvertValue (string value, TypeReference target, out object result) + { + switch (target.MetadataType) { + case MetadataType.Boolean: + if (bool.TryParse (value, out bool bvalue)) { + result = bvalue ? 1 : 0; + return true; + } + + goto case MetadataType.Int32; + + case MetadataType.Byte: + if (!byte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult)) + break; + + result = (int) byteresult; + return true; + + case MetadataType.SByte: + if (!sbyte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult)) + break; + + result = (int) sbyteresult; + return true; + + case MetadataType.Int16: + if (!short.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult)) + break; + + result = (int) shortresult; + return true; + + case MetadataType.UInt16: + if (!ushort.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult)) + break; + + result = (int) ushortresult; + return true; + + case MetadataType.Int32: + if (!int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult)) + break; + + result = iresult; + return true; + + case MetadataType.UInt32: + if (!uint.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult)) + break; + + result = (int) uresult; + return true; + + case MetadataType.Double: + if (!double.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult)) + break; + + result = dresult; + return true; + + case MetadataType.Single: + if (!float.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult)) + break; + + result = fresult; + return true; + + case MetadataType.Int64: + if (!long.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult)) + break; + + result = lresult; + return true; + + case MetadataType.UInt64: + if (!ulong.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult)) + break; + + result = (long) ulresult; + return true; + + case MetadataType.Char: + if (!char.TryParse (value, out char chresult)) + break; + + result = (int) chresult; + return true; + + case MetadataType.String: + if (value is string || value == null) { + result = value; + return true; + } + + break; + + case MetadataType.ValueType: + if (value is string && + target.Resolve () is var typeDefinition && + typeDefinition.IsEnum) { + var enumField = typeDefinition.Fields.Where (f => f.IsStatic && f.Name == value).FirstOrDefault (); + if (enumField != null) { + result = Convert.ToInt32 (enumField.Constant); + return true; + } + } + + break; + } + + result = null; + return false; + } } } diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs index a0514d87e4f6..60629e53b5b1 100644 --- a/src/linker/Linker/LinkContext.cs +++ b/src/linker/Linker/LinkContext.cs @@ -496,7 +496,11 @@ public bool IsOptimizationEnabled (CodeOptimizations optimization, AssemblyDefin public void LogMessage (MessageContainer message) { - if (!LogMessages || message == MessageContainer.Empty) + if (message == MessageContainer.Empty) + return; + + if ((message.Category == MessageCategory.Diagnostic || + message.Category == MessageCategory.Info) && !LogMessages) return; if (message.Category == MessageCategory.Warning && @@ -549,9 +553,6 @@ public void LogDiagnostic (string message) /// New MessageContainer of 'Warning' category public void LogWarning (string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None) { - if (!LogMessages) - return; - var version = GetWarningVersion (code); if ((GeneralWarnAsError && (!WarnAsError.TryGetValue ((uint) code, out var warnAsError) || warnAsError)) || @@ -606,9 +607,6 @@ public void LogWarning (string text, int code, string origin, string subcategory /// New MessageContainer of 'Error' category public void LogError (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null, bool isWarnAsError = false, WarnVersion? version = null) { - if (!LogMessages) - return; - var error = MessageContainer.CreateErrorMessage (text, code, subcategory, origin, isWarnAsError, version); LogMessage (error); } diff --git a/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs b/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs index 9dde4df354dc..b31040d8029d 100644 --- a/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs +++ b/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs @@ -7,11 +7,12 @@ namespace Mono.Linker.Tests.Cases.CommandLine #if !NETCOREAPP [IgnoreTestCase ("Can be enabled once MonoBuild produces a dll from which we can grab the types in the Mono.Linker namespace.")] #else - [SetupCompileBefore ("CustomStep.dll", new [] { "Dependencies/CustomStepDummy.cs" }, new [] { "illink.dll" })] + [SetupCompileBefore ("CustomStep.dll", new[] { "Dependencies/CustomStepDummy.cs" }, new[] { "illink.dll" })] #endif [SetupLinkerArgument ("--custom-step", "CustomStep.CustomStepDummy,CustomStep.dll")] [SetupLinkerArgument ("--custom-step", "-CleanStep:CustomStep.CustomStepDummy,CustomStep.dll")] [SetupLinkerArgument ("--custom-step", "+CleanStep:CustomStep.CustomStepDummy,CustomStep.dll")] + [SetupLinkerArgument ("--verbose")] [LogContains ("Custom step added")] public class AddCustomStep { diff --git a/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs b/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs index 383127a493aa..c6ef3633af99 100644 --- a/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs +++ b/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs @@ -7,11 +7,11 @@ namespace Mono.Linker.Tests.Cases.CommandLine #if !NETCOREAPP [IgnoreTestCase ("Can be enabled once MonoBuild produces a dll from which we can grab the types in the Mono.Linker namespace.")] #else - [SetupCompileBefore ("CustomStep.dll", new [] { "Dependencies/CustomStepUser.cs" }, new [] { "illink.dll" })] + [SetupCompileBefore ("CustomStep.dll", new[] { "Dependencies/CustomStepUser.cs" }, new[] { "illink.dll" })] #endif [SetupLinkerArgument ("--custom-step", "CustomStep.CustomStepUser,CustomStep.dll")] [SetupLinkerArgument ("--custom-data", "NewKey=UserValue")] - + [SetupLinkerArgument ("--verbose")] [LogContains ("Custom step added with custom data of UserValue")] public class CustomStepData { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs index ed6e8031de16..af853430f2bd 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs @@ -678,7 +678,7 @@ static void TestMakeGenericTypeNullType () nullType.MakeGenericType (typeof (TestType)); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2051")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericTypeUnknownInput (Type inputType) { inputType.MakeGenericType (typeof (TestType)); @@ -694,7 +694,7 @@ class TypeMakeGenericNoArguments { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2051")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithRequirements () { // Currently this is not analyzable since we don't track array elements. @@ -702,14 +702,14 @@ static void TestMakeGenericWithRequirements () typeof (TypeMakeGenericWithPublicFieldsArgument<>).MakeGenericType (typeof (TestType)); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2051")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithRequirementsFromParam ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) { typeof (TypeMakeGenericWithPublicFieldsArgument<>).MakeGenericType (type); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2051")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithRequirementsFromGenericParam< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { @@ -736,7 +736,7 @@ class TypeMakeGenericWithNoRequirements { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2051")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithMultipleArgumentsWithRequirements () { typeof (TypeMakeGenericWithMultipleArgumentsWithRequirements<,>).MakeGenericType (typeof (TestType), typeof (TestType)); @@ -754,7 +754,7 @@ static void TestMakeGenericMethod () TestMakeGenericMethodWithNoRequirements (); } - [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2056")] + [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2060")] static void TestMakeGenericMethodWithRequirements () { typeof (GenericParameterDataFlow).GetMethod (nameof (MethodMakeGenericWithRequirements), BindingFlags.Static | BindingFlags.NonPublic) @@ -765,7 +765,7 @@ static void TestMakeGenericMethodWithRequirements () { } - [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2056")] + [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2060")] static void TestMakeGenericMethodWithNoRequirements () { typeof (GenericParameterDataFlow).GetMethod (nameof (MethodMakeGenericWithNoRequirements), BindingFlags.Static | BindingFlags.NonPublic) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs index 5db5478d6e10..84c2e4259488 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -115,7 +115,7 @@ static void TestMultipleConstantValues () [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2006", message: "GetType")] [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetType), new Type[] { typeof (string) }, - messageCode: "IL2053", message: "System.Type.GetType(String)")] + messageCode: "IL2057", message: "System.Type.GetType(String)")] static void TestMultipleMixedValues () { string typeName = null; diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index c59c96e12542..9dd2df28ff72 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -245,7 +245,7 @@ public void TestPropertyWithExistingAttributes () PropertyWithExistingAttributes = null; } - [ExpectedWarning ("IL2052", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field")] + [ExpectedWarning ("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] Type PropertyWithExistingAttributes_Field; diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs index fc74c45a2de6..1643a30b501e 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs @@ -13,8 +13,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [SetupLinkAttributesFile ("XmlAnnotations.xml")] - [ExpectedWarning ("IL2031", "System.DoesNotExistattribute", FileName = "XmlAnnotations.xml")] - [ExpectedWarning ("IL2021", "NonValidArgument", "DynamicallyAccessedMembersAttribute", "DynamicallyAccessedMemberType", FileName = "XmlAnnotations.xml")] + [ExpectedWarning ("IL2031", "System.DoesNotExistAttribute", FileName = "XmlAnnotations.xml")] + [LogDoesNotContain ("IL2006: Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField():*", true)] class XmlAnnotations { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml index 38810e96e43f..2747c62634e8 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml @@ -1,9 +1,15 @@  - + + ILLink + IL2006 + member + M:Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField + + - + 0 diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il new file mode 100644 index 000000000000..6615e890fd8a --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly 'library' { } + +.class interface public auto ansi abstract IMyInterface +{ + .method public hidebysig newslot virtual + instance void Frob () cil managed + { + ret + } +} + +.class public auto ansi MyClass + extends [mscorlib]System.Object + implements IMyInterface +{ + .interfaceimpl type IMyInterface + .custom instance void MyAttribute::.ctor() = ( 01 00 00 00 ) + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ret + } +} + +.class private auto ansi sealed beforefieldinit MyAttribute + extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ret + } +} diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs new file mode 100644 index 000000000000..9be72541cb88 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods +{ +#if NETCOREAPP + [Define ("IL_ASSEMBLY_AVAILABLE")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/InterfaceWithAttributeOnImpl.il" })] + class InterfaceWithAttributeOnImplementation + { + static void Main () + { +#if IL_ASSEMBLY_AVAILABLE + ((IMyInterface)new MyClass ()).Frob (); +#endif + } + } +#endif +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs index b92d528e7759..296515e970d0 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using Mono.Linker.Tests.Cases.Expectations.Assertions; @@ -14,9 +14,8 @@ namespace Mono.Linker.Tests.Cases.LinkAttributes [ExpectedWarning ("IL2030", "NonExistentAssembly1", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2030", "MalformedAssemblyName, thisiswrong", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2031", "NonExistentAttribute", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2020", "doubleParameter", "AttributeWithDoubleNumberParameterAttribute", "System.Double", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2021", "NonExistentEnumValue", "AttributeWithEnumParameterAttribute", "AttributeEnum", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2021", "NotANumber", "AttributeWithIntParameterAttribute", "System.Int32", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2054", "NonExistentEnumValue", "AttributeWithEnumParameterAttribute", "AttributeEnum", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2054", "NotANumber", "AttributeWithIntParameterAttribute", "System.Int32", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2022", "AttributeWithNoParametersAttribute", "1", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2023", "GetTypeMethod", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2024", "methodParameter", "MethodWithParameter", FileName = "LinkAttributeErrorCases.xml")] diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs index 77af491bbf48..201f2936864c 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs @@ -44,7 +44,7 @@ namespace Mono.Linker.Tests.Cases.LinkAttributes [LogDoesNotContain ("IL2045")] // No other 2045 messages should be logged - [LogContains ("IL2048: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'method' 'System.String Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval::methodWithCustomAttribute(System.String)'")] + [LogContains ("IL2048: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'System.String Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval::methodWithCustomAttribute(System.String)'")] [LogContains ("IL2049: Unrecognized internal attribute 'InvalidInternal'")] [KeptMember (".ctor()")] diff --git a/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs b/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs index 87082fbd1978..9d863952cf68 100644 --- a/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs +++ b/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Logging [SetupCompileBefore ("LogStep.dll", new[] { "Dependencies/LogStep.cs" }, new[] { "illink.dll" })] #endif [SetupLinkerArgument ("--custom-step", "Log.LogStep,LogStep.dll")] - + [SetupLinkerArgument ("--verbose")] [LogContains ("ILLink: error IL1004: Error")] [LogContains ("logtest(1,1): warning IL2001: Warning")] [LogContains ("ILLink: Info")] diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs index ed5de8057731..dd472fe85c02 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs @@ -276,7 +276,7 @@ private static void WithAssemblyName () [Kept] [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string) }, - messageCode: "IL2058", message: "assemblyName")] + messageCode: "IL2062", message: "assemblyName")] private static void WithNullAssemblyName () { Activator.CreateInstance (null, "Mono.Linker.Tests.Cases.Reflection.ActivatorCreateInstance+WithAssemblyNameParameterless1"); @@ -284,7 +284,7 @@ private static void WithNullAssemblyName () [Kept] [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string) }, - messageCode: "IL2057", message: "NonExistingAssembly")] + messageCode: "IL2061", message: "NonExistingAssembly")] private static void WithNonExistingAssemblyName () { Activator.CreateInstance ("NonExistingAssembly", "Mono.Linker.Tests.Cases.Reflection.ActivatorCreateInstance+WithAssemblyNameParameterless1"); @@ -295,7 +295,7 @@ private static void WithNonExistingAssemblyName () [Kept] [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string), typeof (object[]) }, - messageCode: "IL2058", message: "typeName")] + messageCode: "IL2062", message: "typeName")] private static void WithAssemblyAndUnknownTypeName () { Activator.CreateInstance ("test", _typeNameField, new object[] { }); @@ -360,9 +360,9 @@ private static void AppDomainCreateInstance () } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string) }, messageCode: "IL2054")] - [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool) }, messageCode: "IL2054")] - [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo), typeof (object[]) }, messageCode: "IL2054")] + [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string) }, messageCode: "IL2058")] + [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool) }, messageCode: "IL2058")] + [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo), typeof (object[]) }, messageCode: "IL2058")] private static void UnsupportedCreateInstance () { typeof (ActivatorCreateInstance).Assembly.CreateInstance ("NonExistent"); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs index 805f20a90c56..18df634f51d9 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs @@ -48,7 +48,7 @@ static Type FindType () [Kept] [UnrecognizedReflectionAccessPattern (typeof (RuntimeHelpers), nameof (RuntimeHelpers.RunClassConstructor), new Type[] { typeof (RuntimeTypeHandle) }, - messageCode: "IL2055", message: "RunClassConstructor")] + messageCode: "IL2059", message: "RunClassConstructor")] static void TestDataFlowType () { @@ -59,7 +59,7 @@ static void TestDataFlowType () [Kept] [RecognizedReflectionAccessPattern] [UnrecognizedReflectionAccessPattern (typeof (RuntimeHelpers), nameof (RuntimeHelpers.RunClassConstructor), new Type[] { typeof (RuntimeTypeHandle) }, - messageCode: "IL2055")] + messageCode: "IL2059")] static void TestIfElseUsingRuntimeTypeHandle (int i) { diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs new file mode 100644 index 000000000000..681a36075b13 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs @@ -0,0 +1,27 @@ +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using System.Text; + +namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression +{ + [SkipKeptItemsValidation] + [SetupLinkAttributesFile ("AddSuppressionsBeforeAttributeRemoval.xml")] + [LogDoesNotContain ("IL2006: Mono.Linker.Tests.Cases.Warnings.WarningSuppression.AddSuppressionsBeforeAttributeRemoval.Main()")] + public class AddSuppressionsBeforeAttributeRemoval + { + public static Type TriggerUnrecognizedPattern () + { + return typeof (AddedPseudoAttributeAttribute); + } + + [UnconditionalSuppressMessage ("ILLinker", "IL2006")] + public static void Main () + { + Expression.Call (TriggerUnrecognizedPattern (), "", Type.EmptyTypes); + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml new file mode 100644 index 000000000000..bd79f27926cf --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs index 7bf5889d60d6..bfc113392abb 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs @@ -84,14 +84,6 @@ public virtual TestCaseLinkerOptions GetLinkerOptions (NPath inputPath) tclo.AdditionalArguments.Add (new KeyValuePair ((string) ca[0].Value, values)); } - foreach (var testType in _fullTestCaseAssemblyDefinition.AllDefinedTypes ()) { - if (testType.CustomAttributes.Concat (testType.AllMembers ().SelectMany (m => m.CustomAttributes)).Any (attr => - attr.AttributeType.Name == nameof (LogContainsAttribute) || attr.AttributeType.Name == nameof (LogDoesNotContainAttribute) || attr.AttributeType.Name == nameof (ExpectedWarningAttribute))) { - tclo.AdditionalArguments.Add (new KeyValuePair ("--verbose", new string[] { })); - break; - } - } - return tclo; }