Skip to content

Commit

Permalink
Fixed symbol comparison to be case-insensitive, since message initial…
Browse files Browse the repository at this point in the history
…izers ignore property name case
  • Loading branch information
phatboyg committed Feb 26, 2023
1 parent f01d817 commit bf77c67
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 26 deletions.
10 changes: 4 additions & 6 deletions src/MassTransit.Analyzers/MessageContractAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ static bool TypesAreStructurallyCompatible(TypeConversionHelper typeConverterHel

foreach (var inputProperty in inputProperties)
{
var contractProperty = contractProperties.FirstOrDefault(m => m.Name == inputProperty.Name);
var contractProperty = contractProperties.FirstOrDefault(m => m.Name.Equals(inputProperty.Name, StringComparison.OrdinalIgnoreCase));

var propertyPath = Append(path, inputProperty.Name);

Expand Down Expand Up @@ -210,8 +210,7 @@ static bool PropertyTypesAreStructurallyCompatible(TypeConversionHelper typeConv
{
if (contractPropertyType.TypeKind.IsClassOrInterface())
{
if (!TypesAreStructurallyCompatible(typeConverterHelper, contractPropertyType,
inputPropertyType, path, incompatibleProperties))
if (!TypesAreStructurallyCompatible(typeConverterHelper, contractPropertyType, inputPropertyType, path, incompatibleProperties))
return false;
}
else
Expand Down Expand Up @@ -309,8 +308,7 @@ static bool KeyValueTypesAreStructurallyCompatible(TypeConversionHelper typeConv

if (contractValueType.TypeKind.IsClassOrInterface())
{
if (!TypesAreStructurallyCompatible(typeConverterHelper, contractValueType,
inputValueType, path, incompatibleProperties))
if (!TypesAreStructurallyCompatible(typeConverterHelper, contractValueType, inputValueType, path, incompatibleProperties))
return false;
}
else
Expand Down Expand Up @@ -357,7 +355,7 @@ static bool HasMissingProperties(ITypeSymbol inputType, ITypeSymbol contractType

foreach (var contractProperty in contractProperties)
{
var inputProperty = inputProperties.FirstOrDefault(m => m.Name == contractProperty.Name);
var inputProperty = inputProperties.FirstOrDefault(m => m.Name.Equals(contractProperty.Name, StringComparison.OrdinalIgnoreCase));

var propertyPath = Append(path, contractProperty.Name);

Expand Down
42 changes: 22 additions & 20 deletions src/MassTransit.Analyzers/MessageContractCodeFixProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace MassTransit.Analyzers
{
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
Expand Down Expand Up @@ -53,9 +54,9 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
}

static async Task<Document> AddMissingProperties(Document document,
AnonymousObjectCreationExpressionSyntax anonymousObject,
string fullType,
CancellationToken cancellationToken)
AnonymousObjectCreationExpressionSyntax anonymousObject,
string fullType,
CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -92,7 +93,7 @@ static async Task FindAnonymousTypesWithMessageContractsInTree(IDictionary<Anony
{
var name = GetName(initializer);

var contractProperty = contractProperties.FirstOrDefault(p => p.Name == name);
var contractProperty = contractProperties.FirstOrDefault(m => m.Name.Equals(name, StringComparison.OrdinalIgnoreCase));

if (contractProperty != null)
{
Expand Down Expand Up @@ -122,9 +123,9 @@ await FindAnonymousTypesWithMessageContractsInTree(dictionary, anonymousObjectPr
.ConfigureAwait(false);
}
else if (initializer.Expression is InvocationExpressionSyntax invocationExpressionSyntax
&& semanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol is IMethodSymbol method
&& method.ReturnType.IsList(out var methodReturnTypeArgument)
&& methodReturnTypeArgument.IsAnonymousType)
&& semanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol is IMethodSymbol method
&& method.ReturnType.IsList(out var methodReturnTypeArgument)
&& methodReturnTypeArgument.IsAnonymousType)
{
if (contractProperty.Type.IsImmutableArray(out var contractElementType) ||
contractProperty.Type.IsList(out contractElementType) ||
Expand Down Expand Up @@ -198,7 +199,8 @@ static SyntaxNode AddMissingProperties(SyntaxNode root, AnonymousObjectCreationE
var propertiesToAdd = new List<AnonymousObjectMemberDeclaratorSyntax>();
foreach (var messageContractProperty in contractProperties)
{
var initializer = anonymousObject.Initializers.FirstOrDefault(i => GetName(i) == messageContractProperty.Name);
var initializer = anonymousObject.Initializers
.FirstOrDefault(i => GetName(i).Equals(messageContractProperty.Name, StringComparison.OrdinalIgnoreCase));
if (initializer == null)
{
var path = Enumerable.Empty<ITypeSymbol>();
Expand Down Expand Up @@ -237,8 +239,8 @@ static AnonymousObjectMemberDeclaratorSyntax CreateProperty(IPropertySymbol cont
ExpressionSyntax expression;

if (contractProperty.Type.IsImmutableArray(out var contractElementType) ||
contractProperty.Type.IsList(out contractElementType) ||
contractProperty.Type.IsArray(out contractElementType))
contractProperty.Type.IsList(out contractElementType) ||
contractProperty.Type.IsArray(out contractElementType))
{
if (path.Contains(contractElementType, SymbolEqualityComparer.Default))
expression = CreateEmptyArray(contractElementType);
Expand All @@ -265,16 +267,16 @@ static AnonymousObjectMemberDeclaratorSyntax CreateProperty(IPropertySymbol cont
static ExpressionSyntax CreateEmptyArray(ITypeSymbol type)
{
return SyntaxFactory.InvocationExpression(
SyntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.IdentifierName("Array"),
SyntaxFactory.GenericName(
SyntaxFactory.Identifier("Empty"))
.WithTypeArgumentList(
SyntaxFactory.TypeArgumentList(
SyntaxFactory.SingletonSeparatedList<TypeSyntax>(
SyntaxFactory.IdentifierName(type.Name))))))
.NormalizeWhitespace();
SyntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.IdentifierName("Array"),
SyntaxFactory.GenericName(
SyntaxFactory.Identifier("Empty"))
.WithTypeArgumentList(
SyntaxFactory.TypeArgumentList(
SyntaxFactory.SingletonSeparatedList<TypeSyntax>(
SyntaxFactory.IdentifierName(type.Name))))))
.NormalizeWhitespace();
}

static ImplicitArrayCreationExpressionSyntax CreateImplicitArray(ITypeSymbol type, IEnumerable<ITypeSymbol> path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,76 @@ await bus.Publish<OrderSubmitted>(new
VerifyCSharpFix(test, fixtest);
}

[Test]
public void WhenMessageContractHasNullableAreStructurallyCompatibleAndMissingCaseNullableProperty_ShouldHaveDiagnosticAndCodeFix()
{
var test = Usings + @"
namespace ConsoleApplication1
{
public interface OrderSubmitted
{
Guid Id { get; }
int Quantity { get; }
decimal? Price { get; }
}
class Program
{
static async Task Main()
{
var bus = Bus.Factory.CreateUsingInMemory(cfg => { });
await bus.Publish<OrderSubmitted>(new
{
Id = NewId.NextGuid(),
quantity = 10
});
}
}
}
";
var expected = new DiagnosticResult
{
Id = "MCA0003",
Message =
"Anonymous type is missing properties that are in the message contract 'OrderSubmitted'. The following properties are missing: Price.",
Severity = DiagnosticSeverity.Info,
Locations =
new[] { new DiagnosticResultLocation("Test0.cs", 23, 47) }
};

VerifyCSharpDiagnostic(test, expected);

var fixtest = Usings + @"
namespace ConsoleApplication1
{
public interface OrderSubmitted
{
Guid Id { get; }
int Quantity { get; }
decimal? Price { get; }
}
class Program
{
static async Task Main()
{
var bus = Bus.Factory.CreateUsingInMemory(cfg => { });
await bus.Publish<OrderSubmitted>(new
{
Id = NewId.NextGuid(),
quantity = 10
,
Price = default(decimal?)
});
}
}
}
";
VerifyCSharpFix(test, fixtest);
}

[Test]
public void WhenPublishTypesAreStructurallyCompatibleAndMissingProperty_ShouldHaveDiagnostic()
{
Expand Down

0 comments on commit bf77c67

Please sign in to comment.