diff --git a/src/Analyzers/AnalyzerFormatter.cs b/src/Analyzers/AnalyzerFormatter.cs index 2676e3a549..07bed02a8c 100644 --- a/src/Analyzers/AnalyzerFormatter.cs +++ b/src/Analyzers/AnalyzerFormatter.cs @@ -16,6 +16,20 @@ namespace Microsoft.CodeAnalysis.Tools.Analyzers { internal class AnalyzerFormatter : ICodeFormatter { + public static AnalyzerFormatter CodeStyleFormatter => new AnalyzerFormatter( + Resources.Code_Style, + FixCategory.CodeStyle, + new CodeStyleInformationProvider(), + new AnalyzerRunner(), + new SolutionCodeFixApplier()); + + public static AnalyzerFormatter ThirdPartyFormatter => new AnalyzerFormatter( + Resources.Analyzer_Reference, + FixCategory.Analyzers, + new AnalyzerReferenceInformationProvider(), + new AnalyzerRunner(), + new SolutionCodeFixApplier()); + private readonly string _name; private readonly IAnalyzerInformationProvider _informationProvider; private readonly IAnalyzerRunner _runner; diff --git a/src/CodeFormatter.cs b/src/CodeFormatter.cs index 86bace4ce8..e69e55dc04 100644 --- a/src/CodeFormatter.cs +++ b/src/CodeFormatter.cs @@ -25,8 +25,8 @@ internal static class CodeFormatter new CharsetFormatter(), new OrganizeImportsFormatter(), new UnnecessaryImportsFormatter(), - new AnalyzerFormatter(Resources.Code_Style, FixCategory.CodeStyle, new CodeStyleInformationProvider(), new AnalyzerRunner(), new SolutionCodeFixApplier()), - new AnalyzerFormatter(Resources.Analyzer_Reference, FixCategory.Analyzers, new AnalyzerReferenceInformationProvider(), new AnalyzerRunner(), new SolutionCodeFixApplier())); + AnalyzerFormatter.CodeStyleFormatter, + AnalyzerFormatter.ThirdPartyFormatter); public static async Task FormatWorkspaceAsync( FormatOptions formatOptions, diff --git a/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs b/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs new file mode 100644 index 0000000000..9cd2bdc2a0 --- /dev/null +++ b/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Tools.Analyzers; +using Microsoft.CodeAnalysis.Tools.Formatters; +using Microsoft.CodeAnalysis.Tools.Tests.Formatters; +using Xunit; + +namespace Microsoft.CodeAnalysis.Tools.Tests.Analyzers +{ + public class CodeStyleAnalyzerFormatterTests : CSharpFormatterTests + { + private protected override ICodeFormatter Formatter => AnalyzerFormatter.CodeStyleFormatter; + + [Fact] + public async Task TestUseVarCodeStyle_AppliesWhenNotUsingVar() + { + var testCode = @" +using System.Collections.Generic; + +class C +{ + void M() + { + object obj = new object(); + List list = new List(); + int count = 5; + } +}"; + + var expectedCode = @" +using System.Collections.Generic; + +class C +{ + void M() + { + var obj = new object(); + var list = new List(); + var count = 5; + } +}"; + + var editorConfig = new Dictionary() + { + /// Prefer "var" everywhere + ["dotnet_diagnostic.IDE0007.severity"] = "error", + ["csharp_style_var_for_built_in_types"] = "true:error", + ["csharp_style_var_when_type_is_apparent"] = "true:error", + ["csharp_style_var_elsewhere"] = "true:error", + }; + + await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.CodeStyle); + } + } +} diff --git a/tests/Formatters/AbstractFormatterTests.cs b/tests/Formatters/AbstractFormatterTests.cs index 12949fd4e4..8d4e895dd3 100644 --- a/tests/Formatters/AbstractFormatterTests.cs +++ b/tests/Formatters/AbstractFormatterTests.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Tools.Formatters; @@ -23,12 +22,6 @@ namespace Microsoft.CodeAnalysis.Tools.Tests.Formatters { public abstract class AbstractFormatterTest { - private static MetadataReference CorlibReference => MetadataReference.CreateFromFile(typeof(object).Assembly.Location).WithAliases(ImmutableArray.Create("global", "corlib")); - private static MetadataReference SystemReference => MetadataReference.CreateFromFile(typeof(System.Diagnostics.Debug).Assembly.Location).WithAliases(ImmutableArray.Create("global", "system")); - private static MetadataReference SystemCoreReference => MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location); - private static MetadataReference CodeAnalysisReference => MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); - - private static MetadataReference SystemCollectionsImmutableReference => MetadataReference.CreateFromFile(typeof(ImmutableArray).Assembly.Location); private static MetadataReference MicrosoftVisualBasicReference => MetadataReference.CreateFromFile(typeof(Microsoft.VisualBasic.Strings).Assembly.Location); private static Lazy ExportProviderFactory { get; } @@ -49,6 +42,8 @@ static AbstractFormatterTest() LazyThreadSafetyMode.ExecutionAndPublication); } + protected virtual ReferenceAssemblies ReferenceAssemblies => ReferenceAssemblies.Default; + protected virtual string DefaultFilePathPrefix => "Test"; protected virtual string DefaultTestProjectName => "TestProject"; @@ -59,7 +54,7 @@ static AbstractFormatterTest() protected virtual string DefaultTestProjectPath => Path.Combine(DefaultFolderPath, $"{DefaultTestProjectName}.{DefaultFileExt}proj"); - protected virtual string DefaultEditorConfigPath => Path.Combine(DefaultFolderPath + ".editorconfig"); + protected virtual string DefaultEditorConfigPath => Path.Combine(DefaultFolderPath, ".editorconfig"); protected virtual string DefaultFilePath => Path.Combine(DefaultFolderPath, $"{DefaultFilePathPrefix}0.{DefaultFileExt}"); @@ -77,7 +72,7 @@ protected AbstractFormatterTest() /// public abstract string Language { get; } - private static ILogger Logger => new TestLogger(); + private static TestLogger Logger => new TestLogger(); public SolutionState TestState { get; } @@ -129,7 +124,7 @@ protected AbstractFormatterTest() var fileMatcher = SourceFileMatcher.CreateMatcher(new[] { document.FilePath }, exclude: Array.Empty()); var formatOptions = new FormatOptions( workspaceFilePath: project.FilePath, - workspaceType: WorkspaceType.Folder, + workspaceType: WorkspaceType.Solution, logLevel: LogLevel.Trace, fixCategory, codeStyleSeverity, @@ -174,12 +169,6 @@ protected AbstractFormatterTest() /// public Dictionary XmlReferences { get; } = new Dictionary(); - /// - /// Gets a collection of transformation functions to apply to during diagnostic - /// or code fix test setup. - /// - public List> OptionsTransforms { get; } = new List>(); - /// /// Given an array of strings as sources and a language, turn them into a and return the /// solution. @@ -252,7 +241,7 @@ protected virtual Project CreateProjectImpl((string filename, SourceText content { (var newFileName, var source) = sources[i]; var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); - solution = solution.AddDocument(documentId, newFileName, source, filePath: Path.Combine(DefaultTestProjectPath, newFileName)); + solution = solution.AddDocument(documentId, newFileName, source, filePath: Path.Combine(DefaultFolderPath, newFileName)); } for (var i = 0; i < additionalFiles.Length; i++) @@ -274,15 +263,18 @@ protected virtual Project CreateProjectImpl((string filename, SourceText content /// The created solution. protected virtual Solution CreateSolution(ProjectId projectId, string language, SourceText editorConfigText) { - var compilationOptions = CreateCompilationOptions(); - var xmlReferenceResolver = new TestXmlReferenceResolver(); foreach (var xmlReference in XmlReferences) { xmlReferenceResolver.XmlReferences.Add(xmlReference.Key, xmlReference.Value); } - compilationOptions = compilationOptions.WithXmlReferenceResolver(xmlReferenceResolver); + var compilationOptions = CreateCompilationOptions() + .WithXmlReferenceResolver(xmlReferenceResolver) + .WithAssemblyIdentityComparer(ReferenceAssemblies.AssemblyIdentityComparer); + + var parseOptions = CreateParseOptions(); + var referenceAssemblies = ReferenceAssemblies.ResolveAsync(language, CancellationToken.None).GetAwaiter().GetResult(); var editorConfigDocument = DocumentInfo.Create( DocumentId.CreateNewId(projectId, DefaultEditorConfigPath), @@ -290,32 +282,30 @@ protected virtual Solution CreateSolution(ProjectId projectId, string language, loader: TextLoader.From(TextAndVersion.Create(editorConfigText, VersionStamp.Create())), filePath: DefaultEditorConfigPath); - var projectInfo = ProjectInfo.Create(projectId, VersionStamp.Create(), DefaultTestProjectName, DefaultTestProjectName, language, filePath: DefaultTestProjectPath) + var projectInfo = ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name: DefaultTestProjectName, + assemblyName: DefaultTestProjectName, + language, + filePath: DefaultTestProjectPath, + outputFilePath: Path.ChangeExtension(DefaultTestProjectPath, "dll"), + compilationOptions: compilationOptions, + parseOptions: parseOptions, + metadataReferences: referenceAssemblies, + isSubmission: false) + .WithDefaultNamespace(DefaultTestProjectName) .WithAnalyzerConfigDocuments(ImmutableArray.Create(editorConfigDocument)); var solution = CreateWorkspace() .CurrentSolution - .AddProject(projectInfo) - .WithProjectCompilationOptions(projectId, compilationOptions) - .AddMetadataReference(projectId, CorlibReference) - .AddMetadataReference(projectId, SystemReference) - .AddMetadataReference(projectId, SystemCoreReference) - .AddMetadataReference(projectId, CodeAnalysisReference) - .AddMetadataReference(projectId, SystemCollectionsImmutableReference); + .AddProject(projectInfo); if (language == LanguageNames.VisualBasic) { solution = solution.AddMetadataReference(projectId, MicrosoftVisualBasicReference); } - foreach (var transform in OptionsTransforms) - { - solution.Workspace.TryApplyChanges(solution.WithOptions(transform(solution.Workspace.Options))); - } - - var parseOptions = solution.GetProject(projectId).ParseOptions; - solution = solution.WithProjectParseOptions(projectId, parseOptions.WithDocumentationMode(DocumentationMode.Diagnose)); - return solution; } @@ -327,5 +317,7 @@ public virtual AdhocWorkspace CreateWorkspace() } protected abstract CompilationOptions CreateCompilationOptions(); + + protected abstract ParseOptions CreateParseOptions(); } } diff --git a/tests/Formatters/CSharpFormatterTests.cs b/tests/Formatters/CSharpFormatterTests.cs index 255a0422b2..1c77af21c0 100644 --- a/tests/Formatters/CSharpFormatterTests.cs +++ b/tests/Formatters/CSharpFormatterTests.cs @@ -12,5 +12,8 @@ public abstract class CSharpFormatterTests : AbstractFormatterTest protected override CompilationOptions CreateCompilationOptions() => new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true); + + protected override ParseOptions CreateParseOptions() + => new CSharpParseOptions(LanguageVersion.Default, DocumentationMode.Diagnose); } }