Skip to content

Commit

Permalink
Simplifier options (#60174)
Browse files Browse the repository at this point in the history
* SimplifierOptions

* Public option tests

* Serializability

* Fallback simplifier options for analyzers

* Null annotate

* Fallback simplifier options for code actions

* Document extension

* Avoid calling Reducer APIs that take OptionSet; CodeCleanupOptions

* Revert project change

* Remove GlobalIdeOptionsProvider

* Formatting

* Make IsApplicable abstract
  • Loading branch information
tmat authored Apr 14, 2022
1 parent ce9af42 commit 2b1fbd8
Show file tree
Hide file tree
Showing 257 changed files with 2,178 additions and 1,276 deletions.
4 changes: 4 additions & 0 deletions eng/config/BannedSymbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ M:Microsoft.CodeAnalysis.Formatting.Formatter.Format(Microsoft.CodeAnalysis.Synt
M:Microsoft.CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Workspace,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload with SyntaxFormattingOptions instead
M:Microsoft.CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Text.TextSpan,Microsoft.CodeAnalysis.Workspace,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload with SyntaxFormattingOptions instead
M:Microsoft.CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(Microsoft.CodeAnalysis.SyntaxNode,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Text.TextSpan},Microsoft.CodeAnalysis.Workspace,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload with SyntaxFormattingOptions instead
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.SyntaxAnnotation,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Text.TextSpan,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Text.TextSpan},Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
1 change: 1 addition & 0 deletions src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Include="$(MSBuildThisFileDirectory)PopulateSwitch\CSharpPopulateSwitchStatementDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnreachableCode\CSharpRemoveUnreachableCodeDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnreachableCode\RemoveUnreachableCodeHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Simplification\CSharpSimplifierOptionsFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SimplifyBooleanExpression\CSharpSimplifyConditionalDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SimplifyInterpolation\CSharpSimplifyInterpolationHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SimplifyInterpolation\CSharpSimplifyInterpolationDiagnosticAnalyzer.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Simplification;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.QualifyMemberAccess;
Expand All @@ -13,11 +14,14 @@ namespace Microsoft.CodeAnalysis.CSharp.QualifyMemberAccess
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpQualifyMemberAccessDiagnosticAnalyzer
: AbstractQualifyMemberAccessDiagnosticAnalyzer<SyntaxKind, ExpressionSyntax, SimpleNameSyntax>
: AbstractQualifyMemberAccessDiagnosticAnalyzer<SyntaxKind, ExpressionSyntax, SimpleNameSyntax, CSharpSimplifierOptions>
{
protected override string GetLanguageName()
=> LanguageNames.CSharp;

protected override CSharpSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree)
=> options.GetCSharpSimplifierOptions(syntaxTree);

protected override bool IsAlreadyQualifiedMemberAccess(ExpressionSyntax node)
=> node.IsKind(SyntaxKind.ThisExpression);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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 Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp.Simplification;

internal static class CSharpSimplifierOptionsFactory
{
internal static CSharpSimplifierOptions GetCSharpSimplifierOptions(this AnalyzerOptions options, SyntaxTree syntaxTree)
{
var configOptions = options.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree);
var ideOptions = options.GetIdeOptions();

return CSharpSimplifierOptions.Create(configOptions, (CSharpSimplifierOptions?)ideOptions.SimplifierOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Simplification;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Simplification;

namespace Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation
{
Expand Down Expand Up @@ -44,7 +46,6 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
if (syntaxTree.Options.LanguageVersion() < LanguageVersion.CSharp9)
return;

var optionSet = options.GetAnalyzerOptionSet(syntaxTree, cancellationToken);
var styleOption = options.GetOption(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, syntaxTree, cancellationToken);
if (!styleOption.Value)
{
Expand Down Expand Up @@ -73,11 +74,15 @@ objectCreation.Parent.Parent.Parent is VariableDeclarationSyntax variableDeclara
typeNode = variableDeclaration.Type;

var helper = CSharpUseImplicitTypeHelper.Instance;
if (helper.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken) &&
helper.AnalyzeTypeName(typeNode, semanticModel, optionSet, cancellationToken).IsStylePreferred)
if (helper.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken))
{
// this is a case where the user would prefer 'var'. don't offer to use an implicit object here.
return;
var simplifierOptions = context.Options.GetCSharpSimplifierOptions(syntaxTree);

if (helper.AnalyzeTypeName(typeNode, semanticModel, simplifierOptions, cancellationToken).IsStylePreferred)
{
// this is a case where the user would prefer 'var'. don't offer to use an implicit object here.
return;
}
}
}
else if (objectCreation.Parent.IsKind(SyntaxKind.ArrowExpressionClause))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Simplification;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
Expand Down Expand Up @@ -52,10 +53,8 @@ protected override void InitializeWorker(AnalysisContext context)
private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
{
var declarationStatement = context.Node;
var options = context.Options;
var syntaxTree = context.Node.SyntaxTree;
var cancellationToken = context.CancellationToken;
var optionSet = options.GetAnalyzerOptionSet(syntaxTree, cancellationToken);

var semanticModel = context.SemanticModel;
var declaredType = Helper.FindAnalyzableType(declarationStatement, semanticModel, cancellationToken);
Expand All @@ -64,8 +63,10 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
return;
}

var simplifierOptions = context.Options.GetCSharpSimplifierOptions(syntaxTree);

var typeStyle = Helper.AnalyzeTypeName(
declaredType, semanticModel, optionSet, cancellationToken);
declaredType, semanticModel, simplifierOptions, cancellationToken);
if (!typeStyle.IsStylePreferred || !typeStyle.CanConvert())
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Simplification;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
Expand Down Expand Up @@ -65,14 +66,17 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)

