提交 1ef362f0 编写于 作者: A Alireza Habibi

Simplify code

上级 53d22f27
......@@ -15,63 +15,53 @@ namespace Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
/// </summary>
internal abstract class AnalyzedPattern
{
private AnalyzedPattern()
{
}
/// <summary>
/// Base class for patterns that target a specific expression, i.e. non-combinators
/// </summary>
internal abstract class Test : AnalyzedPattern
{
public readonly IOperation TargetOperation;
public readonly ExpressionSyntax TargetExpression;
protected Test(IOperation targetOperation)
=> TargetOperation = targetOperation;
}
private AnalyzedPattern(ExpressionSyntax target)
=> TargetExpression = target;
/// <summary>
/// Represents a type-pattern, constructed from is-expression
/// </summary>
internal sealed class Type : Test
internal sealed class Type : AnalyzedPattern
{
public readonly TypeSyntax TypeSyntax;
public Type(TypeSyntax expression, IOperation target) : base(target)
public Type(TypeSyntax expression, ExpressionSyntax target) : base(target)
=> TypeSyntax = expression;
}
/// <summary>
/// Represents a source-pattern, constructed from C# patterns
/// </summary>
internal sealed class Source : Test
internal sealed class Source : AnalyzedPattern
{
public readonly PatternSyntax PatternSyntax;
public Source(PatternSyntax patternSyntax, IOperation target) : base(target)
public Source(PatternSyntax patternSyntax, ExpressionSyntax target) : base(target)
=> PatternSyntax = patternSyntax;
}
/// <summary>
/// Represents a constant-pattern, constructed from an equality check
/// </summary>
internal sealed class Constant : Test
internal sealed class Constant : AnalyzedPattern
{
public readonly ExpressionSyntax ExpressionSyntax;
public Constant(ExpressionSyntax expression, IOperation target) : base(target)
public Constant(ExpressionSyntax expression, ExpressionSyntax target) : base(target)
=> ExpressionSyntax = expression;
}
/// <summary>
/// Represents a relational-pattern, constructed from relational operators
/// </summary>
internal sealed class Relational : Test
internal sealed class Relational : AnalyzedPattern
{
public readonly BinaryOperatorKind OperatorKind;
public readonly ExpressionSyntax Value;
public Relational(BinaryOperatorKind operatorKind, ExpressionSyntax value, IOperation target) : base(target)
public Relational(BinaryOperatorKind operatorKind, ExpressionSyntax value, ExpressionSyntax target) : base(target)
{
OperatorKind = operatorKind;
Value = value;
......@@ -88,7 +78,7 @@ internal sealed class Binary : AnalyzedPattern
public readonly bool IsDisjunctive;
public readonly SyntaxToken Token;
private Binary(AnalyzedPattern leftPattern, AnalyzedPattern rightPattern, bool isDisjunctive, SyntaxToken token)
private Binary(AnalyzedPattern leftPattern, AnalyzedPattern rightPattern, bool isDisjunctive, SyntaxToken token, ExpressionSyntax target) : base(target)
{
Left = leftPattern;
Right = rightPattern;
......@@ -96,11 +86,15 @@ private Binary(AnalyzedPattern leftPattern, AnalyzedPattern rightPattern, bool i
Token = token;
}
public static AnalyzedPattern Create(AnalyzedPattern leftPattern, AnalyzedPattern rightPattern, bool isDisjunctive, SyntaxToken token)
public static AnalyzedPattern? Create(AnalyzedPattern leftPattern, AnalyzedPattern rightPattern, bool isDisjunctive, SyntaxToken token)
{
var target = leftPattern.TargetExpression;
if (!SyntaxFactory.AreEquivalent(target, rightPattern.TargetExpression))
return null;
return !isDisjunctive && (leftPattern, rightPattern) is (Not left, Not right)
? Not.Create(new Binary(left.Pattern, right.Pattern, isDisjunctive: true, token))
: new Binary(leftPattern, rightPattern, isDisjunctive, token);
? Not.Create(new Binary(left.Pattern, right.Pattern, isDisjunctive: true, token, target))
: new Binary(leftPattern, rightPattern, isDisjunctive, token, target);
}
}
......@@ -111,7 +105,7 @@ internal sealed class Not : AnalyzedPattern
{
public readonly AnalyzedPattern Pattern;
private Not(AnalyzedPattern pattern)
private Not(AnalyzedPattern pattern, ExpressionSyntax target) : base(target)
=> Pattern = pattern;
private static BinaryOperatorKind Negate(BinaryOperatorKind kind)
......@@ -124,12 +118,13 @@ private static BinaryOperatorKind Negate(BinaryOperatorKind kind)
var v => throw ExceptionUtilities.UnexpectedValue(v)
};
public static AnalyzedPattern Create(AnalyzedPattern pattern)
public static AnalyzedPattern? Create(AnalyzedPattern? pattern)
=> pattern switch
{
null => null,
Not p => p.Pattern,
Relational p => new Relational(Negate(p.OperatorKind), p.Value, p.TargetOperation),
_ => new Not(pattern)
Relational p => new Relational(Negate(p.OperatorKind), p.Value, p.TargetExpression),
_ => new Not(pattern, pattern.TargetExpression)
};
}
}
......
......@@ -4,7 +4,6 @@
#nullable enable
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Operations;
using Roslyn.Utilities;
......@@ -16,14 +15,9 @@ namespace Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
internal static class CSharpUsePatternCombinatorsAnalyzer
{
public static bool Analyze(IOperation operation,
[NotNullWhen(true)] out AnalyzedPattern? pattern,
[NotNullWhen(true)] out ExpressionSyntax? target)
public static AnalyzedPattern? Analyze(IOperation operation)
{
if ((pattern = ParsePattern(operation)) != null)
return TryGetTargetExpression(pattern, out target);
target = null;
return false;
return ParsePattern(operation);
}
private enum ConstantResult
......@@ -52,12 +46,7 @@ private enum ConstantResult
return ParseConstantPattern(op);
case IBinaryOperation { OperatorKind: NotEquals } op:
{
var pattern = ParseConstantPattern(op);
if (pattern == null)
break;
return Not.Create(pattern);
}
return Not.Create(ParseConstantPattern(op));
case IBinaryOperation { OperatorKind: ConditionalOr, Syntax: BinaryExpressionSyntax syntax } op:
return ParseBinaryPattern(op, isDisjunctive: true, syntax.OperatorToken);
......@@ -69,18 +58,13 @@ private enum ConstantResult
return ParseRelationalPattern(op);
case IUnaryOperation { OperatorKind: UnaryOperatorKind.Not } op:
{
var pattern = ParsePattern(op.Operand);
if (pattern == null)
break;
return Not.Create(pattern);
}
return Not.Create(ParsePattern(op.Operand));
case IIsTypeOperation { Syntax: BinaryExpressionSyntax { Right: TypeSyntax type } } op:
return new Type(type, op.ValueOperand);
return new Type(type, GetTargetExpression(op.ValueOperand));
case IIsPatternOperation { Pattern: { Syntax: PatternSyntax pattern } } op:
return new Source(pattern, op.Value);
return new Source(pattern, GetTargetExpression(op.Value));
case IParenthesizedOperation op:
return ParsePattern(op.Operand);
......@@ -117,9 +101,9 @@ private static ConstantResult DetermineConstant(IBinaryOperation op)
return DetermineConstant(op) switch
{
ConstantResult.Left when op.LeftOperand.Syntax is ExpressionSyntax left
=> new Relational(Flip(op.OperatorKind), left, op.RightOperand),
=> new Relational(Flip(op.OperatorKind), left, GetTargetExpression(op.RightOperand)),
ConstantResult.Right when op.RightOperand.Syntax is ExpressionSyntax right
=> new Relational(op.OperatorKind, right, op.LeftOperand),
=> new Relational(op.OperatorKind, right, GetTargetExpression(op.LeftOperand)),
_ => null
};
}
......@@ -129,9 +113,9 @@ private static ConstantResult DetermineConstant(IBinaryOperation op)
return DetermineConstant(op) switch
{
ConstantResult.Left when op.LeftOperand.Syntax is ExpressionSyntax left
=> new Constant(left, op.RightOperand),
=> new Constant(left, GetTargetExpression(op.RightOperand)),
ConstantResult.Right when op.RightOperand.Syntax is ExpressionSyntax right
=> new Constant(right, op.LeftOperand),
=> new Constant(right, GetTargetExpression(op.LeftOperand)),
_ => null
};
}
......@@ -177,47 +161,14 @@ private static bool IsConstant(IOperation operation)
: operation.ConstantValue.HasValue;
}
private static bool TryGetTargetExpression(AnalyzedPattern pattern, [NotNullWhen(true)] out ExpressionSyntax? target)
private static ExpressionSyntax GetTargetExpression(IOperation operation)
{
target = null;
#pragma warning disable CS8762 // Parameter must have a non-null value when exiting in some condition.
return CheckTargetExpressions(pattern, ref target);
#pragma warning restore CS8762 // Parameter must have a non-null value when exiting in some condition.
// Unwrap explicit casts because the pattern will emit those anyways.
// For instance, `(int)o == 123` would be the same as `o is 123`.
if (operation is IConversionOperation { IsImplicit: false } op)
operation = op.Operand;
static bool CheckTargetExpressions(AnalyzedPattern pattern, ref ExpressionSyntax? target)
{
return pattern switch
{
Test p => CheckTargetExpression(p.TargetOperation, ref target),
Binary p => CheckTargetExpressions(p.Left, ref target) &&
CheckTargetExpressions(p.Right, ref target),
Not p => CheckTargetExpressions(p.Pattern, ref target),
var p => throw ExceptionUtilities.UnexpectedValue(p)
};
}
static bool CheckTargetExpression(IOperation operation, ref ExpressionSyntax? target)
{
var expr = GetTargetExpression(operation);
if (expr is null)
return false;
if (target != null)
return SyntaxFactory.AreEquivalent(expr, target);
target = expr;
return true;
}
static ExpressionSyntax? GetTargetExpression(IOperation operation)
{
// Unwrap explicit casts because the pattern will emit those anyways.
// For instance, `(int)o == 123` would be the same as `o is 123`.
if (operation is IConversionOperation { IsImplicit: false } op)
operation = op.Operand;
return operation.Syntax as ExpressionSyntax;
}
return (ExpressionSyntax)operation.Syntax;
}
}
}
......
......@@ -7,7 +7,6 @@
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
......@@ -72,10 +71,10 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var expression = editor.OriginalRoot.FindNode(location.SourceSpan, getInnermostNodeForTie: true);
var operation = semanticModel.GetOperation(expression, cancellationToken);
RoslynDebug.AssertNotNull(operation);
if (!CSharpUsePatternCombinatorsAnalyzer.Analyze(operation, out var pattern, out var target))
Debug.Fail("Analysis was expected to succeed.");
var pattern = CSharpUsePatternCombinatorsAnalyzer.Analyze(operation);
RoslynDebug.AssertNotNull(pattern);
var patternSyntax = AsPatternSyntax(pattern).WithAdditionalAnnotations(Formatter.Annotation);
editor.ReplaceNode(expression, IsPatternExpression(target, patternSyntax));
editor.ReplaceNode(expression, IsPatternExpression(pattern.TargetExpression, patternSyntax));
}
}
......
......@@ -77,7 +77,8 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
if (operation is null)
return;
if (!CSharpUsePatternCombinatorsAnalyzer.Analyze(operation, out var pattern, target: out _))
var pattern = CSharpUsePatternCombinatorsAnalyzer.Analyze(operation);
if (pattern is null)
return;
if (IsTrivial(pattern))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册