Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for <RunAnalyzers /> and <RunAnalyzersDuringLiveAnalysis /> #1739

Merged
merged 10 commits into from
Mar 26, 2020
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All changes to the project will be documented in this file.

## [1.34.15] - not yet released
* Support for .NET Core 3.1 in csx files (PR: [#1731](https://github.com/OmniSharp/omnisharp-roslyn/pull/1731))
* Support for `<RunAnalyzers />` and `<RunAnalyzersDuringLiveAnalysis />` (PR: [#1739](https://github.com/OmniSharp/omnisharp-roslyn/pull/1739))

## [1.34.14] - 2020-03-09
* Added support for `annotations` value of `Nullable` csproj property ([#1721](https://github.com/OmniSharp/omnisharp-roslyn/issues/1721), PR: [#1722](https://github.com/OmniSharp/omnisharp-roslyn/pull/1722))
Expand Down
3 changes: 3 additions & 0 deletions build.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
"ProjectWithMultiTFMLib",
"ExternAlias",
"ProjectWithComplexAnalyzers",
"ProjectWithDisabledAnalyzers",
"ProjectWithDisabledAnalyzers2",
"ProjectWithAnalyzers",
"NetCore30Project"
],
"CakeTestAssets": [
Expand Down
19 changes: 16 additions & 3 deletions src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ private class ProjectData
public ImmutableDictionary<string, string> ReferenceAliases { get; }
public ImmutableDictionary<string, string> ProjectReferenceAliases { get; }
public bool TreatWarningsAsErrors { get; }
public bool RunAnalyzers { get; }
public bool RunAnalyzersDuringLiveAnalysis { get; }
public string DefaultNamespace { get; }

private ProjectData()
Expand Down Expand Up @@ -91,6 +93,8 @@ private ProjectData(
string assemblyOriginatorKeyFile,
bool treatWarningsAsErrors,
string defaultNamespace,
bool runAnalyzers,
bool runAnalyzersDuringLiveAnalysis,
RuleSet ruleset)
: this()
{
Expand Down Expand Up @@ -122,6 +126,9 @@ private ProjectData(
TreatWarningsAsErrors = treatWarningsAsErrors;
RuleSet = ruleset;
DefaultNamespace = defaultNamespace;

RunAnalyzers = runAnalyzers;
RunAnalyzersDuringLiveAnalysis = runAnalyzersDuringLiveAnalysis;
}

private ProjectData(
Expand Down Expand Up @@ -149,12 +156,14 @@ private ProjectData(
ImmutableArray<string> additionalFiles,
bool treatWarningsAsErrors,
string defaultNamespace,
bool runAnalyzers,
bool runAnalyzersDuringLiveAnalysis,
RuleSet ruleset,
ImmutableDictionary<string, string> referenceAliases,
ImmutableDictionary<string, string> projectReferenceAliases)
: this(guid, name, assemblyName, targetPath, outputPath, intermediateOutputPath, projectAssetsFile,
configuration, platform, targetFramework, targetFrameworks, outputKind, languageVersion, nullableContextOptions, allowUnsafeCode, checkForOverflowUnderflow,
documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, ruleset)
documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, runAnalyzers, runAnalyzersDuringLiveAnalysis, ruleset)
{
SourceFiles = sourceFiles.EmptyIfDefault();
ProjectReferences = projectReferences.EmptyIfDefault();
Expand Down Expand Up @@ -200,11 +209,13 @@ public static ProjectData Create(MSB.Evaluation.Project project)
var signAssembly = PropertyConverter.ToBoolean(project.GetPropertyValue(PropertyNames.SignAssembly), defaultValue: false);
var assemblyOriginatorKeyFile = project.GetPropertyValue(PropertyNames.AssemblyOriginatorKeyFile);
var treatWarningsAsErrors = PropertyConverter.ToBoolean(project.GetPropertyValue(PropertyNames.TreatWarningsAsErrors), defaultValue: false);
var runAnalyzers = PropertyConverter.ToBoolean(project.GetPropertyValue(PropertyNames.RunAnalyzers), defaultValue: true);
var runAnalyzersDuringLiveAnalysis = PropertyConverter.ToBoolean(project.GetPropertyValue(PropertyNames.RunAnalyzersDuringLiveAnalysis), defaultValue: true);

return new ProjectData(
guid, name, assemblyName, targetPath, outputPath, intermediateOutputPath, projectAssetsFile,
configuration, platform, targetFramework, targetFrameworks, outputKind, languageVersion, nullableContextOptions, allowUnsafeCode, checkForOverflowUnderflow,
documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, ruleset: null);
documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, runAnalyzers, runAnalyzersDuringLiveAnalysis, ruleset: null);
}

public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance)
Expand Down Expand Up @@ -240,6 +251,8 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance)
var suppressedDiagnosticIds = PropertyConverter.ToSuppressedDiagnosticIds(projectInstance.GetPropertyValue(PropertyNames.NoWarn));
var signAssembly = PropertyConverter.ToBoolean(projectInstance.GetPropertyValue(PropertyNames.SignAssembly), defaultValue: false);
var treatWarningsAsErrors = PropertyConverter.ToBoolean(projectInstance.GetPropertyValue(PropertyNames.TreatWarningsAsErrors), defaultValue: false);
var runAnalyzers = PropertyConverter.ToBoolean(projectInstance.GetPropertyValue(PropertyNames.RunAnalyzers), defaultValue: true);
var runAnalyzersDuringLiveAnalysis = PropertyConverter.ToBoolean(projectInstance.GetPropertyValue(PropertyNames.RunAnalyzersDuringLiveAnalysis), defaultValue: true);
var assemblyOriginatorKeyFile = projectInstance.GetPropertyValue(PropertyNames.AssemblyOriginatorKeyFile);

var ruleset = ResolveRulesetIfAny(projectInstance);
Expand Down Expand Up @@ -310,7 +323,7 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance)
configuration, platform, targetFramework, targetFrameworks,
outputKind, languageVersion, nullableContextOptions, allowUnsafeCode, checkForOverflowUnderflow, documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds,
signAssembly, assemblyOriginatorKeyFile,
sourceFiles, projectReferences.ToImmutable(), references.ToImmutable(), packageReferences, analyzers, additionalFiles, treatWarningsAsErrors, defaultNamespace, ruleset,
sourceFiles, projectReferences.ToImmutable(), references.ToImmutable(), packageReferences, analyzers, additionalFiles, treatWarningsAsErrors, defaultNamespace, runAnalyzers, runAnalyzersDuringLiveAnalysis, ruleset,
referenceAliases.ToImmutableDictionary(), projectReferenceAliases.ToImmutable());
}

Expand Down
2 changes: 2 additions & 0 deletions src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ internal partial class ProjectFileInfo
public ImmutableDictionary<string, string> ReferenceAliases => _data.ReferenceAliases;
public ImmutableDictionary<string, string> ProjectReferenceAliases => _data.ProjectReferenceAliases;
public bool TreatWarningsAsErrors => _data.TreatWarningsAsErrors;
public bool RunAnalyzers => _data.RunAnalyzers;
public bool RunAnalyzersDuringLiveAnalysis => _data.RunAnalyzersDuringLiveAnalysis;
public string DefaultNamespace => _data.DefaultNamespace;

public ProjectIdInfo ProjectIdInfo { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public static ProjectInfo CreateProjectInfo(this ProjectFileInfo projectFileInfo

private static IEnumerable<AnalyzerReference> ResolveAnalyzerReferencesForProject(ProjectFileInfo projectFileInfo, IAnalyzerAssemblyLoader analyzerAssemblyLoader)
{
if (!projectFileInfo.RunAnalyzers || !projectFileInfo.RunAnalyzersDuringLiveAnalysis)
{
return Enumerable.Empty<AnalyzerReference>();
}

foreach(var analyzerAssemblyPath in projectFileInfo.Analyzers.Distinct())
{
analyzerAssemblyLoader.AddDependencyLocation(analyzerAssemblyPath);
Expand Down
2 changes: 2 additions & 0 deletions src/OmniSharp.MSBuild/ProjectFile/PropertyNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ internal static class PropertyNames
public const string _ResolveReferenceDependencies = nameof(_ResolveReferenceDependencies);
public const string RootNamespace = nameof(RootNamespace);
public const string RoslynTargetsPath = nameof(RoslynTargetsPath);
public const string RunAnalyzers = nameof(RunAnalyzers);
public const string RunAnalyzersDuringLiveAnalysis = nameof(RunAnalyzersDuringLiveAnalysis);
public const string SignAssembly = nameof(SignAssembly);
public const string SkipCompilerExecution = nameof(SkipCompilerExecution);
public const string SolutionDir = nameof(SolutionDir);
Expand Down
6 changes: 6 additions & 0 deletions src/OmniSharp.MSBuild/ProjectManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,12 @@ private void UpdateProject(string projectFilePath)

private void UpdateAnalyzerReferences(Project project, ProjectFileInfo projectFileInfo)
{
if (!projectFileInfo.RunAnalyzers || !projectFileInfo.RunAnalyzersDuringLiveAnalysis)
{
_workspace.SetAnalyzerReferences(project.Id, ImmutableArray<AnalyzerFileReference>.Empty);
return;
}

var analyzerFileReferences = projectFileInfo.Analyzers
.Select(analyzerReferencePath => new AnalyzerFileReference(analyzerReferencePath, _analyzerAssemblyLoader))
.ToImmutableArray();
Expand Down
12 changes: 12 additions & 0 deletions test-assets/test-projects/ProjectWithDisabledAnalyzers/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RestorePackagesPath>./nugets/</RestorePackagesPath>
<RunAnalyzers>false</RunAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
</ItemGroup>
</Project>
12 changes: 12 additions & 0 deletions test-assets/test-projects/ProjectWithDisabledAnalyzers2/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RestorePackagesPath>./nugets/</RestorePackagesPath>
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
</ItemGroup>
</Project>
16 changes: 15 additions & 1 deletion tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,28 @@ public async Task WhenProjectHasAnalyzersItDoesntLockAnalyzerDlls()
public async Task WhenProjectIsLoadedThenItContainsCustomRulesetsFromCsproj()
{
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("ProjectWithAnalyzers"))
using (var host = CreateMSBuildTestHost(testProject.Directory))
using (var host = CreateMSBuildTestHost(testProject.Directory, configurationData: TestHelpers.GetConfigurationDataWithAnalyzerConfig(roslynAnalyzersEnabled: true)))
{
var project = host.Workspace.CurrentSolution.Projects.Single();

Assert.Contains(project.CompilationOptions.SpecificDiagnosticOptions, x => x.Key == "CA1021" && x.Value == ReportDiagnostic.Warn);
}
}

[Theory]
[InlineData("ProjectWithDisabledAnalyzers")]
[InlineData("ProjectWithDisabledAnalyzers2")]
public async Task WhenProjectWithRunAnalyzersDisabledIsLoadedThenAnalyzersAreIgnored(string projectName)
{
using var testProject = await TestAssets.Instance.GetTestProjectAsync(projectName);
await RestoreProject(testProject);

using var host = CreateMSBuildTestHost(testProject.Directory, configurationData: TestHelpers.GetConfigurationDataWithAnalyzerConfig(roslynAnalyzersEnabled: true));
var analyzerReferences = host.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences.ToList();

Assert.Empty(analyzerReferences);
}

[Fact]
public async Task WhenProjectRulesetFileIsChangedThenUpdateRulesAccordingly()
{
Expand Down