Skip to content

Commit

Permalink
Run codestyle and 3rd party analyzers during integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeRobich committed Jul 30, 2020
1 parent 7c047cf commit 95da645
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 8 deletions.
2 changes: 1 addition & 1 deletion azure-pipelines-integration.yml
Expand Up @@ -73,4 +73,4 @@ jobs:
displayName: Run dotnet-format on $(_repoName) $(_targetSolution)

- script: eng\integration-test.cmd -repo '$(_repo)' -branchName '$(_branchName)' -sha '$(_sha)' -targetSolution '$(_targetSolution)' -testPath '$(Build.SourcesDirectory)\temp' -stage 'format-folder'
displayName: Run dotnet-format on $(_repoName) repo folder
displayName: Run dotnet-format on $(_repoName) repo folder
2 changes: 1 addition & 1 deletion eng/format-verifier.ps1
Expand Up @@ -62,7 +62,7 @@ try {

if ($stage -eq "format-workspace") {
Write-Output "$(Get-Date) - $solutionFile - Formatting Workspace"
$output = dotnet.exe run -p "$currentLocation\src\dotnet-format.csproj" -c Release -- $solution -v diag --check | Out-String
$output = dotnet.exe run -p "$currentLocation\src\dotnet-format.csproj" -c Release -- $solution --fix-style --fix-analyzers -v diag --check | Out-String
Write-Output $output.TrimEnd()

# Ignore CheckFailedExitCode since we don't expect these repos to be properly formatted.
Expand Down
50 changes: 49 additions & 1 deletion src/Analyzers/AnalyzerReferenceInformationProvider.cs
@@ -1,8 +1,10 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
Expand All @@ -12,6 +14,16 @@ namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
internal class AnalyzerReferenceInformationProvider : IAnalyzerInformationProvider
{
private static readonly string[] s_roslynCodeStyleAssmeblies = new[]
{
"Microsoft.CodeAnalysis.CodeStyle",
"Microsoft.CodeAnalysis.CodeStyle.Fixes",
"Microsoft.CodeAnalysis.CSharp.CodeStyle",
"Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes",
"Microsoft.CodeAnalysis.VisualBasic.CodeStyle",
"Microsoft.CodeAnalysis.VisualBasic.CodeStyle.Fixes"
};

public (ImmutableArray<DiagnosticAnalyzer> Analyzers, ImmutableArray<CodeFixProvider> Fixers) GetAnalyzersAndFixers(
Solution solution,
FormatOptions formatOptions,
Expand All @@ -25,11 +37,47 @@ internal class AnalyzerReferenceInformationProvider : IAnalyzerInformationProvid
var assemblies = solution.Projects
.SelectMany(project => project.AnalyzerReferences.Select(reference => reference.FullPath))
.Distinct()
.Select(path => Assembly.LoadFrom(path));
.Select(TryLoadAssemblyFrom)
.OfType<Assembly>()
.ToImmutableArray();

return AnalyzerFinderHelpers.LoadAnalyzersAndFixers(assemblies);
}

private Assembly? TryLoadAssemblyFrom(string? path)
{
// Since we are not deploying these assemblies we need to ensure the files exist.
if (path is null || !File.Exists(path))
{
return null;
}

// Roslyn CodeStyle analysis is handled with the --fix-style option.
var assemblyFileName = Path.GetFileNameWithoutExtension(path);
if (s_roslynCodeStyleAssmeblies.Contains(assemblyFileName))
{
return null;
}

try
{
// First try loading the assembly from disk.
return AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
}
catch { }

try
{
// Next see if this assembly has already been loaded into our context.
var assemblyName = AssemblyLoadContext.GetAssemblyName(path);
return AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName.Name));
}
catch { }

// Give up.
return null;
}

public DiagnosticSeverity GetSeverity(FormatOptions formatOptions) => formatOptions.AnalyzerSeverity;
}
}
33 changes: 28 additions & 5 deletions src/Analyzers/AnalyzerRunner.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -37,15 +38,21 @@ public AnalyzerRunner(bool includeCompilerDiagnostics)
ILogger logger,
CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (compilation is null)
// If are not running any analyzers and are not reporting compiler diagnostics, then there is
// nothing to report.
if (analyzers.IsEmpty && !_includeComplilerDiagnostics)
{
return;
}

// If are not running any analyzers and are not reporting compiler diagnostics, then there is
// nothing to report.
if (analyzers.IsEmpty && !_includeComplilerDiagnostics)
if (!AllReferencedProjectsLoaded(project))
{
Debug.WriteLine($"Required references did not load for {project.Name} or referenced project.");
return;
}

var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (compilation is null)
{
return;
}
Expand All @@ -57,6 +64,8 @@ public AnalyzerRunner(bool includeCompilerDiagnostics)
}
else
{
Debug.WriteLine($"Running {analyzers.Length} analyzers on {project.Name}.");

var analyzerOptions = new CompilationWithAnalyzersOptions(
project.AnalyzerOptions,
onAnalyzerException: null,
Expand All @@ -81,6 +90,20 @@ public AnalyzerRunner(bool includeCompilerDiagnostics)
result.AddDiagnostic(project, diagnostic);
}
}

return;

static bool AllReferencedProjectsLoaded(Project project)
{
if (!project.MetadataReferences.Any(reference => reference.Display?.EndsWith("mscorlib.dll") == true))
{
return false;
}

return project.ProjectReferences
.Select(projectReference => project.Solution.GetProject(projectReference.ProjectId))
.All(referencedProject => referencedProject != null && AllReferencedProjectsLoaded(referencedProject));
}
}
}
}
12 changes: 12 additions & 0 deletions src/Program.cs
Expand Up @@ -4,6 +4,7 @@
using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -106,6 +107,10 @@ private static async Task<int> Main(string[] args)
}
}

var runtimeVersion = GetRuntimeVersion();

Debug.WriteLine($"The dotnet runtime version is '{runtimeVersion}'.");

// Load MSBuild
Environment.CurrentDirectory = workspaceDirectory;

Expand Down Expand Up @@ -265,5 +270,12 @@ private static bool TryLoadMSBuild([NotNullWhen(returnValue: true)] out string?
return false;
}
}

private static string GetRuntimeVersion()
{
var pathParts = typeof(string).Assembly.Location.Split('\\', '/');
var netCoreAppIndex = Array.IndexOf(pathParts, "Microsoft.NETCore.App");
return pathParts[netCoreAppIndex + 1];
}
}
}
13 changes: 13 additions & 0 deletions tests/ProgramTests.cs
Expand Up @@ -193,5 +193,18 @@ public void CommandLine_FolderValidation_FailsIfFixStyleSpecified()
// Assert
Assert.Equal(1, result.Errors.Count);
}

[Fact]
public void CommandLine_AnalyzerOptions_CanSpecifyBothWithDefaults()
{
// Arrange
var sut = FormatCommand.CreateCommandLineOptions();

// Act
var result = sut.Parse(new[] { "--fix-analyzers", "--fix-style" });

// Assert
Assert.Equal(0, result.Errors.Count);
}
}
}

0 comments on commit 95da645

Please sign in to comment.