Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,6 @@ private Diagnostic CreateDiagnostic(Result result, NotificationOption2 notificat
{
// Keep track of the invocation node
var invocation = result.Invocation;
var additionalLocations = ImmutableArray.Create(
invocation.GetLocation());

// Mark the span under the two arguments to .Slice(..., ...) as what we will be
// updating.
Expand All @@ -325,7 +323,7 @@ private Diagnostic CreateDiagnostic(Result result, NotificationOption2 notificat
location,
notificationOption,
analyzerOptions,
additionalLocations,
[invocation.GetLocation()],
ImmutableDictionary<string, string?>.Empty,
result.SliceLikeMethod.Name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,9 @@ private static SyntaxList<MemberDeclarationSyntax> GetMembers(SyntaxNode node)
private static TSyntaxNode RemoveLeadingBlankLinesFromFirstMember<TSyntaxNode>(TSyntaxNode node) where TSyntaxNode : SyntaxNode
{
var members = GetMembers(node);
if (members.Count == 0)
if (members is not [var firstMember, ..])
return node;

var firstMember = members.First();
var firstMemberTrivia = firstMember.GetLeadingTrivia();

// If there is no leading trivia, then return the node as it is.
Expand Down Expand Up @@ -367,10 +366,9 @@ private static IEnumerable<IEnumerable<SyntaxTrivia>> SplitIntoLines(SyntaxTrivi
private static TSyntaxNode EnsureLeadingBlankLineBeforeFirstMember<TSyntaxNode>(TSyntaxNode node) where TSyntaxNode : SyntaxNode
{
var members = GetMembers(node);
if (members.Count == 0)
if (members is not [var firstMember, ..])
return node;

var firstMember = members.First();
var firstMemberTrivia = firstMember.GetLeadingTrivia();

// If the first member already contains a leading new line then, this will already break up the usings from these members.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,15 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities;
/// <summary>
/// Helper code to support analysis of HashCode methods
/// </summary>
internal readonly partial struct HashCodeAnalyzer
internal readonly partial struct HashCodeAnalyzer(
IMethodSymbol objectGetHashCodeMethod,
INamedTypeSymbol? equalityComparerType,
INamedTypeSymbol systemHashCodeType)
{
private readonly Compilation _compilation;
private readonly IMethodSymbol _objectGetHashCodeMethod;
private readonly INamedTypeSymbol? _equalityComparerType;
private readonly IMethodSymbol _objectGetHashCodeMethod = objectGetHashCodeMethod;
private readonly INamedTypeSymbol? _equalityComparerType = equalityComparerType;

public readonly INamedTypeSymbol SystemHashCodeType;

private HashCodeAnalyzer(
Compilation compilation, IMethodSymbol objectGetHashCodeMethod,
INamedTypeSymbol? equalityComparerType, INamedTypeSymbol systemHashCodeType)
{
_compilation = compilation;
_objectGetHashCodeMethod = objectGetHashCodeMethod;
_equalityComparerType = equalityComparerType;
SystemHashCodeType = systemHashCodeType;
}
public readonly INamedTypeSymbol SystemHashCodeType = systemHashCodeType;

public static bool TryGetAnalyzer(Compilation compilation, [NotNullWhen(true)] out HashCodeAnalyzer analyzer)
{
Expand All @@ -47,7 +39,7 @@ public static bool TryGetAnalyzer(Compilation compilation, [NotNullWhen(true)] o
if (systemHashCodeType == null)
return false;

analyzer = new HashCodeAnalyzer(compilation, objectGetHashCodeMethod, equalityComparerType, systemHashCodeType);
analyzer = new HashCodeAnalyzer(objectGetHashCodeMethod, equalityComparerType, systemHashCodeType);
return true;
}

Expand Down Expand Up @@ -129,31 +121,19 @@ public static bool TryGetAnalyzer(Compilation compilation, [NotNullWhen(true)] o

// First statement has to be the declaration of the accumulator.
// Last statement has to be the return of it.
if (statements.First() is not IVariableDeclarationGroupOperation varDeclStatement ||
!(statements.Last() is IReturnOperation { ReturnedValue: { } returnedValue }))
{
if (statements is not [IVariableDeclarationGroupOperation varDeclStatement, .., IReturnOperation { ReturnedValue: { } returnedValue }])
return null;
}

var variables = varDeclStatement.GetDeclaredVariables();
if (variables.Length != 1 ||
varDeclStatement.Declarations.Length != 1)
{
if (variables.Length != 1)
return null;
}

var declaration = varDeclStatement.Declarations[0];
if (declaration.Declarators.Length != 1)
{
if (varDeclStatement.Declarations is not [{ Declarators: [var declarator] } declaration])
return null;
}

var declarator = declaration.Declarators[0];
var initializerValue = declaration.Initializer?.Value ?? declarator.Initializer?.Value;
if (initializerValue == null)
{
return null;
}

var hashCodeVariable = declarator.Symbol;
if (!(IsLocalReference(returnedValue, hashCodeVariable)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args
var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

var intersectionSpans = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);
if (intersectionSpans.Count == 0)
if (intersectionSpans is not ([var firstSpan, ..] and [.., var lastSpan]))
{
// In Razor we sometimes get formatting changes during inline rename that
// do not intersect with any of our spans. Ideally this shouldn't happen at
Expand All @@ -243,7 +243,7 @@ private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args
// spans, but they should still all map to a single tracked rename span (e.g.
// renaming "two" to "one two three" may be interpreted as two distinct
// additions of "one" and "three").
var boundingIntersectionSpan = Span.FromBounds(intersectionSpans.First().Start, intersectionSpans.Last().End);
var boundingIntersectionSpan = Span.FromBounds(firstSpan.Start, lastSpan.End);
var trackingSpansTouched = GetEditableSpansForSnapshot(args.After).Where(ss => ss.IntersectsWith(boundingIntersectionSpan));
Debug.Assert(trackingSpansTouched.Count() == 1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ private ValueTask ProcessTagsChangedAsync(

foreach (var collection in snapshotSpans)
{
if (collection.Count == 0)
if (collection is not ([var firstSpan, ..] and [.., var lastSpan]))
continue;

var snapshot = collection.First().Snapshot;
var snapshot = firstSpan.Snapshot;

// Coalesce the spans if there are a lot of them.
var coalesced = collection.Count > CoalesceDifferenceCount
? new NormalizedSnapshotSpanCollection(snapshot.GetSpanFromBounds(collection.First().Start, collection.Last().End))
? new NormalizedSnapshotSpanCollection(snapshot.GetSpanFromBounds(firstSpan.Start, lastSpan.End))
: collection;

_dataSource.BeforeTagsChanged(snapshot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,11 @@ protected override bool CancelOnNewWork
// that, determine the start/end line for the buffer that is in view.
var visibleSpan = textView.TextViewLines.FormattedSpan;
var visibleSpansInBuffer = textView.BufferGraph.MapDownToBuffer(visibleSpan, SpanTrackingMode.EdgeInclusive, subjectBuffer);
if (visibleSpansInBuffer.Count == 0)
if (visibleSpansInBuffer is not ([var firstVisibleSpan, ..] and [.., var lastVisibleSpan]))
return null;

var visibleStart = visibleSpansInBuffer.First().Start;
var visibleEnd = visibleSpansInBuffer.Last().End;

var visibleStart = firstVisibleSpan.Start;
var visibleEnd = lastVisibleSpan.End;
var snapshot = subjectBuffer.CurrentSnapshot;
var startLine = visibleStart.GetContainingLineNumber();
var endLine = visibleEnd.GetContainingLineNumber();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,20 @@ namespace Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch;

internal sealed partial class CSharpConvertIfToSwitchCodeRefactoringProvider
{
private static readonly Dictionary<BinaryOperatorKind, SyntaxKind> s_operatorMap = new Dictionary<BinaryOperatorKind, SyntaxKind>
private static readonly Dictionary<BinaryOperatorKind, SyntaxKind> s_operatorMap = new()
{
{ BinaryOperatorKind.LessThan, SyntaxKind.LessThanToken },
{ BinaryOperatorKind.GreaterThan, SyntaxKind.GreaterThanToken },
{ BinaryOperatorKind.LessThanOrEqual, SyntaxKind.LessThanEqualsToken },
{ BinaryOperatorKind.GreaterThanOrEqual, SyntaxKind.GreaterThanEqualsToken },
};

public override SyntaxNode CreateSwitchExpressionStatement(SyntaxNode target, ImmutableArray<AnalyzedSwitchSection> sections, Feature feature)
{
return ReturnStatement(
public override SyntaxNode CreateSwitchExpressionStatement(
ExpressionSyntax target, ImmutableArray<AnalyzedSwitchSection> sections, Feature feature)
=> ReturnStatement(
SwitchExpression(
(ExpressionSyntax)target,
target,
[.. sections.Select(section => AsSwitchExpressionArmSyntax(section, feature))]));
}

private static SwitchExpressionArmSyntax AsSwitchExpressionArmSyntax(AnalyzedSwitchSection section, Feature feature)
{
Expand All @@ -59,23 +58,24 @@ private static SwitchExpressionArmSyntax AsSwitchExpressionArmSyntax(AnalyzedSwi
private static ExpressionSyntax AsExpressionSyntax(IOperation operation)
=> operation switch
{
IReturnOperation { ReturnedValue: { } value } => (ExpressionSyntax)value.Syntax,
IThrowOperation { Exception: { } exception } => ThrowExpression((ExpressionSyntax)exception.Syntax),
IBlockOperation op => AsExpressionSyntax(op.Operations.Single()),
IReturnOperation { ReturnedValue.Syntax: ExpressionSyntax value } => value,
IThrowOperation { Exception.Syntax: ExpressionSyntax exception } => ThrowExpression(exception),
IBlockOperation { Operations: [var op] } => AsExpressionSyntax(op),
var v => throw ExceptionUtilities.UnexpectedValue(v.Kind)
};

public override SyntaxNode CreateSwitchStatement(IfStatementSyntax ifStatement, SyntaxNode expression, IEnumerable<SyntaxNode> sectionList)
public override SyntaxNode CreateSwitchStatement(
IfStatementSyntax ifStatement, ExpressionSyntax expression, IEnumerable<SyntaxNode> sectionList)
{
var block = ifStatement.Statement as BlockSyntax;
return SwitchStatement(
switchKeyword: SwitchKeyword.WithTriviaFrom(ifStatement.IfKeyword),
openParenToken: ifStatement.OpenParenToken,
expression: (ExpressionSyntax)expression,
closeParenToken: ifStatement.CloseParenToken.WithPrependedLeadingTrivia(ElasticMarker),
openBraceToken: block?.OpenBraceToken ?? OpenBraceToken,
sections: [.. sectionList.Cast<SwitchSectionSyntax>()],
closeBraceToken: block?.CloseBraceToken.WithoutLeadingTrivia() ?? CloseBraceToken);
SwitchKeyword.WithTriviaFrom(ifStatement.IfKeyword),
ifStatement.OpenParenToken,
expression,
ifStatement.CloseParenToken.WithPrependedLeadingTrivia(ElasticMarker),
block?.OpenBraceToken ?? OpenBraceToken,
[.. sectionList.Cast<SwitchSectionSyntax>()],
block?.CloseBraceToken.WithoutLeadingTrivia() ?? CloseBraceToken);
}

private static WhenClauseSyntax? AsWhenClause(AnalyzedSwitchLabel label)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Collections;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
Expand Down Expand Up @@ -2678,14 +2677,14 @@ protected override TextSpan GetExceptionHandlingRegion(SyntaxNode node, out bool
tryStatement = (TryStatementSyntax)node;
coversAllChildren = false;

if (tryStatement.Catches.Count == 0)
if (tryStatement.Catches is not [var firstCatch, ..])
{
RoslynDebug.Assert(tryStatement.Finally != null);
return tryStatement.Finally.Span;
}

return TextSpan.FromBounds(
tryStatement.Catches.First().SpanStart,
firstCatch.SpanStart,
(tryStatement.Finally != null)
? tryStatement.Finally.Span.End
: tryStatement.Catches.Last().Span.End);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ protected override async ValueTask<bool> PrefersThrowExpressionAsync(Document do
return GetAccessedMemberName(arrowExpression.Expression);

// { return this.name; }
if (body is BlockSyntax { Statements.Count: > 0 } block)
return GetAccessedMemberName(block.Statements.First());
if (body is BlockSyntax { Statements: [var firstStatement, ..] })
return GetAccessedMemberName(firstStatement);

return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ internal abstract class Analyzer(ISyntaxFacts syntaxFacts, AbstractConvertIfToSw
/// <remarks>
/// Note that this is initially unset until we find a non-constant expression.
/// </remarks>
private SyntaxNode _switchTargetExpression = null!;
private TExpressionSyntax _switchTargetExpression = null!;

/// <summary>
/// Holds the type of the <see cref="_switchTargetExpression"/>
/// </summary>
Expand All @@ -68,7 +69,7 @@ internal abstract class Analyzer(ISyntaxFacts syntaxFacts, AbstractConvertIfToSw
public bool Supports(Feature feature)
=> (Features & feature) != 0;

public (ImmutableArray<AnalyzedSwitchSection>, SyntaxNode TargetExpression) AnalyzeIfStatementSequence(ReadOnlySpan<IOperation> operations)
public (ImmutableArray<AnalyzedSwitchSection>, TExpressionSyntax TargetExpression) AnalyzeIfStatementSequence(ReadOnlySpan<IOperation> operations)
{
using var _ = ArrayBuilder<AnalyzedSwitchSection>.GetInstance(out var sections);
if (!ParseIfStatementSequence(operations, sections, topLevel: true, out var defaultBodyOpt))
Expand Down Expand Up @@ -450,7 +451,9 @@ private bool CheckTargetExpression(IOperation operation)
{
operation = operation.WalkDownConversion();

var expression = operation.Syntax;
if (operation.Syntax is not TExpressionSyntax expression)
return false;

// If we have not figured the switch expression yet,
// we will assume that the first expression is the one.
if (_switchTargetExpression is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ namespace Microsoft.CodeAnalysis.ConvertIfToSwitch;
internal abstract partial class AbstractConvertIfToSwitchCodeRefactoringProvider<
TIfStatementSyntax, TExpressionSyntax, TIsExpressionSyntax, TPatternSyntax>
{
public abstract SyntaxNode CreateSwitchExpressionStatement(SyntaxNode target, ImmutableArray<AnalyzedSwitchSection> sections, Feature feature);
public abstract SyntaxNode CreateSwitchStatement(TIfStatementSyntax ifStatement, SyntaxNode target, IEnumerable<SyntaxNode> sectionList);
public abstract SyntaxNode CreateSwitchExpressionStatement(TExpressionSyntax target, ImmutableArray<AnalyzedSwitchSection> sections, Feature feature);
public abstract SyntaxNode CreateSwitchStatement(TIfStatementSyntax ifStatement, TExpressionSyntax target, IEnumerable<SyntaxNode> sectionList);
public abstract IEnumerable<SyntaxNode> AsSwitchSectionStatements(IOperation operation);
public abstract SyntaxNode AsSwitchLabelSyntax(AnalyzedSwitchLabel label, Feature feature);
protected abstract SyntaxTriviaList GetLeadingTriviaToTransfer(SyntaxNode syntaxToRemove);

private async Task<Document> UpdateDocumentAsync(
Document document,
SyntaxNode target,
TExpressionSyntax target,
TIfStatementSyntax ifStatement,
ImmutableArray<AnalyzedSwitchSection> sections,
Feature feature,
Expand All @@ -46,8 +46,7 @@ private async Task<Document> UpdateDocumentAsync(
@switch = @switch
.WithLeadingTrivia(ifStatement.GetLeadingTrivia())
.WithTrailingTrivia(lastNode.GetTrailingTrivia())
.WithAdditionalAnnotations(Formatter.Annotation)
.WithAdditionalAnnotations(Simplifier.Annotation);
.WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);

var nodesToRemove = sections.Skip(1).Select(s => s.SyntaxToRemove).Where(s => s.Parent == ifStatement.Parent);
root = root.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex
var ifStatement = await context.TryGetRelevantNodeAsync<TIfStatementSyntax>().ConfigureAwait(false);
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var syntaxFactsService = document.GetRequiredLanguageService<ISyntaxFactsService>();
if (!ShouldOfferRefactoring(ifStatement, semanticModel, syntaxFactsService, out var analyzer, out var sections, out var target))
if (!ShouldOfferRefactoring(
ifStatement, semanticModel, syntaxFactsService,
out var analyzer, out var sections, out var target))
{
return;
}
Expand Down Expand Up @@ -72,7 +74,7 @@ private bool ShouldOfferRefactoring(
ISyntaxFactsService syntaxFactsService,
[NotNullWhen(true)] out Analyzer? analyzer,
[NotNullWhen(true)] out ImmutableArray<AnalyzedSwitchSection> sections,
[NotNullWhen(true)] out SyntaxNode? target)
[NotNullWhen(true)] out TExpressionSyntax? target)
{
analyzer = null;
sections = default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertIfToSwitch
{BinaryOperatorKind.GreaterThanOrEqual, (SyntaxKind.CaseGreaterThanOrEqualClause, SyntaxKind.GreaterThanEqualsToken)}
}

Public Overrides Function CreateSwitchExpressionStatement(target As SyntaxNode, sections As ImmutableArray(Of AnalyzedSwitchSection), feature As Feature) As SyntaxNode
Public Overrides Function CreateSwitchExpressionStatement(target As ExpressionSyntax, sections As ImmutableArray(Of AnalyzedSwitchSection), feature As Feature) As SyntaxNode
Throw ExceptionUtilities.Unreachable
End Function

Public Overrides Function CreateSwitchStatement(ifStatement As ExecutableStatementSyntax, expression As SyntaxNode, sectionList As IEnumerable(Of SyntaxNode)) As SyntaxNode
Public Overrides Function CreateSwitchStatement(ifStatement As ExecutableStatementSyntax, expression As ExpressionSyntax, sectionList As IEnumerable(Of SyntaxNode)) As SyntaxNode
Return VisualBasicSyntaxGenerator.Instance.SwitchStatement(expression, sectionList)
End Function

Expand Down
Loading
Loading