From 7f58c8a9bdae22da74f1f56f937c12b3537331fb Mon Sep 17 00:00:00 2001 From: kzrnm Date: Tue, 31 May 2022 06:28:07 +0900 Subject: [PATCH] AtCoderAnalyzer_UseMethodImplNumeric --- .../AggressiveInliningCodeFixProvider.cs | 12 +- .../AtCoderAnalyzer/AtCoderAnalyzerConfig.cs | 16 +++ .../CreateOperatorCodeFixProvider.cs | 54 ++++---- .../CreateOperators/EnumerateMember.cs | 31 +++-- .../OperatorEnumerateMember.cs | 2 +- .../Specified/AdditionEnumerateMember.cs | 2 +- .../Specified/CastEnumerateMember.cs | 2 +- .../CompareOperatorEnumerateMember.cs | 2 +- .../Specified/ComparerEnumerateMember.cs | 2 +- .../Specified/DivisionEnumerateMember.cs | 2 +- .../Specified/MinMaxValueEnumerateMember.cs | 2 +- .../MultiplicationEnumerateMember.cs | 2 +- .../Specified/ShiftEnumerateMember.cs | 2 +- .../Specified/SubtractEnumerateMember.cs | 2 +- .../Specified/UnaryNumEnumerateMember.cs | 2 +- .../AtCoderAnalyzer/Helpers/SyntaxHelpers.cs | 8 +- .../AggressiveInliningCodeFixProviderTest.cs | 79 ++++++++++- .../CreateOperatorCodeFixProviderTest.cs | 125 +++++++++++++++++- 18 files changed, 279 insertions(+), 68 deletions(-) create mode 100644 Source/AtCoderAnalyzer/AtCoderAnalyzerConfig.cs diff --git a/Source/AtCoderAnalyzer/AggressiveInliningCodeFixProvider.cs b/Source/AtCoderAnalyzer/AggressiveInliningCodeFixProvider.cs index 3bf5d5e1..3fe719c0 100644 --- a/Source/AtCoderAnalyzer/AggressiveInliningCodeFixProvider.cs +++ b/Source/AtCoderAnalyzer/AggressiveInliningCodeFixProvider.cs @@ -34,6 +34,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) is not CompilationUnitSyntax root) return; + var config = AtCoderAnalyzerConfig.Parse(context.Document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GlobalOptions); var diagnostic = context.Diagnostics[0]; var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -42,7 +43,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; var action = CodeAction.Create(title: title, - createChangedDocument: c => AddAggressiveInlining(context.Document, root, diagnosticSpan.Start, typeDeclarationSyntax, c), + createChangedDocument: c => AddAggressiveInlining(context.Document, root, diagnosticSpan.Start, config, typeDeclarationSyntax, c), equivalenceKey: title); context.RegisterCodeFix(action, diagnostic); } @@ -50,10 +51,11 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) private async Task AddAggressiveInlining( Document document, CompilationUnitSyntax root, int postion, + AtCoderAnalyzerConfig config, TypeDeclarationSyntax typeDeclarationSyntax, CancellationToken cancellationToken) { root = root.ReplaceNode(typeDeclarationSyntax, - new AddAggressiveInliningRewriter(await document.GetSemanticModelAsync(cancellationToken), postion) + new AddAggressiveInliningRewriter(await document.GetSemanticModelAsync(cancellationToken), postion, config) .Visit(typeDeclarationSyntax)); return document.WithSyntaxRoot(root); @@ -66,7 +68,7 @@ private class AddAggressiveInliningRewriter : CSharpSyntaxRewriter private readonly INamedTypeSymbol methodImplAttribute; private readonly INamedTypeSymbol methodImplOptions; private readonly AttributeSyntax aggressiveInliningAttribute; - public AddAggressiveInliningRewriter(SemanticModel semanticModel, int position) : base(false) + public AddAggressiveInliningRewriter(SemanticModel semanticModel, int position, AtCoderAnalyzerConfig config) : base(false) { this.semanticModel = semanticModel; this.position = position; @@ -74,7 +76,9 @@ public AddAggressiveInliningRewriter(SemanticModel semanticModel, int position) System_Runtime_CompilerServices_MethodImplAttribute); methodImplOptions = semanticModel.Compilation.GetTypeByMetadataName( System_Runtime_CompilerServices_MethodImplOptions); - aggressiveInliningAttribute = SyntaxHelpers.AggressiveInliningAttribute(methodImplAttribute.ToMinimalDisplayString(semanticModel, position), methodImplOptions.ToMinimalDisplayString(semanticModel, position)); + aggressiveInliningAttribute = SyntaxHelpers.AggressiveInliningAttribute( + methodImplAttribute.ToMinimalDisplayString(semanticModel, position), + methodImplOptions.ToMinimalDisplayString(semanticModel, position), config.UseMethodImplNumeric); } public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) diff --git a/Source/AtCoderAnalyzer/AtCoderAnalyzerConfig.cs b/Source/AtCoderAnalyzer/AtCoderAnalyzerConfig.cs new file mode 100644 index 00000000..8e3e148b --- /dev/null +++ b/Source/AtCoderAnalyzer/AtCoderAnalyzerConfig.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace AtCoderAnalyzer +{ + public record AtCoderAnalyzerConfig(bool UseMethodImplNumeric) + { + public static AtCoderAnalyzerConfig Parse(AnalyzerConfigOptions analyzerConfigOptions) + { + var useMethodImplNumeric = analyzerConfigOptions.TryGetValue("build_property.AtCoderAnalyzer_UseMethodImplNumeric", out var v) && + StringComparer.OrdinalIgnoreCase.Equals(v, "true"); + + return new(useMethodImplNumeric); + } + } +} diff --git a/Source/AtCoderAnalyzer/CreateOperatorCodeFixProvider.cs b/Source/AtCoderAnalyzer/CreateOperatorCodeFixProvider.cs index 2618fbee..6a00e39c 100644 --- a/Source/AtCoderAnalyzer/CreateOperatorCodeFixProvider.cs +++ b/Source/AtCoderAnalyzer/CreateOperatorCodeFixProvider.cs @@ -28,6 +28,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false) is not CompilationUnitSyntax root) return; + var config = AtCoderAnalyzerConfig.Parse(context.Document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GlobalOptions); var diagnostic = context.Diagnostics[0]; var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -102,48 +103,47 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) } var action = CodeAction.Create(title: title, - createChangedDocument: c => AddOperatorType( + createChangedDocument: c => new OperatorTypeSyntaxBuilder(semanticModel, config).AddOperatorType( context.Document, root, - semanticModel, constraintArrayDic.ToImmutable()), equivalenceKey: title); context.RegisterCodeFix(action, diagnostic); } - private async Task AddOperatorType( - Document document, - CompilationUnitSyntax root, - SemanticModel semanticModel, - ImmutableDictionary> constraintDic) - { - bool hasMethod = false; - var usings = root.Usings.ToNamespaceHashSet(); - var builder = new OperatorTypeSyntaxBuilder(semanticModel); - - MemberDeclarationSyntax[] newMembers = new MemberDeclarationSyntax[constraintDic.Count]; - foreach (var (p, i) in constraintDic.Select((p, i) => (p, i))) - { - bool m; - (newMembers[i], m) = builder.Build(p.Key, p.Value); - hasMethod |= m; - } - - root = root.AddMembers(newMembers); - return document.WithSyntaxRoot(root); - } - private class OperatorTypeSyntaxBuilder { private readonly SemanticModel semanticModel; private readonly int origPosition; - public OperatorTypeSyntaxBuilder(SemanticModel semanticModel) + private AtCoderAnalyzerConfig config; + public OperatorTypeSyntaxBuilder(SemanticModel semanticModel, AtCoderAnalyzerConfig config) { this.semanticModel = semanticModel; origPosition = semanticModel.SyntaxTree.Length; + this.config = config; + } + + public async Task AddOperatorType( + Document document, + CompilationUnitSyntax root, + ImmutableDictionary> constraintDic) + { + bool hasMethod = false; + var usings = root.Usings.ToNamespaceHashSet(); + + MemberDeclarationSyntax[] newMembers = new MemberDeclarationSyntax[constraintDic.Count]; + foreach (var (p, i) in constraintDic.Select((p, i) => (p, i))) + { + bool m; + (newMembers[i], m) = Build(p.Key, p.Value); + hasMethod |= m; + } + + return document.WithSyntaxRoot(root.AddMembers(newMembers)); + } - public (StructDeclarationSyntax syntax, bool hasMethod) Build(string operatorTypeName, ImmutableArray constraints) + private (StructDeclarationSyntax syntax, bool hasMethod) Build(string operatorTypeName, ImmutableArray constraints) { bool hasMethod = false; var members = ImmutableList.CreateBuilder(); @@ -156,7 +156,7 @@ public OperatorTypeSyntaxBuilder(SemanticModel semanticModel) if (!added.Add(baseType)) continue; - foreach (var (member, isMethod) in EnumerateMember.Create(semanticModel, baseType).EnumerateMemberSyntax()) + foreach (var (member, isMethod) in EnumerateMember.Create(semanticModel, baseType, config).EnumerateMemberSyntax()) { members.Add(member); hasMethod |= isMethod; diff --git a/Source/AtCoderAnalyzer/CreateOperators/EnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/EnumerateMember.cs index 120fe02d..2f6eb6ec 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/EnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/EnumerateMember.cs @@ -14,7 +14,8 @@ internal class EnumerateMember protected ITypeSymbol TypeSymbol { get; } private readonly INamedTypeSymbol methodImplAttribute; private readonly INamedTypeSymbol methodImplOptions; - protected EnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) + private readonly AtCoderAnalyzerConfig config; + protected EnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) { SemanticModel = semanticModel; TypeSymbol = typeSymbol; @@ -22,20 +23,21 @@ protected EnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) Constants.System_Runtime_CompilerServices_MethodImplAttribute); methodImplOptions = semanticModel.Compilation.GetTypeByMetadataName( Constants.System_Runtime_CompilerServices_MethodImplOptions); + this.config = config; } - public static EnumerateMember Create(SemanticModel semanticModel, ITypeSymbol typeSymbol) => typeSymbol.OriginalDefinition.ToDisplayString() switch + public static EnumerateMember Create(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) => typeSymbol.OriginalDefinition.ToDisplayString() switch { - "AtCoder.Operators.IAdditionOperator" => new AdditionEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.ISubtractOperator" => new SubtractEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.IMultiplicationOperator" => new MultiplicationEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.IDivisionOperator" => new DivisionEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.IUnaryNumOperator" => new UnaryNumEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.ICompareOperator" => new CompareOperatorEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.IMinMaxValue" => new MinMaxValueEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.IShiftOperator" => new ShiftEnumerateMember(semanticModel, typeSymbol), - "AtCoder.Operators.ICastOperator" => new CastEnumerateMember(semanticModel, typeSymbol), - "System.Collections.Generic.IComparer" => new ComparerEnumerateMember(semanticModel, typeSymbol), - _ => new EnumerateMember(semanticModel, typeSymbol), + "AtCoder.Operators.IAdditionOperator" => new AdditionEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.ISubtractOperator" => new SubtractEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.IMultiplicationOperator" => new MultiplicationEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.IDivisionOperator" => new DivisionEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.IUnaryNumOperator" => new UnaryNumEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.ICompareOperator" => new CompareOperatorEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.IMinMaxValue" => new MinMaxValueEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.IShiftOperator" => new ShiftEnumerateMember(semanticModel, typeSymbol, config), + "AtCoder.Operators.ICastOperator" => new CastEnumerateMember(semanticModel, typeSymbol, config), + "System.Collections.Generic.IComparer" => new ComparerEnumerateMember(semanticModel, typeSymbol, config), + _ => new EnumerateMember(semanticModel, typeSymbol, config), }; public IEnumerable<(MemberDeclarationSyntax Syntax, bool IsMethod)> EnumerateMemberSyntax() @@ -91,7 +93,8 @@ private MethodDeclarationSyntax CommonMethodDeclaration(IMethodSymbol symbol, Se SingletonSeparatedList( SyntaxHelpers.AggressiveInliningAttribute( methodImplAttribute.ToMinimalDisplayString(semanticModel, position), - methodImplOptions.ToMinimalDisplayString(semanticModel, position)))))) + methodImplOptions.ToMinimalDisplayString(semanticModel, position), + config.UseMethodImplNumeric))))) .WithParameterList(symbol.ToParameterListSyntax(semanticModel, semanticModel.SyntaxTree.Length)); protected MethodDeclarationSyntax CreateMethodSyntax(SemanticModel semanticModel, int position, IMethodSymbol symbol, BlockSyntax block) { diff --git a/Source/AtCoderAnalyzer/CreateOperators/OperatorEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/OperatorEnumerateMember.cs index f425f844..75578675 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/OperatorEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/OperatorEnumerateMember.cs @@ -7,7 +7,7 @@ namespace AtCoderAnalyzer.CreateOperators { internal abstract class OperatorEnumerateMember : EnumerateMember { - protected OperatorEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + protected OperatorEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected abstract SyntaxKind? GetSyntaxKind(IMethodSymbol symbol); protected override MethodDeclarationSyntax CreateMethodSyntax(IMethodSymbol symbol) diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/AdditionEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/AdditionEnumerateMember.cs index bd288466..3a6246e4 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/AdditionEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/AdditionEnumerateMember.cs @@ -5,7 +5,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class AdditionEnumerateMember : OperatorEnumerateMember { - internal AdditionEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal AdditionEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override SyntaxKind? GetSyntaxKind(IMethodSymbol symbol) => symbol switch diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/CastEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/CastEnumerateMember.cs index 45dfc4c5..b4b486b0 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/CastEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/CastEnumerateMember.cs @@ -7,7 +7,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class CastEnumerateMember : EnumerateMember { - internal CastEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal CastEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override MethodDeclarationSyntax CreateMethodSyntax(IMethodSymbol symbol) { if (symbol is diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/CompareOperatorEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/CompareOperatorEnumerateMember.cs index 61cf9824..631f4d77 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/CompareOperatorEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/CompareOperatorEnumerateMember.cs @@ -5,7 +5,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class CompareOperatorEnumerateMember : OperatorEnumerateMember { - internal CompareOperatorEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal CompareOperatorEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override SyntaxKind? GetSyntaxKind(IMethodSymbol symbol) => symbol switch diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/ComparerEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/ComparerEnumerateMember.cs index 880847e3..3431bca7 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/ComparerEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/ComparerEnumerateMember.cs @@ -9,7 +9,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class ComparerEnumerateMember : EnumerateMember { - internal ComparerEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal ComparerEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override MethodDeclarationSyntax CreateMethodSyntax(IMethodSymbol symbol) { if (symbol is diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/DivisionEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/DivisionEnumerateMember.cs index a3b55703..df27df5a 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/DivisionEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/DivisionEnumerateMember.cs @@ -5,7 +5,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class DivisionEnumerateMember : OperatorEnumerateMember { - internal DivisionEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal DivisionEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override SyntaxKind? GetSyntaxKind(IMethodSymbol symbol) => symbol switch diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/MinMaxValueEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/MinMaxValueEnumerateMember.cs index 460a23ef..bed8aaf6 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/MinMaxValueEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/MinMaxValueEnumerateMember.cs @@ -8,7 +8,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class MinMaxValueEnumerateMember : EnumerateMember { - internal MinMaxValueEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal MinMaxValueEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override PropertyDeclarationSyntax CreatePropertySyntax(IPropertySymbol symbol) { if (symbol is { Name: "MaxValue" or "MinValue" }) diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/MultiplicationEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/MultiplicationEnumerateMember.cs index 6961b7fc..2b7db908 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/MultiplicationEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/MultiplicationEnumerateMember.cs @@ -8,7 +8,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class MultiplicationEnumerateMember : OperatorEnumerateMember { - internal MultiplicationEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal MultiplicationEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override SyntaxKind? GetSyntaxKind(IMethodSymbol symbol) => symbol switch diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/ShiftEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/ShiftEnumerateMember.cs index d08279d9..2452b206 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/ShiftEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/ShiftEnumerateMember.cs @@ -5,7 +5,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class ShiftEnumerateMember : OperatorEnumerateMember { - internal ShiftEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal ShiftEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override SyntaxKind? GetSyntaxKind(IMethodSymbol symbol) => symbol switch { diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/SubtractEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/SubtractEnumerateMember.cs index 26f49ceb..8eb71176 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/SubtractEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/SubtractEnumerateMember.cs @@ -5,7 +5,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class SubtractEnumerateMember : OperatorEnumerateMember { - internal SubtractEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal SubtractEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override SyntaxKind? GetSyntaxKind(IMethodSymbol symbol) => symbol switch diff --git a/Source/AtCoderAnalyzer/CreateOperators/Specified/UnaryNumEnumerateMember.cs b/Source/AtCoderAnalyzer/CreateOperators/Specified/UnaryNumEnumerateMember.cs index c722cb2d..17e96939 100644 --- a/Source/AtCoderAnalyzer/CreateOperators/Specified/UnaryNumEnumerateMember.cs +++ b/Source/AtCoderAnalyzer/CreateOperators/Specified/UnaryNumEnumerateMember.cs @@ -7,7 +7,7 @@ namespace AtCoderAnalyzer.CreateOperators.Specified { internal class UnaryNumEnumerateMember : EnumerateMember { - internal UnaryNumEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol) : base(semanticModel, typeSymbol) { } + internal UnaryNumEnumerateMember(SemanticModel semanticModel, ITypeSymbol typeSymbol, AtCoderAnalyzerConfig config) : base(semanticModel, typeSymbol, config) { } protected override MethodDeclarationSyntax CreateMethodSyntax(IMethodSymbol symbol) { diff --git a/Source/AtCoderAnalyzer/Helpers/SyntaxHelpers.cs b/Source/AtCoderAnalyzer/Helpers/SyntaxHelpers.cs index 307e1a1c..e469aa5f 100644 --- a/Source/AtCoderAnalyzer/Helpers/SyntaxHelpers.cs +++ b/Source/AtCoderAnalyzer/Helpers/SyntaxHelpers.cs @@ -35,14 +35,14 @@ public static MemberAccessExpressionSyntax AggressiveInliningMember(string metho => MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ParseExpression(methodImplOptions), IdentifierName("AggressiveInlining")); - public static AttributeSyntax AggressiveInliningAttribute(string methodImplAttribute, string methodImplOptions) + public static AttributeSyntax AggressiveInliningAttribute(string methodImplAttribute, string methodImplOptions, bool useNumeric) => Attribute( ParseName(methodImplAttribute.EndsWith("Attribute") ? methodImplAttribute.Substring(0, methodImplAttribute.Length - "Attribute".Length) : methodImplAttribute) - ).AddArgumentListArguments(AttributeArgument(AggressiveInliningMember(methodImplOptions))); - public static AttributeListSyntax AggressiveInliningAttributeList(string methodImplAttribute, string methodImplOptions) - => AttributeList(SingletonSeparatedList(AggressiveInliningAttribute(methodImplAttribute, methodImplOptions))); + ).AddArgumentListArguments(AttributeArgument( + useNumeric ? LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(256)) : AggressiveInliningMember(methodImplOptions) + )); public static readonly ArrowExpressionClauseSyntax ArrowDefault = ArrowExpressionClause( diff --git a/Test/AtCoderAnalyzer.Test/AggressiveInliningCodeFixProviderTest.cs b/Test/AtCoderAnalyzer.Test/AggressiveInliningCodeFixProviderTest.cs index d2cd507b..8dc059b4 100644 --- a/Test/AtCoderAnalyzer.Test/AggressiveInliningCodeFixProviderTest.cs +++ b/Test/AtCoderAnalyzer.Test/AggressiveInliningCodeFixProviderTest.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Testing; using Xunit; using VerifyCS = AtCoderAnalyzer.Test.CSharpCodeFixVerifier< @@ -467,20 +468,88 @@ public async Task UsingAlias() var source = @" using AtCoder; using System.Runtime.CompilerServices; +using MI = System.Runtime.CompilerServices.MethodImplAttribute; struct Op : ILazySegtreeOperator { public long Identity => 0L; public int FIdentity => 0; - [MethodImpl(256)] public int Composition(int f, int g) => 0; - [MethodImpl(256)] public long Mapping(int f, long x) => 0L; - [MethodImpl(MethodImplOptions.AggressiveInlining)] public long Operate(long x, long y) => 0L; } "; - await VerifyCS.VerifyAnalyzerAsync(source); + var fixedSource = @" +using AtCoder; +using System.Runtime.CompilerServices; +using MI = System.Runtime.CompilerServices.MethodImplAttribute; +struct Op : ILazySegtreeOperator +{ + public long Identity => 0L; + public int FIdentity => 0; + + [MI(MethodImplOptions.AggressiveInlining)] + public int Composition(int f, int g) => 0; + [MI(MethodImplOptions.AggressiveInlining)] + public long Mapping(int f, long x) => 0L; + [MI(MethodImplOptions.AggressiveInlining)] + public long Operate(long x, long y) => 0L; +} +"; + await VerifyCS.VerifyCodeFixAsync(source, + VerifyCS.Diagnostic().WithSpan(5, 1, 12, 2).WithArguments("Composition, Mapping, Operate"), + fixedSource); } + [Fact] + public async Task MethodImpl256() + { + var source = @" +using AtCoder; +using System.Runtime.CompilerServices; +using MI = System.Runtime.CompilerServices.MethodImplAttribute; +struct Op : ILazySegtreeOperator +{ + public long Identity => 0L; + public int FIdentity => 0; + public int Composition(int f, int g) => 0; + public long Mapping(int f, long x) => 0L; + public long Operate(long x, long y) => 0L; +} +"; + var fixedSource = @" +using AtCoder; +using System.Runtime.CompilerServices; +using MI = System.Runtime.CompilerServices.MethodImplAttribute; +struct Op : ILazySegtreeOperator +{ + public long Identity => 0L; + public int FIdentity => 0; + + [MI(256)] + public int Composition(int f, int g) => 0; + [MI(256)] + public long Mapping(int f, long x) => 0L; + [MI(256)] + public long Operate(long x, long y) => 0L; +} +"; + var test = new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + TestState = + { + AnalyzerConfigFiles = + { + ("/.editorconfig", @" +is_global = true +build_property.AtCoderAnalyzer_UseMethodImplNumeric = true +"), + }, + }, + }; + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic().WithSpan(5, 1, 12, 2).WithArguments("Composition, Mapping, Operate")); + await test.RunAsync(CancellationToken.None); + } } } diff --git a/Test/AtCoderAnalyzer.Test/CreateOperatorCodeFixProviderTest.cs b/Test/AtCoderAnalyzer.Test/CreateOperatorCodeFixProviderTest.cs index 95fb41db..fdaee1c6 100644 --- a/Test/AtCoderAnalyzer.Test/CreateOperatorCodeFixProviderTest.cs +++ b/Test/AtCoderAnalyzer.Test/CreateOperatorCodeFixProviderTest.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Xunit; using VerifyCS = AtCoderAnalyzer.Test.CSharpCodeFixVerifier< AtCoderAnalyzer.CreateOperatorAnalyzer, @@ -569,7 +570,6 @@ await VerifyCS.VerifyCodeFixAsync(source, } [Fact] - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public async Task AnyDefinedType() { var source = @" @@ -632,7 +632,6 @@ await VerifyCS.VerifyCodeFixAsync(source, } [Fact] - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public async Task AnyDefinedMethod() { var source = @" @@ -937,6 +936,126 @@ await VerifyCS.VerifyCodeFixAsync(source, VerifyCS.Diagnostic("AC0008").WithSpan(7, 5, 7, 27).WithArguments("OpSeg"), fixedSource); } + + [Fact] + public async Task MethodImplAlias() + { + var source = @"using AtCoder; +using System.Runtime.CompilerServices; +using MI = System.Runtime.CompilerServices.MethodImplAttribute; +class Program +{ + Segtree defined; + Segtree notDefined; +} +struct MinOp : ISegtreeOperator +{ + public int Identity => 0; + + public int Operate(int x, int y) + { + return System.Math.Min(x, y); + } +} +"; + var fixedSource = @"using AtCoder; +using System.Runtime.CompilerServices; +using MI = System.Runtime.CompilerServices.MethodImplAttribute; +class Program +{ + Segtree defined; + Segtree notDefined; +} +struct MinOp : ISegtreeOperator +{ + public int Identity => 0; + + public int Operate(int x, int y) + { + return System.Math.Min(x, y); + } +} + +struct OpSeg : ISegtreeOperator +{ + [MI(MethodImplOptions.AggressiveInlining)] + public long Operate(long x, long y) => default; + + public long Identity => default; +}"; + + var test = new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + }; + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic("AC0008").WithSpan(7, 5, 7, 25).WithArguments("OpSeg")); + await test.RunAsync(CancellationToken.None); + } + + [Fact] + public async Task MethodImpl256() + { + var source = @"using AtCoder; +using System.Runtime.CompilerServices; +class Program +{ + Segtree defined; + Segtree notDefined; +} +struct MinOp : ISegtreeOperator +{ + public int Identity => 0; + + public int Operate(int x, int y) + { + return System.Math.Min(x, y); + } +} +"; + var fixedSource = @"using AtCoder; +using System.Runtime.CompilerServices; +class Program +{ + Segtree defined; + Segtree notDefined; +} +struct MinOp : ISegtreeOperator +{ + public int Identity => 0; + + public int Operate(int x, int y) + { + return System.Math.Min(x, y); + } +} + +struct OpSeg : ISegtreeOperator +{ + [MethodImpl(256)] + public long Operate(long x, long y) => default; + + public long Identity => default; +}"; + + var test = new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + TestState = + { + AnalyzerConfigFiles = + { + ("/.editorconfig", @" +is_global = true +build_property.AtCoderAnalyzer_UseMethodImplNumeric = true +") + }, + }, + }; + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic("AC0008").WithSpan(6, 5, 6, 25).WithArguments("OpSeg")); + await test.RunAsync(CancellationToken.None); + } #endregion Others } }