diff options
author | Mateo Torres-Ruiz <mateoatr@users.noreply.github.com> | 2020-12-09 05:23:56 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-09 05:23:56 +0300 |
commit | a86658f4602e616d71e5d6db23a30940534132e2 (patch) | |
tree | a6f958d0ffeac9bae729e3845ca18375a78d021f /test | |
parent | d0602c4767acf5dcd46700381ce39bd2775de6d7 (diff) |
Port single-file analyzer (#1665)
* Add single-file analyzer
* Add tests
* Use str constant
* Update Resources
* Update tests
* PR feedback
* Remove mysterious filename from comments
* Add helper method for single-file diagnostic verification
* Refactor MSBuild properties
* Add test with PublishSingleFile not set
Diffstat (limited to 'test')
-rw-r--r-- | test/ILLink.RoslynAnalyzer.Tests/AvoidAssemblyLocationInSingleFileTests.cs | 144 | ||||
-rw-r--r-- | test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs | 4 | ||||
-rw-r--r-- | test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs (renamed from test/ILLink.RoslynAnalyzer.Tests/AnalyzerTests.cs) | 21 | ||||
-rw-r--r-- | test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs | 9 | ||||
-rw-r--r-- | test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs | 4 |
5 files changed, 168 insertions, 14 deletions
diff --git a/test/ILLink.RoslynAnalyzer.Tests/AvoidAssemblyLocationInSingleFileTests.cs b/test/ILLink.RoslynAnalyzer.Tests/AvoidAssemblyLocationInSingleFileTests.cs new file mode 100644 index 000000000..0ea712f97 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/AvoidAssemblyLocationInSingleFileTests.cs @@ -0,0 +1,144 @@ +// 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. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Xunit; +using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier< + ILLink.RoslynAnalyzer.AvoidAssemblyLocationInSingleFile>; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public class AvoidAssemblyLocationInSingleFileTests + { + static Task VerifySingleFileAnalyzer (string source, params DiagnosticResult[] expected) + { + return VerifyCS.VerifyAnalyzerAsync (source, + TestCaseUtils.UseMSBuildProperties (MSBuildPropertyOptionNames.PublishSingleFile), + expected); + } + + [Fact] + public Task GetExecutingAssemblyLocation () + { + const string src = @" +using System.Reflection; +class C +{ + public string M() => Assembly.GetExecutingAssembly().Location; +}"; + + return VerifySingleFileAnalyzer (src, + // (5,26): warning IL3000: 'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3000).WithSpan (5, 26, 5, 66).WithArguments ("System.Reflection.Assembly.Location")); + } + + [Fact] + public Task AssemblyProperties () + { + var src = @" +using System.Reflection; +class C +{ + public void M() + { + var a = Assembly.GetExecutingAssembly(); + _ = a.Location; + // below methods are marked as obsolete in 5.0 + // _ = a.CodeBase; + // _ = a.EscapedCodeBase; + } +}"; + return VerifySingleFileAnalyzer (src, + // (8,13): warning IL3000: 'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3000).WithSpan (8, 13, 8, 23).WithArguments ("System.Reflection.Assembly.Location") + ); + } + + [Fact] + public Task AssemblyMethods () + { + var src = @" +using System.Reflection; +class C +{ + public void M() + { + var a = Assembly.GetExecutingAssembly(); + _ = a.GetFile(""/some/file/path""); + _ = a.GetFiles(); + } +}"; + return VerifySingleFileAnalyzer (src, + // (8,13): warning IL3001: Assemblies embedded in a single-file app cannot have additional files in the manifest. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3001).WithSpan (8, 13, 8, 41).WithArguments ("System.Reflection.Assembly.GetFile(string)"), + // (9,13): warning IL3001: Assemblies embedded in a single-file app cannot have additional files in the manifest. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3001).WithSpan (9, 13, 9, 25).WithArguments ("System.Reflection.Assembly.GetFiles()") + ); + } + + [Fact] + public Task AssemblyNameAttributes () + { + var src = @" +using System.Reflection; +class C +{ + public void M() + { + var a = Assembly.GetExecutingAssembly().GetName(); + _ = a.CodeBase; + _ = a.EscapedCodeBase; + } +}"; + return VerifySingleFileAnalyzer (src, + // (8,13): warning IL3000: 'System.Reflection.AssemblyName.CodeBase' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3000).WithSpan (8, 13, 8, 23).WithArguments ("System.Reflection.AssemblyName.CodeBase"), + // (9,13): warning IL3000: 'System.Reflection.AssemblyName.EscapedCodeBase' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3000).WithSpan (9, 13, 9, 30).WithArguments ("System.Reflection.AssemblyName.EscapedCodeBase") + ); + } + + [Fact] + public Task FalsePositive () + { + // This is an OK use of Location and GetFile since these assemblies were loaded from + // a file, but the analyzer is conservative + var src = @" +using System.Reflection; +class C +{ + public void M() + { + var a = Assembly.LoadFrom(""/some/path/not/in/bundle""); + _ = a.Location; + _ = a.GetFiles(); + } +}"; + return VerifySingleFileAnalyzer (src, + // (8,13): warning IL3000: 'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3000).WithSpan (8, 13, 8, 23).WithArguments ("System.Reflection.Assembly.Location"), + // (9,13): warning IL3001: Assemblies embedded in a single-file app cannot have additional files in the manifest. + VerifyCS.Diagnostic (AvoidAssemblyLocationInSingleFile.IL3001).WithSpan (9, 13, 9, 25).WithArguments ("System.Reflection.Assembly.GetFiles()") + ); + } + + [Fact] + public Task PublishSingleFileIsNotSet () + { + var src = @" +using System.Reflection; +class C +{ + public void M() + { + var a = Assembly.GetExecutingAssembly().Location; + } +}"; + // If 'PublishSingleFile' is not set to true, no diagnostics should be produced by the analyzer. This will + // effectively verify that the number of produced diagnostics matches the number of expected ones (zero). + return VerifyCS.VerifyAnalyzerAsync (src); + } + } +} diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs index e63d2c02f..f205fb25e 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Xunit; @@ -24,7 +22,7 @@ namespace ILLink.RoslynAnalyzer.Tests case "MethodWithDuplicateRequiresAttribute": return; } - RunTest (m, attrs); + RunTest (m, attrs, UseMSBuildProperties (MSBuildPropertyOptionNames.PublishTrimmed)); } } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/AnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs index fc1ee182d..81899e890 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/AnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs @@ -3,14 +3,22 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; using Xunit; using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier< ILLink.RoslynAnalyzer.RequiresUnreferencedCodeAnalyzer>; namespace ILLink.RoslynAnalyzer.Tests { - public class AnalyzerTests + public class RequiresUnreferencedCodeAnalyzerTests { + static Task VerifyRequiresUnreferencedCodeAnalyzer (string source, params DiagnosticResult[] expected) + { + return VerifyCS.VerifyAnalyzerAsync (source, + TestCaseUtils.UseMSBuildProperties (MSBuildPropertyOptionNames.PublishTrimmed), + expected); + } + [Fact] public Task SimpleDiagnostic () { @@ -23,10 +31,9 @@ class C int M1() => 0; int M2() => M1(); }"; - return VerifyCS.VerifyAnalyzerAsync (TestRequiresWithMessageOnlyOnMethod, + return VerifyRequiresUnreferencedCodeAnalyzer (TestRequiresWithMessageOnlyOnMethod, // (8,17): warning IL2026: Calling 'System.Int32 C::M1()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. message. - VerifyCS.Diagnostic ().WithSpan (8, 17, 8, 21).WithArguments ("C.M1()", "message", "") - ); + VerifyCS.Diagnostic ().WithSpan (8, 17, 8, 21).WithArguments ("C.M1()", "message", "")); } [Fact] @@ -46,7 +53,7 @@ class C { } }"; - return VerifyCS.VerifyAnalyzerAsync (MessageAndUrlOnMethod, + return VerifyRequiresUnreferencedCodeAnalyzer (MessageAndUrlOnMethod, // (8,3): warning IL2026: Calling 'C.RequiresWithMessageAndUrl()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --RequiresWithMessageAndUrl--. VerifyCS.Diagnostic ().WithSpan (8, 3, 8, 31).WithArguments ("C.RequiresWithMessageAndUrl()", "Message for --RequiresWithMessageAndUrl--", "https://helpurl") ); @@ -70,7 +77,7 @@ class C get { return 42; } } }"; - return VerifyCS.VerifyAnalyzerAsync (PropertyRequires, + return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, // (8,7): warning IL2026: Calling 'C.PropertyRequires.get' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --getter PropertyRequires--. VerifyCS.Diagnostic ().WithSpan (8, 7, 8, 23).WithArguments ("C.PropertyRequires.get", "Message for --getter PropertyRequires--", "") ); @@ -94,7 +101,7 @@ class C set { } } }"; - return VerifyCS.VerifyAnalyzerAsync (PropertyRequires, + return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, // (8,3): warning IL2026: Calling 'C.PropertyRequires.set' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --setter PropertyRequires--. VerifyCS.Diagnostic ().WithSpan (8, 3, 8, 19).WithArguments ("C.PropertyRequires.set", "Message for --setter PropertyRequires--", "") ); diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index 003823c02..c62c2d762 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -53,9 +53,9 @@ namespace ILLink.RoslynAnalyzer.Tests } } - internal static void RunTest (MethodDeclarationSyntax m, List<AttributeSyntax> attrs) + internal static void RunTest (MethodDeclarationSyntax m, List<AttributeSyntax> attrs, params (string, string)[] MSBuildProperties) { - var comp = CSharpAnalyzerVerifier<RequiresUnreferencedCodeAnalyzer>.CreateCompilation (m.SyntaxTree).Result; + var comp = CSharpAnalyzerVerifier<RequiresUnreferencedCodeAnalyzer>.CreateCompilation (m.SyntaxTree, MSBuildProperties).Result; var diags = comp.GetAnalyzerDiagnosticsAsync ().Result; var filtered = diags.Where (d => d.Location.SourceSpan.IntersectsWith (m.Span)) @@ -181,6 +181,11 @@ In diagnostics: } } + internal static (string, string)[] UseMSBuildProperties (params string[] MSBuildProperties) + { + return MSBuildProperties.Select (msbp => ($"build_property.{msbp}", "true")).ToArray (); + } + internal static void GetDirectoryPaths (out string rootSourceDirectory, out string testAssemblyPath, [CallerFilePath] string thisFile = null) { diff --git a/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs b/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs index 91b28b1aa..4d96f37d8 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs @@ -71,9 +71,9 @@ namespace ILLink.RoslynAnalyzer.Tests } /// <inheritdoc cref="AnalyzerVerifier{TAnalyzer, TTest, TVerifier}.VerifyAnalyzerAsync(string, DiagnosticResult[])"/> - public static async Task VerifyAnalyzerAsync (string src, params DiagnosticResult[] expected) + public static async Task VerifyAnalyzerAsync (string src, (string, string)[]? analyzerOptions = null, params DiagnosticResult[] expected) { - var diags = await (await CreateCompilation (src)).GetAllDiagnosticsAsync (); + var diags = await (await CreateCompilation (src, analyzerOptions)).GetAllDiagnosticsAsync (); var analyzers = ImmutableArray.Create<DiagnosticAnalyzer> (new TAnalyzer ()); VerifyDiagnosticResults (diags, analyzers, expected, DefaultVerifier); |