#if CODE_STYLE
var options = document.Project.AnalyzerOptions.GetAnalyzerOptionSet(syntaxRoot.SyntaxTree, cancellationToken);
var simplifierOptions = CSharpSimplifierOptions.Create(options, fallbackOptions: null);
#else
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var simplifierOptions = await SimplifierOptions.FromDocumentAsync(document, fallbackOptions: context.Options(document.Project.LanguageServices).SimplifierOptions, cancellationToken).ConfigureAwait(false);
#endif
var codeStyleOption = options.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement);

// Read the preferred placement option and verify if it can be applied to this code file.
// There are cases where we will not be able to fix the diagnostic and the user will need to resolve
// it manually.
var (placement, preferPreservation) = DeterminePlacement(compilationUnit, options);
var (placement, preferPreservation) = DeterminePlacement(compilationUnit, codeStyleOption);
if (preferPreservation)
return;

Expand All @@ -81,24 +85,22 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
CodeAction.Create(
CSharpAnalyzersResources.Move_misplaced_using_directives,
token => GetTransformedDocumentAsync(document, compilationUnit, GetAllUsingDirectives(compilationUnit), placement, token),
token => GetTransformedDocumentAsync(document, compilationUnit, GetAllUsingDirectives(compilationUnit), placement, simplifierOptions, token),
nameof(CSharpAnalyzersResources.Move_misplaced_using_directives)),
diagnostic);
}
}

