diff options
author | Vitek Karas <10670590+vitek-karas@users.noreply.github.com> | 2022-05-02 22:15:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-02 22:15:42 +0300 |
commit | 05a3b652d525acaac1307221b62db979d0108692 (patch) | |
tree | a022115eb1dfde9ec5ba2b1dc3e6acf4aa6b73c9 | |
parent | 2375cba1a60713f83da1ba09c44faa17e9ad432c (diff) |
Add ability for the analyzer to recognize const fields (#2774)
This means the value of the fields is tracked as a const value instead of a field reference.
This is to support some additional code patterns as well as align the behavior with the linker. Compiler will inline the const fields into the IL effectively removing the field refernce in these cases and linker only sees the constant. So ideally the analyzer should have a similar behavior.
-rw-r--r-- | src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs | 44 | ||||
-rw-r--r-- | test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs | 17 |
2 files changed, 47 insertions, 14 deletions
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index 0225087e8..24b81e832 100644 --- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -55,19 +55,8 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis // If the return value is empty (TopValue basically) and the Operation tree // reports it as having a constant value, use that as it will automatically cover // cases we don't need/want to handle. - if (operation != null && returnValue.IsEmpty () && operation.ConstantValue.HasValue) { - object? constantValue = operation.ConstantValue.Value; - if (constantValue == null) - return NullValue.Instance; - else if (operation.Type?.SpecialType == SpecialType.System_String && constantValue is string stringConstantValue) - return new KnownStringValue (stringConstantValue); - else if (operation.Type?.TypeKind == TypeKind.Enum && constantValue is int enumConstantValue) - return new ConstIntValue (enumConstantValue); - else if (operation.Type?.SpecialType == SpecialType.System_Int32 && constantValue is int intConstantValue) - return new ConstIntValue (intConstantValue); - else if (operation.Type?.SpecialType == SpecialType.System_Boolean && constantValue is bool boolConstantValue) - return new ConstIntValue (boolConstantValue ? 1 : 0); - } + if (operation != null && returnValue.IsEmpty () && TryGetConstantValue (operation, out var constValue)) + return constValue; return returnValue; } @@ -139,6 +128,9 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis } } + if (TryGetConstantValue (fieldRef, out var constValue)) + return constValue; + if (fieldRef.Field.Type.IsTypeInterestingForDataflow ()) return new FieldValue (fieldRef.Field); @@ -297,5 +289,31 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis ); } } + + static bool TryGetConstantValue (IOperation operation, out MultiValue constValue) + { + if (operation.ConstantValue.HasValue) { + object? constantValue = operation.ConstantValue.Value; + if (constantValue == null) { + constValue = NullValue.Instance; + return true; + } else if (operation.Type?.SpecialType == SpecialType.System_String && constantValue is string stringConstantValue) { + constValue = new KnownStringValue (stringConstantValue); + return true; + } else if (operation.Type?.TypeKind == TypeKind.Enum && constantValue is int enumConstantValue) { + constValue = new ConstIntValue (enumConstantValue); + return true; + } else if (operation.Type?.SpecialType == SpecialType.System_Int32 && constantValue is int intConstantValue) { + constValue = new ConstIntValue (intConstantValue); + return true; + } else if (operation.Type?.SpecialType == SpecialType.System_Boolean && constantValue is bool boolConstantValue) { + constValue = new ConstIntValue (boolConstantValue ? 1 : 0); + return true; + } + } + + constValue = default; + return false; + } } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs index dff625716..ef58eac31 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -34,6 +34,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow TestStringEmpty (); TypeWithWarnings.Test (); + OverConstTypeName.Test (); // TODO: // Test multi-value returns @@ -163,7 +164,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow class TypeWithWarnings { - [RequiresUnreferencedCode ("--Method1--")] public void Method1 () { } @@ -179,6 +179,21 @@ namespace Mono.Linker.Tests.Cases.DataFlow } } + class OverConstTypeName + { + private const string s_ConstTypeName = "Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (OverConstTypeName); + + [RequiresUnreferencedCode ("--Method1--")] + public void Method1 () { } + + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)] + public static void Test () + { + Type.GetType (s_ConstTypeName).RequiresPublicMethods (); + } + } + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] private static string GetStringTypeWithPublicParameterlessConstructor () { |