Thanks to visit codestin.com
Credit goes to github.com

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
9 changes: 8 additions & 1 deletion src/MessagePackAnalyzer/MessagePackAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,14 @@ public override void Initialize(AnalysisContext context)
{
if (ReferenceSymbols.TryCreate(ctxt.Compilation, out ReferenceSymbols? typeReferences))
{
ctxt.RegisterSyntaxNodeAction(c => Analyze(c, typeReferences), SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration);
var relevantSyntaxKinds = new[]
{
SyntaxKind.ClassDeclaration,
SyntaxKind.StructDeclaration,
SyntaxKind.InterfaceDeclaration,
SyntaxKind.RecordDeclaration,
};
ctxt.RegisterSyntaxNodeAction(c => Analyze(c, typeReferences), relevantSyntaxKinds);
}
});
}
Expand Down
18 changes: 16 additions & 2 deletions src/MessagePackAnalyzer/MessagePackCodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,26 @@ private static async Task<Solution> AddKeyAttributeAsync(Document document, INam

foreach (ISymbol member in targets)
{
if (member.GetAttributes().FindAttributeShortName(MessagePackAnalyzer.KeyAttributeShortName) is null)
if (!member.IsImplicitlyDeclared &&
member.GetAttributes().FindAttributeShortName(MessagePackAnalyzer.KeyAttributeShortName) is null)
{
SyntaxNode node = await member.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
var documentEditor = await solutionEditor.GetDocumentEditorAsync(document.Project.Solution.GetDocumentId(node.SyntaxTree), cancellationToken).ConfigureAwait(false);
var syntaxGenerator = SyntaxGenerator.GetGenerator(documentEditor.OriginalDocument);
documentEditor.AddAttribute(node, syntaxGenerator.Attribute("MessagePack.KeyAttribute", syntaxGenerator.LiteralExpression(startOrder++)));
AttributeListSyntax attributeList = (AttributeListSyntax)syntaxGenerator.Attribute("MessagePack.KeyAttribute", syntaxGenerator.LiteralExpression(startOrder++));
if (node is ParameterSyntax parameter)
{
// The primary constructor requires special target on the attribute list.
attributeList = attributeList.WithTarget(
SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.PropertyKeyword)))
.WithLeadingTrivia(parameter.GetLeadingTrivia());
ParameterSyntax attributedParameter = parameter.AddAttributeLists(attributeList);
documentEditor.ReplaceNode(parameter, attributedParameter);
}
else
{
documentEditor.AddAttribute(node, attributeList);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) All contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
Expand All @@ -22,26 +23,26 @@ public static DiagnosticResult Diagnostic(string diagnosticId)
public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
=> new DiagnosticResult(descriptor);

public static Task VerifyAnalyzerWithoutMessagePackReferenceAsync(string source)
public static Task VerifyAnalyzerWithoutMessagePackReferenceAsync([StringSyntax("c#-test")] string source)
{
var test = new Test { TestCode = source, ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net472.Default };
return test.RunAsync();
}

public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
public static Task VerifyAnalyzerAsync([StringSyntax("c#-test")] string source, params DiagnosticResult[] expected)
{
var test = new Test { TestCode = source };
test.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}

public static Task VerifyCodeFixAsync(string source, string fixedSource)
public static Task VerifyCodeFixAsync([StringSyntax("c#-test")] string source, [StringSyntax("c#-test")] string fixedSource)
=> VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);

public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
public static Task VerifyCodeFixAsync([StringSyntax("c#-test")] string source, DiagnosticResult expected, [StringSyntax("c#-test")] string fixedSource)
=> VerifyCodeFixAsync(source, new[] { expected }, fixedSource);

