Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix enum contained flags check for partial matches in [RCS1258](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1258) ([PR](https://github.com/dotnet/roslynator/pull/1740) by @ovska)
- Fix analyzer [RCS1146](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1146) ([PR](https://github.com/dotnet/roslynator/pull/1747))
- Fix analyzer [RCS1194](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1194) ([PR](https://github.com/dotnet/roslynator/pull/1733))
- Fix analyzer [RCS1246](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1246) for conditional access expressions ([PR](https://github.com/dotnet/roslynator/pull/XXXX))
Comment thread
krajek marked this conversation as resolved.
Outdated

## [4.15.0] - 2025-12-14

Expand Down
6 changes: 6 additions & 0 deletions src/Common/CSharp/Analysis/UseElementAccessAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public static bool IsFixableElementAt(
if (!HasAccessibleIndexer(typeSymbol, reducedExtensionMethodInfo.ReducedSymbolOrSymbol.ReturnType, semanticModel, invocationExpression.SpanStart))
return false;

// Skip the speculative binding check for member binding expressions (conditional access context)
// because GetSpeculativeSymbolInfo cannot bind a MemberBindingExpression as a standalone expression.
// The infinite recursion scenario this check guards against is not applicable in conditional access.
if (invocationInfo.Expression.IsKind(SyntaxKind.MemberBindingExpression))
return true;

Comment thread
krajek marked this conversation as resolved.
Outdated
ElementAccessExpressionSyntax elementAccess = SyntaxFactory.ElementAccessExpression(
invocationInfo.Expression,
CSharpFactory.BracketedArgumentList(invocationInfo.Arguments[0]));
Expand Down
102 changes: 102 additions & 0 deletions src/Tests/Analyzers.Tests/RCS1246UseElementAccessTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,108 @@ void M()
KeyValuePair<string, string> elementAt = dic.ElementAt(1);
}
}
");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseElementAccess)]
public async Task Test_UseElementAccessInsteadOfElementAt_ConditionalAccess()
{
await VerifyDiagnosticAndFixAsync(@"
using System.Collections.Generic;
using System.Linq;

class C
{
void M()
{
var x = new C();
var y = x?.Values.[|ElementAt(0)|];
}

public IReadOnlyList<int> Values => new List<int>();
}
", @"
using System.Collections.Generic;
using System.Linq;

class C
{
void M()
{
var x = new C();
var y = x?.Values[0];
}

public IReadOnlyList<int> Values => new List<int>();
}
");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseElementAccess)]
public async Task Test_UseElementAccessInsteadOfFirst_ConditionalAccess()
{
await VerifyDiagnosticAndFixAsync(@"
using System.Collections.Generic;
using System.Linq;

class C
{
void M()
{
var x = new C();
var y = x?.Values.[|First()|];
}

public IReadOnlyList<int> Values => new List<int>();
}
", @"
using System.Collections.Generic;
using System.Linq;

class C
{
void M()
{
var x = new C();
var y = x?.Values[0];
}

public IReadOnlyList<int> Values => new List<int>();
}
");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseElementAccess)]
public async Task Test_UseElementAccessInsteadOfLast_ConditionalAccess()
{
await VerifyDiagnosticAndFixAsync(@"
using System.Collections.Generic;
using System.Linq;

class C
{
void M()
{
var x = new C();
var y = x?.Values.[|Last()|];
}

public IReadOnlyList<int> Values => new List<int>();
}
", @"
using System.Collections.Generic;
using System.Linq;

class C
{
void M()
{
var x = new C();
var y = x?.Values[^1];
}

public IReadOnlyList<int> Values => new List<int>();
}
");
}
}
Loading