internal static async Task<Document> TransformDocumentIfRequiredAsync(Document document, CancellationToken cancellationToken)
internal static async Task<Document> TransformDocumentIfRequiredAsync(
Document document,
SimplifierOptions simplifierOptions,
CodeStyleOption2<AddImportPlacement> importPlacementStyleOption,
CancellationToken cancellationToken)
{
var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var compilationUnit = (CompilationUnitSyntax)syntaxRoot;

#if CODE_STYLE
var options = document.Project.AnalyzerOptions.GetAnalyzerOptionSet(syntaxRoot.SyntaxTree, cancellationToken);
#else
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
#endif

var (placement, preferPreservation) = DeterminePlacement(compilationUnit, options);
var (placement, preferPreservation) = DeterminePlacement(compilationUnit, importPlacementStyleOption);
if (preferPreservation)
{
return document;
Expand All @@ -112,7 +114,7 @@ internal static async Task<Document> TransformDocumentIfRequiredAsync(Document d
return document;
}

return await GetTransformedDocumentAsync(document, compilationUnit, allUsingDirectives, placement, cancellationToken).ConfigureAwait(false);
return await GetTransformedDocumentAsync(document, compilationUnit, allUsingDirectives, placement, simplifierOptions, cancellationToken).ConfigureAwait(false);
}

private static ImmutableList<UsingDirectiveSyntax> GetAllUsingDirectives(CompilationUnitSyntax compilationUnit)
Expand All @@ -127,6 +129,7 @@ private static async Task<Document> GetTransformedDocumentAsync(
CompilationUnitSyntax compilationUnit,
IEnumerable<UsingDirectiveSyntax> allUsingDirectives,
AddImportPlacement placement,
SimplifierOptions simplifierOptions,
CancellationToken cancellationToken)
{
var bannerService = document.GetRequiredLanguageService<IFileBannerFactsService>();
Expand All @@ -149,8 +152,13 @@ private static async Task<Document> GetTransformedDocumentAsync(
var newDocument = document.WithSyntaxRoot(newCompilationUnitWithHeader);

// Simplify usings now that they have been moved and are in the proper context.
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
return await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, options, cancellationToken).ConfigureAwait(false);
#if CODE_STYLE
#pragma warning disable RS0030 // Do not used banned APIs
return await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, optionSet: null, cancellationToken).ConfigureAwait(false);
#pragma warning restore
#else
return await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, simplifierOptions, cancellationToken).ConfigureAwait(false);
#endif
}

private static async Task<CompilationUnitSyntax> ExpandUsingDirectivesAsync(Document document, CompilationUnitSyntax containerNode, IEnumerable<UsingDirectiveSyntax> allUsingDirectives, CancellationToken cancellationToken)
Expand Down Expand Up @@ -360,12 +368,10 @@ private static TSyntaxNode EnsureLeadingBlankLineBeforeFirstMember<TSyntaxNode>(
return node.ReplaceNode(firstMember, newFirstMember);
}

private static (AddImportPlacement placement, bool preferPreservation) DeterminePlacement(CompilationUnitSyntax compilationUnit, OptionSet options)
private static (AddImportPlacement placement, bool preferPreservation) DeterminePlacement(CompilationUnitSyntax compilationUnit, CodeStyleOption2<AddImportPlacement> styleOption)
{
var codeStyleOption = options.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement);

var placement = codeStyleOption.Value;
var preferPreservation = codeStyleOption.Notification == NotificationOption2.None;
var placement = styleOption.Value;
var preferPreservation = styleOption.Notification == NotificationOption2.None;

if (preferPreservation || placement == AddImportPlacement.OutsideNamespace)
return (placement, preferPreservation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@

using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.Simplification;

#if CODE_STYLE
using TOption = Microsoft.CodeAnalysis.Options.IOption2;
Expand All @@ -27,7 +23,8 @@ internal readonly record struct IdeAnalyzerOptions(
[property: DataMember(Order = 3)] bool ReportInvalidPlaceholdersInStringDotFormatCalls = true,
[property: DataMember(Order = 4)] bool ReportInvalidRegexPatterns = true,
[property: DataMember(Order = 5)] bool ReportInvalidJsonPatterns = true,
[property: DataMember(Order = 6)] bool DetectAndOfferEditorFeaturesForProbableJsonStrings = true)
[property: DataMember(Order = 6)] bool DetectAndOfferEditorFeaturesForProbableJsonStrings = true,
[property: DataMember(Order = 7)] SimplifierOptions? SimplifierOptions = null)
{
public IdeAnalyzerOptions()
: this(CrashOnAnalyzerException: false)
Expand Down
Loading

0 comments on commit 2b1fbd8

Please sign in to comment.