public static Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
public static Task VerifyCodeFixAsync([StringSyntax("c#-test")] string source, DiagnosticResult[] expected, [StringSyntax("c#-test")] string fixedSource)
{
var test = new Test
{
Expand All @@ -53,7 +54,7 @@ public static Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected
return test.RunAsync();
}

public static Task VerifyCodeFixAsync(string[] source, string[] fixedSource)
public static Task VerifyCodeFixAsync([StringSyntax("c#-test")] string[] source, [StringSyntax("c#-test")] string[] fixedSource)
{
var test = new Test
{
Expand Down
101 changes: 87 additions & 14 deletions tests/MessagePackAnalyzer.Tests/MessagePackAnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
// Copyright (c) All contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Xunit;
using VerifyCS =
CSharpCodeFixVerifier<MessagePackAnalyzer.MessagePackAnalyzer, MessagePackAnalyzer.MessagePackCodeFixProvider>;

public class MessagePackAnalyzerTests
{
private const string Preamble = @"
private const string Preamble = /* lang=c#-test */ @"
using MessagePack;
";

[Fact]
public async Task NoMessagePackReference()
{
string input = @"
string input = /* lang=c#-test */ @"
public class Foo
{
}
Expand All @@ -29,7 +31,7 @@ public class Foo
[Fact]
public async Task MessageFormatterAttribute()
{
string input = Preamble + @"using MessagePack.Formatters;
string input = Preamble + /* lang=c#-test */ @"using MessagePack.Formatters;

public class FooFormatter : IMessagePackFormatter<Foo> {
public void Serialize(ref MessagePackWriter writer, Foo value, MessagePackSerializerOptions options) {}
Expand All @@ -55,7 +57,7 @@ public class SomeClass {
[Fact]
public async Task InvalidMessageFormatterType()
{
string input = Preamble + @"using MessagePack.Formatters;
string input = Preamble + /* lang=c#-test */ @"using MessagePack.Formatters;

public class InvalidMessageFormatter { }

Expand All @@ -77,7 +79,7 @@ public class SomeClass {
[Fact]
public async Task NullStringKey()
{
string input = Preamble + @"
string input = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public class Foo
{
Expand All @@ -92,7 +94,7 @@ public class Foo
[Fact]
public async Task AddAttributesToMembers()
{
string input = Preamble + @"
string input = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public class Foo
{
Expand All @@ -101,7 +103,7 @@ public class Foo
}
";

string output = Preamble + @"
string output = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public class Foo
{
Expand All @@ -119,7 +121,7 @@ public class Foo
public async Task AddAttributeToType()
{
// Don't use Preamble because we want to test that it works without a using statement at the top.
string input = @"
string input = /* lang=c#-test */ @"
public class Foo
{
public string Member { get; set; }
Expand All @@ -133,7 +135,7 @@ public class Bar
}
";

string output = @"
string output = /* lang=c#-test */ @"
[MessagePack.MessagePackObject]
public class Foo
{
Expand All @@ -157,13 +159,13 @@ public async Task CodeFixAppliesAcrossFiles()
{
var inputs = new string[]
{
@"
/* lang=c#-test */ @"
public class Foo
{
public int {|MsgPack004:Member1|} { get; set; }
}
",
@"using MessagePack;
/* lang=c#-test */ @"using MessagePack;

[MessagePackObject]
public class Bar : Foo
Expand All @@ -174,14 +176,14 @@ public class Bar : Foo
};
var outputs = new string[]
{
@"
/* lang=c#-test */ @"
public class Foo
{
[MessagePack.Key(1)]
public int Member1 { get; set; }
}
",
@"using MessagePack;
/* lang=c#-test */ @"using MessagePack;

[MessagePackObject]
public class Bar : Foo
Expand All @@ -194,4 +196,75 @@ public class Bar : Foo

await VerifyCS.VerifyCodeFixAsync(inputs, outputs);
}

[Fact]
public async Task AddAttributesToMembersOfRecord()
{
string input = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public record Foo
{
public string {|MsgPack004:Member1|} { get; set; }
public string {|MsgPack004:Member2|} { get; set; }
}
";

string output = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public record Foo
{
[Key(0)]
public string Member1 { get; set; }
[Key(1)]
public string Member2 { get; set; }
}
";
await new VerifyCS.Test
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net60.WithPackages(ImmutableArray.Create(new PackageIdentity("MessagePack", "2.0.335"))),
CompilerDiagnostics = CompilerDiagnostics.Errors,
SolutionTransforms =
{
static (solution, projectId) =>
{
return solution.WithProjectParseOptions(projectId, new CSharpParseOptions(languageVersion: LanguageVersion.CSharp11));
},
},
TestCode = input,
FixedCode = output,
}.RunAsync();
}

[Fact]
public async Task AddAttributesToMembersOfRecordWithPrimaryCtor()
{
string input = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public record Foo(
string {|MsgPack004:Member1|},
string {|MsgPack004:Member2|});
";

string output = Preamble + /* lang=c#-test */ @"
[MessagePackObject]
public record Foo(
[property: Key(0)] string {|MsgPack004:Member1|},
[property: Key(1)] string {|MsgPack004:Member2|});
";

await new VerifyCS.Test
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net60.WithPackages(ImmutableArray.Create(new PackageIdentity("MessagePack", "2.0.335"))),
CompilerDiagnostics = CompilerDiagnostics.Errors,
SolutionTransforms =
{
static (solution, projectId) =>
{
return solution.WithProjectParseOptions(projectId, new CSharpParseOptions(languageVersion: LanguageVersion.CSharp11));
},
},
TestCode = input,
FixedCode = output,
}.RunAsync();
}
}
Loading