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
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
Expand Down Expand Up @@ -48,8 +47,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
attributeList = attributeList.Parent;
}

// Get the class, method or property adjacent to the AttributeList
if (attributeList?.Parent is not SyntaxNode parentDeclaration)
// Get the member declaration adjacent to the AttributeList
if (attributeList?.Parent is not MemberDeclarationSyntax parentDeclaration)
{
return;
}
Expand All @@ -63,12 +62,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
diagnostic);
}

private static async Task<Document> PutOnSeparateLine(Document document, SyntaxNode parentDeclaration, CancellationToken cancellationToken)
private static async Task<Document> PutOnSeparateLine(Document document, MemberDeclarationSyntax parentDeclaration, CancellationToken cancellationToken)
{
var attributeLists = new SyntaxList<AttributeListSyntax>();

// put every attribute into it's own attributelist eg.: [A,B,C] => [A][B][C]
foreach (AttributeSyntax attribute in GetAttributeListSyntaxes(parentDeclaration).SelectMany(l => l.Attributes))
foreach (AttributeSyntax attribute in parentDeclaration.AttributeLists.SelectMany(l => l.Attributes))
{
attributeLists = attributeLists.Add(
SyntaxFactory.AttributeList(
Expand All @@ -80,7 +79,7 @@ private static async Task<Document> PutOnSeparateLine(Document document, SyntaxN
}

// the formatter-annotation will wrap every attribute on a separate line
SyntaxNode newNode = BuildNodeWithAttributeLists(parentDeclaration, attributeLists)
MemberDeclarationSyntax newNode = parentDeclaration.WithAttributeLists(attributeLists)
.WithAdditionalAnnotations(Formatter.Annotation);

// Replace the old local declaration with the new local declaration.
Expand All @@ -90,29 +89,5 @@ private static async Task<Document> PutOnSeparateLine(Document document, SyntaxN

return document.WithSyntaxRoot(newRoot);
}

private static IEnumerable<AttributeListSyntax> GetAttributeListSyntaxes(SyntaxNode node)
{
return node switch
{
ClassDeclarationSyntax c => c.AttributeLists,
MethodDeclarationSyntax m => m.AttributeLists,
PropertyDeclarationSyntax p => p.AttributeLists,
FieldDeclarationSyntax f => f.AttributeLists,
_ => throw new NotImplementedException(),
};
}

private static SyntaxNode BuildNodeWithAttributeLists(SyntaxNode node, SyntaxList<AttributeListSyntax> attributeLists)
{
return node switch
{
ClassDeclarationSyntax c => c.WithAttributeLists(attributeLists),
MethodDeclarationSyntax m => m.WithAttributeLists(attributeLists),
PropertyDeclarationSyntax p => p.WithAttributeLists(attributeLists),
FieldDeclarationSyntax f => f.WithAttributeLists(attributeLists),
_ => throw new NotImplementedException(),
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,312 @@ static void Main()
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task StructAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A][B]
struct MyStruct
{
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A]
[B]
struct MyStruct
{
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task RecordAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A][B]
record MyRecord
{
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A]
[B]
record MyRecord
{
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task InterfaceAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A][B]
interface IMyInterface
{
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A]
[B]
interface IMyInterface
{
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task EnumAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A][B]
enum MyEnum
{
Foo
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

[A]
[B]
enum MyEnum
{
Foo
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task ConstructorAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

class Program
{
[A][B]
Program()
{
}
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

class Program
{
[A]
[B]
Program()
{
}
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task EnumMemberAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

enum MyEnum
{
[A][B]
Bar
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

enum MyEnum
{
[A]
[B]
Bar
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
public async Task IndexerAttributeLineViolation_CodeFix_TwoAttributesOnSameLine_TwoAttributesOnSeparateLines()
{
string test = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

class Program
{
[A][B]
int this[int i] { get => 0; }
}
}";

string fixTest = @"using System;

namespace ConsoleApp
{
class AAttribute : Attribute
{
}

class BAttribute : Attribute
{
}

class Program
{
[A]
[B]
int this[int i] { get => 0; }
}
}";
await VerifyCSharpFix(test, fixTest);
}

[TestMethod]
[Description("Analyzer should not report on generated code")]
public void AttributesOnSameLine_InGeneratedCode_NoDiagnostic()
Expand Down
Loading