-
-
Notifications
You must be signed in to change notification settings - Fork 21
❇️ Add rcs1200 analyzer #121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
vdebellabre
merged 3 commits into
green-code-initiative:main
from
QzLP2P:feat/rcs1200/orderbyAndThenBy
May 20, 2026
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -486,3 +486,6 @@ $RECYCLE.BIN/ | |
|
|
||
| **/Container | ||
| **/Publish | ||
|
|
||
| # Claude Code local configuration | ||
| .claude/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
src/Creedengo.Core/Analyzers/GCI98.UseThenByInsteadOfOrderBy.Fixer.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| namespace Creedengo.Core.Analyzers; | ||
|
|
||
| /// <summary>GCI98 fixer: Use 'ThenBy' instead of 'OrderBy'.</summary> | ||
| [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseThenByInsteadOfOrderByFixer)), Shared] | ||
| public sealed class UseThenByInsteadOfOrderByFixer : CodeFixProvider | ||
| { | ||
| /// <inheritdoc/> | ||
| public override ImmutableArray<string> FixableDiagnosticIds => _fixableDiagnosticIds; | ||
| private static readonly ImmutableArray<string> _fixableDiagnosticIds = | ||
| ImmutableArray.Create(UseThenByInsteadOfOrderBy.Descriptor.Id); | ||
|
|
||
| /// <inheritdoc/> | ||
| public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; | ||
|
|
||
| /// <inheritdoc/> | ||
| public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||
| { | ||
| if (await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false) is not { } root) | ||
| return; | ||
|
|
||
| foreach (var diagnostic in context.Diagnostics) | ||
| { | ||
| if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not SimpleNameSyntax nameSyntax) | ||
| continue; | ||
| if (nameSyntax.Parent is not MemberAccessExpressionSyntax memberAccess) | ||
| continue; | ||
|
|
||
| context.RegisterCodeFix( | ||
| CodeAction.Create( | ||
| title: "Use 'ThenBy' instead of 'OrderBy'", | ||
| createChangedDocument: _ => FixAsync(context.Document, memberAccess, nameSyntax), | ||
| equivalenceKey: "UseThenByInsteadOfOrderBy"), | ||
| diagnostic); | ||
| } | ||
| } | ||
|
|
||
| private static Task<Document> FixAsync( | ||
| Document document, | ||
| MemberAccessExpressionSyntax memberAccess, | ||
| SimpleNameSyntax nameSyntax) | ||
| { | ||
| var newIdentifier = nameSyntax.Identifier.Text == "OrderBy" ? "ThenBy" : "ThenByDescending"; | ||
| SimpleNameSyntax newNameSyntax = nameSyntax is GenericNameSyntax generic | ||
| ? generic.WithIdentifier(SyntaxFactory.Identifier(newIdentifier)) | ||
| : SyntaxFactory.IdentifierName(newIdentifier); | ||
| var newMemberAccess = memberAccess.WithName(newNameSyntax.WithTriviaFrom(nameSyntax)); | ||
| return document.WithUpdatedRoot(memberAccess, newMemberAccess); | ||
| } | ||
| } | ||
51 changes: 51 additions & 0 deletions
51
src/Creedengo.Core/Analyzers/GCI98.UseThenByInsteadOfOrderBy.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| namespace Creedengo.Core.Analyzers; | ||
|
|
||
| /// <summary>GCI98: Use 'ThenBy' instead of 'OrderBy' in a LINQ sort chain.</summary> | ||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
| public sealed class UseThenByInsteadOfOrderBy : DiagnosticAnalyzer | ||
| { | ||
| private static readonly ImmutableArray<SyntaxKind> InvocationExpressions = | ||
| ImmutableArray.Create(SyntaxKind.InvocationExpression); | ||
|
|
||
| /// <summary>The diagnostic descriptor.</summary> | ||
| public static DiagnosticDescriptor Descriptor { get; } = Rule.CreateDescriptor( | ||
| id: Rule.Ids.GCI98_UseThenByInsteadOfOrderBy, | ||
| title: "Use 'ThenBy' instead of 'OrderBy'", | ||
| message: "Call 'ThenBy' or 'ThenByDescending' instead of 'OrderBy' or 'OrderByDescending' to preserve the primary sort order", | ||
| category: Rule.Categories.Usage, | ||
| severity: DiagnosticSeverity.Warning, | ||
| description: "Chaining 'OrderBy' or 'OrderByDescending' after another sort operation discards all previous sort keys. Use 'ThenBy' or 'ThenByDescending' to add a secondary sort key while preserving the primary sort."); | ||
|
|
||
| /// <inheritdoc/> | ||
| public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => _supportedDiagnostics; | ||
| private static readonly ImmutableArray<DiagnosticDescriptor> _supportedDiagnostics = | ||
| ImmutableArray.Create(Descriptor); | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void Initialize(AnalysisContext context) | ||
| { | ||
| context.EnableConcurrentExecution(); | ||
| context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
| context.RegisterSyntaxNodeAction(static context => AnalyzeNode(context), InvocationExpressions); | ||
| } | ||
|
|
||
| private static void AnalyzeNode(SyntaxNodeAnalysisContext context) | ||
| { | ||
| var invocation = (InvocationExpressionSyntax)context.Node; | ||
|
|
||
| if (invocation.Expression is not MemberAccessExpressionSyntax | ||
| { Name.Identifier.Text: "OrderBy" or "OrderByDescending" } memberAccess) | ||
| return; | ||
|
|
||
| if (memberAccess.Expression is not InvocationExpressionSyntax | ||
| { | ||
| Expression: MemberAccessExpressionSyntax | ||
| { | ||
| Name.Identifier.Text: "OrderBy" or "OrderByDescending" or "ThenBy" or "ThenByDescending" | ||
| } | ||
| }) | ||
| return; | ||
|
|
||
| context.ReportDiagnostic(Diagnostic.Create(Descriptor, memberAccess.Name.GetLocation())); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net10.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
|
vdebellabre marked this conversation as resolved.
|
||
| <TreatWarningsAsErrors>false</TreatWarningsAsErrors> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\Creedengo.Core\Creedengo.Core.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> | ||
| </ItemGroup> | ||
| </Project> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Console.WriteLine("Write your own class sandbox"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| namespace Creedengo.Sandbox; | ||
|
|
||
| internal class RCS1200Sandbox | ||
| { | ||
| public static void Sort() | ||
| { | ||
|
|
||
| var items = new (int a, int b)[] { | ||
| (1, 2), | ||
| (3, 4), | ||
| (5, 6) | ||
| }; | ||
|
|
||
| var sorted = items.OrderBy(item => item.Item1) | ||
| .OrderBy(item => item.Item2); | ||
|
|
||
| } | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.