Skip to content

Commit

Permalink
Merge pull request #728 from JoeRobich/analyzer-integration
Browse files Browse the repository at this point in the history
Run analyzers during integration tests
  • Loading branch information
JoeRobich committed Aug 11, 2020
2 parents fc437f6 + b469c6f commit 98c65c9
Show file tree
Hide file tree
Showing 20 changed files with 311 additions and 9 deletions.
4 changes: 2 additions & 2 deletions azure-pipelines-integration.yml
Expand Up @@ -64,7 +64,7 @@ jobs:
_targetSolution: "EntityFramework.sln"
_branchName: "master"
_sha: "efd56d44977632d1915a569046be6a23cb39da16"
timeoutInMinutes: 30
timeoutInMinutes: 40
steps:
- script: eng\integration-test.cmd -repo '$(_repo)' -branchName '$(_branchName)' -sha '$(_sha)' -targetSolution '$(_targetSolution)' -testPath '$(Build.SourcesDirectory)\temp' -stage 'prepare'
displayName: Prepare $(_repoName) for formatting
Expand All @@ -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;
}
}
36 changes: 31 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
Expand Down Expand Up @@ -31,15 +32,23 @@ internal partial class AnalyzerRunner : IAnalyzerRunner
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 && includeCompilerDiagnostics)
{
return;
}

// If are not running any analyzers and are not reporting compiler diagnostics, then there is
// nothing to report.
if (analyzers.IsEmpty && !includeCompilerDiagnostics)
// For projects targeting NetStandard, the Runtime references are resolved from the project.assets.json.
// This file is generated during a `dotnet restore`.
if (!AllReferencedProjectsLoaded(project))
{
logger.LogWarning(Resources.Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting, project.Name);
return;
}

var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (compilation is null)
{
return;
}
Expand All @@ -51,6 +60,8 @@ internal partial class AnalyzerRunner : IAnalyzerRunner
}
else
{
logger.LogDebug(Resources.Running_0_analyzers_on_1, analyzers.Length, project.Name);

var analyzerOptions = new CompilationWithAnalyzersOptions(
project.AnalyzerOptions,
onAnalyzerException: null,
Expand All @@ -75,6 +86,21 @@ internal partial class AnalyzerRunner : IAnalyzerRunner
result.AddDiagnostic(project, diagnostic);
}
}

return;

static bool AllReferencedProjectsLoaded(Project project)
{
// Use mscorlib to represent Runtime references being loaded.
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));
}
}
}
}
11 changes: 11 additions & 0 deletions src/Program.cs
Expand Up @@ -106,6 +106,10 @@ private static async Task<int> Main(string[] args)
}
}

var runtimeVersion = GetRuntimeVersion();

logger.LogDebug(Resources.The_dotnet_runtime_version_is_0, runtimeVersion);

// Load MSBuild
Environment.CurrentDirectory = workspaceDirectory;

