Skip to content

Commit

Permalink
Add analyzer RCS0062, put expression body on its own line (dotnet#1575)
Browse files Browse the repository at this point in the history
  • Loading branch information
cbersch committed Dec 9, 2024
1 parent 96dfb34 commit 0cea640
Show file tree
Hide file tree
Showing 7 changed files with 400 additions and 3 deletions.
19 changes: 18 additions & 1 deletion src/Analyzers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1629,6 +1629,23 @@ public class C
</Sample>
</Samples>
</Analyzer>
<Analyzer>
<Id>RCS0062</Id>
<Identifier>PutExpressionBodyOnItsOwnLine</Identifier>
<Title>Put expression body on its own line</Title>
<DefaultSeverity>Info</DefaultSeverity>
<IsEnabledByDefault>false</IsEnabledByDefault>
<Samples>
<Sample>
<Before><![CDATA[object Foo() => null;]]></Before>
<After><![CDATA[object Foo()
=> null;]]></After>
</Sample>
</Samples>
<ConfigOptions>
<Option Key="arrow_token_new_line" IsRequired="false" />
</ConfigOptions>
</Analyzer>
<Analyzer>
<Id>RCS1001</Id>
<Identifier>AddBracesWhenExpressionSpansOverMultipleLines</Identifier>
Expand Down Expand Up @@ -7973,4 +7990,4 @@ class FooCodeFixProvider : CodeFixProvider
</Sample>
</Samples>
</Analyzer>
</Analyzers>
</Analyzers>
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public override ImmutableArray<string> FixableDiagnosticIds
DiagnosticIdentifiers.PlaceNewLineAfterOrBeforeArrowToken,
DiagnosticIdentifiers.PlaceNewLineAfterOrBeforeEqualsToken,
DiagnosticIdentifiers.PutAttributeListOnItsOwnLine,
DiagnosticIdentifiers.AddOrRemoveNewLineBeforeWhileInDoStatement);
DiagnosticIdentifiers.AddOrRemoveNewLineBeforeWhileInDoStatement,
DiagnosticIdentifiers.PutExpressionBodyOnItsOwnLine);
}
}

Expand Down Expand Up @@ -61,6 +62,11 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
await CodeActionFactory.RegisterCodeActionForNewLineAsync(context).ConfigureAwait(false);
break;
}
case DiagnosticIdentifiers.PutExpressionBodyOnItsOwnLine:
{
await CodeActionFactory.RegisterCodeActionForNewLineAsync(context, increaseIndentation: true).ConfigureAwait(false);
break;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@ public static partial class DiagnosticIdentifiers
public const string PlaceNewLineAfterOrBeforeNullConditionalOperator = "RCS0059";
public const string BlankLineAfterFileScopedNamespaceDeclaration = "RCS0060";
public const string BlankLineBetweenSwitchSections = "RCS0061";
public const string PutExpressionBodyOnItsOwnLine = "RCS0062";
}
}
12 changes: 12 additions & 0 deletions src/Formatting.Analyzers/CSharp/DiagnosticRules.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,5 +645,17 @@ public static partial class DiagnosticRules
helpLinkUri: DiagnosticIdentifiers.BlankLineBetweenSwitchSections,
customTags: Array.Empty<string>());

/// <summary>RCS0062</summary>
public static readonly DiagnosticDescriptor PutExpressionBodyOnItsOwnLine = DiagnosticDescriptorFactory.Create(
id: DiagnosticIdentifiers.PutExpressionBodyOnItsOwnLine,
title: "Put expression body on its own line",
messageFormat: "Put expression body on its own line",
category: DiagnosticCategories.Roslynator,
defaultSeverity: DiagnosticSeverity.Info,
isEnabledByDefault: false,
description: null,
helpLinkUri: DiagnosticIdentifiers.PutExpressionBodyOnItsOwnLine,
customTags: Array.Empty<string>());

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslynator.CSharp;
using Roslynator.CSharp.CodeStyle;

namespace Roslynator.Formatting.CSharp;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class PutExpressionBodyOnItsOwnLineAnalyzer : BaseDiagnosticAnalyzer
{
private static ImmutableArray<DiagnosticDescriptor> _supportedDiagnostics;

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
if (_supportedDiagnostics.IsDefault)
Immutable.InterlockedInitialize(ref _supportedDiagnostics, DiagnosticRules.PutExpressionBodyOnItsOwnLine);

return _supportedDiagnostics;
}
}

public override void Initialize(AnalysisContext context)
{
base.Initialize(context);

context.RegisterSyntaxNodeAction(f => AnalyzeArrowExpressionClause(f), SyntaxKind.ArrowExpressionClause);
}

private static void AnalyzeArrowExpressionClause(SyntaxNodeAnalysisContext context)
{
var arrowExpressionClause = (ArrowExpressionClauseSyntax)context.Node;

switch (arrowExpressionClause.Parent.Kind())
{
case SyntaxKind.MethodDeclaration:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.DestructorDeclaration:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.IndexerDeclaration:
case SyntaxKind.OperatorDeclaration:
case SyntaxKind.ConversionOperatorDeclaration:
AnalyzeArrowExpressionClause(arrowExpressionClause.ArrowToken, context);
break;
}
}

private static void AnalyzeArrowExpressionClause(SyntaxToken arrowToken, SyntaxNodeAnalysisContext context)
{
NewLinePosition newLinePosition = context.GetArrowTokenNewLinePosition();

SyntaxToken first;
SyntaxToken second;
if (newLinePosition == NewLinePosition.After)
{
first = arrowToken;
second = arrowToken.GetNextToken();
}
else
{
first = arrowToken.GetPreviousToken();
second = arrowToken;
}

TriviaBlock block = TriviaBlock.FromBetween(first, second);

if (block.Kind == TriviaBlockKind.NoNewLine)
{
DiagnosticHelpers.ReportDiagnostic(
context,
DiagnosticRules.PutExpressionBodyOnItsOwnLine,
block.GetLocation());
}
}
}
Loading

0 comments on commit 0cea640

Please sign in to comment.