Expand Down Expand Up @@ -265,5 +269,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];
}
}
}
9 changes: 9 additions & 0 deletions src/Resources.resx
Expand Up @@ -270,6 +270,15 @@
<data name="Unable_to_fix_0_No_associated_code_fix_found" xml:space="preserve">
<value>Unable to fix {0}. No associated code fix found.</value>
</data>
<data name="Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting" xml:space="preserve">
<value>Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</value>
</data>
<data name="Running_0_analyzers_on_1" xml:space="preserve">
<value>Running {0} analyzers on {1}.</value>
</data>
<data name="The_dotnet_runtime_version_is_0" xml:space="preserve">
<value>The dotnet runtime version is '{0}'.</value>
</data>
<data name="Remove_unnecessary_import" xml:space="preserve">
<value>Remove unnecessary import.</value>
</data>
Expand Down
15 changes: 15 additions & 0 deletions src/xlf/Resources.cs.xlf
Expand Up @@ -152,6 +152,11 @@
<target state="translated">{0} obsahuje více souborů řešení MSBuild. Určete, který soubor chcete použít, pomocí argumentu &lt;workspace&gt;.</target>
<note />
</trans-unit>
<trans-unit id="Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting">
<source>Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</source>
<target state="new">Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unnecessary_import">
<source>Remove unnecessary import.</source>
<target state="new">Remove unnecessary import.</target>
Expand All @@ -172,6 +177,11 @@
<target state="translated">Probíhá analýza {0}.</target>
<note />
</trans-unit>
<trans-unit id="Running_0_analyzers_on_1">
<source>Running {0} analyzers on {1}.</source>
<target state="new">Running {0} analyzers on {1}.</target>
<note />
</trans-unit>
<trans-unit id="Running_formatters">
<source>Running formatters.</source>
<target state="translated">Spouští se formátování.</target>
Expand All @@ -197,6 +207,11 @@
<target state="translated">Verze .NET CLI je {0}.</target>
<note />
</trans-unit>
<trans-unit id="The_dotnet_runtime_version_is_0">
<source>The dotnet runtime version is '{0}'.</source>
<target state="new">The dotnet runtime version is '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_file_0_does_not_appear_to_be_a_valid_project_or_solution_file">
<source>The file '{0}' does not appear to be a valid project or solution file.</source>
<target state="translated">Soubor {0} zřejmě není platný soubor projektu nebo řešení.</target>
Expand Down
15 changes: 15 additions & 0 deletions src/xlf/Resources.de.xlf
Expand Up @@ -152,6 +152,11 @@
<target state="translated">In "{0}" wurden mehrere MSBuild-Projektmappendateien gefunden. Geben Sie die zu verwendende Datei mit dem &lt;workspace&gt;-Argument an.</target>
<note />
</trans-unit>
<trans-unit id="Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting">
<source>Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</source>
<target state="new">Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unnecessary_import">
<source>Remove unnecessary import.</source>
<target state="new">Remove unnecessary import.</target>
Expand All @@ -172,6 +177,11 @@
<target state="translated">Die Analyse für "{0}" wird ausgeführt.</target>
<note />
</trans-unit>
<trans-unit id="Running_0_analyzers_on_1">
<source>Running {0} analyzers on {1}.</source>
<target state="new">Running {0} analyzers on {1}.</target>
<note />
</trans-unit>
<trans-unit id="Running_formatters">
<source>Running formatters.</source>
<target state="translated">Formatierer werden ausgeführt.</target>
Expand All @@ -197,6 +207,11 @@
<target state="translated">Die dotnet-CLI-Version ist "{0}".</target>
<note />
</trans-unit>
<trans-unit id="The_dotnet_runtime_version_is_0">
<source>The dotnet runtime version is '{0}'.</source>
<target state="new">The dotnet runtime version is '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_file_0_does_not_appear_to_be_a_valid_project_or_solution_file">
<source>The file '{0}' does not appear to be a valid project or solution file.</source>
<target state="translated">Die Datei "{0}" ist weder ein gültiges Projekt noch eine Projektmappendatei.</target>
Expand Down
15 changes: 15 additions & 0 deletions src/xlf/Resources.es.xlf
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Se encontraron varios archivos de solución MSBuild en "{0}". Especifique cuál debe usarse con el argumento &lt;workspace&gt;.</target>
<note />
</trans-unit>
<trans-unit id="Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting">
<source>Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</source>
<target state="new">Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unnecessary_import">
<source>Remove unnecessary import.</source>
<target state="new">Remove unnecessary import.</target>
Expand All @@ -172,6 +177,11 @@
<target state="translated">Ejecutando el análisis de {0}.</target>
<note />
</trans-unit>
<trans-unit id="Running_0_analyzers_on_1">
<source>Running {0} analyzers on {1}.</source>
<target state="new">Running {0} analyzers on {1}.</target>
<note />
</trans-unit>
<trans-unit id="Running_formatters">
<source>Running formatters.</source>
<target state="translated">Ejecutando los formateadores.</target>
Expand All @@ -197,6 +207,11 @@
<target state="translated">La versión de la CLI de dotnet es "{0}".</target>
<note />
</trans-unit>
<trans-unit id="The_dotnet_runtime_version_is_0">
<source>The dotnet runtime version is '{0}'.</source>
<target state="new">The dotnet runtime version is '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_file_0_does_not_appear_to_be_a_valid_project_or_solution_file">
<source>The file '{0}' does not appear to be a valid project or solution file.</source>
<target state="translated">El archivo "{0}" no parece ser un proyecto o archivo de solución válido.</target>
Expand Down
15 changes: 15 additions & 0 deletions src/xlf/Resources.fr.xlf
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Plusieurs fichiers solution MSBuild trouvés dans '{0}'. Spécifiez celui qui doit être utilisé avec l'argument &lt;espace de travail&gt;.</target>
<note />
</trans-unit>
<trans-unit id="Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting">
<source>Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</source>
<target state="new">Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unnecessary_import">
<source>Remove unnecessary import.</source>
<target state="new">Remove unnecessary import.</target>
Expand All @@ -172,6 +177,11 @@
<target state="translated">Exécution de l'analyse de {0}.</target>
<note />
</trans-unit>
<trans-unit id="Running_0_analyzers_on_1">
<source>Running {0} analyzers on {1}.</source>
<target state="new">Running {0} analyzers on {1}.</target>
<note />
</trans-unit>
<trans-unit id="Running_formatters">
<source>Running formatters.</source>
<target state="translated">Exécution des formateurs.</target>
Expand All @@ -197,6 +207,11 @@
<target state="translated">La version de l'interface CLI dotnet est '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_dotnet_runtime_version_is_0">
<source>The dotnet runtime version is '{0}'.</source>
<target state="new">The dotnet runtime version is '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_file_0_does_not_appear_to_be_a_valid_project_or_solution_file">
<source>The file '{0}' does not appear to be a valid project or solution file.</source>
<target state="translated">Le fichier '{0}' ne semble pas être un fichier projet ou solution valide.</target>
Expand Down
15 changes: 15 additions & 0 deletions src/xlf/Resources.it.xlf
Expand Up @@ -152,6 +152,11 @@
<target state="translated">In '{0}' sono stati trovati più file di soluzione MSBuild. Per specificare quello desiderato, usare l'argomento &lt;workspace&gt;.</target>
<note />
</trans-unit>
<trans-unit id="Required_references_did_not_load_for_0_or_referenced_project_Run_dotnet_restore_prior_to_formatting">
<source>Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</source>
<target state="new">Required references did not load for {0} or referenced project. Run `dotnet restore` prior to formatting.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unnecessary_import">
<source>Remove unnecessary import.</source>
<target state="new">Remove unnecessary import.</target>
Expand All @@ -172,6 +177,11 @@
<target state="translated">Esecuzione dell'analisi {0}.</target>
<note />
</trans-unit>
<trans-unit id="Running_0_analyzers_on_1">
<source>Running {0} analyzers on {1}.</source>
<target state="new">Running {0} analyzers on {1}.</target>
<note />
</trans-unit>
<trans-unit id="Running_formatters">
<source>Running formatters.</source>
<target state="translated">Esecuzione dei formattatori.</target>
Expand All @@ -197,6 +207,11 @@
<target state="translated">La versione dell'interfaccia della riga di comando di dotnet è '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_dotnet_runtime_version_is_0">
<source>The dotnet runtime version is '{0}'.</source>
<target state="new">The dotnet runtime version is '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="The_file_0_does_not_appear_to_be_a_valid_project_or_solution_file">
<source>The file '{0}' does not appear to be a valid project or solution file.</source>
<target state="translated">Il file '{0}' non sembra essere un file di progetto o di soluzione valido.</target>
Expand Down

0 comments on commit 98c65c9

Please sign in to comment.