-
Notifications
You must be signed in to change notification settings - Fork 0
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
Improved nullable support #30
Changes from 9 commits
a4d737c
88dfdcf
c5bc172
0d06066
1116173
cd1f6fc
e85fede
8c856ec
86521ee
5cfce1f
02b537a
2c80122
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,10 @@ BinaryExpressionSyntax asExpression when asExpression.Kind() == SyntaxKind.AsExp | |
} | ||
|
||
var member = memberAccess.Name.Identifier.Text; | ||
IPathPart part = new MemberAccess(member); | ||
var typeInfo = Context.SemanticModel.GetTypeInfo(memberAccess).Type; | ||
var isReferenceType = typeInfo?.IsReferenceType ?? false; | ||
var isNullableValueType = typeInfo != null ? BindingGenerationUtilities.IsNullableValueType(typeInfo) : false; | ||
IPathPart part = new MemberAccess(member, !isReferenceType, isNullableValueType); | ||
parts.Add(part); | ||
return (diagnostics, parts); | ||
} | ||
|
@@ -55,12 +58,13 @@ BinaryExpressionSyntax asExpression when asExpression.Kind() == SyntaxKind.AsExp | |
} | ||
|
||
var elementAccessSymbol = Context.SemanticModel.GetSymbolInfo(elementAccess).Symbol; | ||
var (elementAccessDiagnostics, elementAccessParts) = HandleElementAccessSymbol(elementAccessSymbol, elementAccess.ArgumentList.Arguments, elementAccess.GetLocation()); | ||
var elementType = Context.SemanticModel.GetTypeInfo(elementAccess).Type; | ||
|
||
var (elementAccessDiagnostics, elementAccessParts) = CreateIndexAccess(elementAccessSymbol, elementType, elementAccess.ArgumentList.Arguments, elementAccess.GetLocation()); | ||
if (elementAccessDiagnostics.Length > 0) | ||
{ | ||
return (elementAccessDiagnostics, elementAccessParts); | ||
} | ||
|
||
parts.AddRange(elementAccessParts); | ||
return (diagnostics, parts); | ||
} | ||
|
@@ -86,7 +90,10 @@ BinaryExpressionSyntax asExpression when asExpression.Kind() == SyntaxKind.AsExp | |
private (EquatableArray<DiagnosticInfo> diagnostics, List<IPathPart> parts) HandleMemberBindingExpression(MemberBindingExpressionSyntax memberBinding) | ||
{ | ||
var member = memberBinding.Name.Identifier.Text; | ||
IPathPart part = new MemberAccess(member); | ||
var typeInfo = Context.SemanticModel.GetTypeInfo(memberBinding).Type; | ||
var isReferenceType = typeInfo?.IsReferenceType ?? false; | ||
var isNullableValueType = typeInfo != null ? BindingGenerationUtilities.IsNullableValueType(typeInfo) : false; | ||
IPathPart part = new MemberAccess(member, !isReferenceType, isNullableValueType); | ||
part = new ConditionalAccess(part); | ||
|
||
return ([], new List<IPathPart>([part])); | ||
|
@@ -95,7 +102,9 @@ BinaryExpressionSyntax asExpression when asExpression.Kind() == SyntaxKind.AsExp | |
private (EquatableArray<DiagnosticInfo> diagnostics, List<IPathPart> parts) HandleElementBindingExpression(ElementBindingExpressionSyntax elementBinding) | ||
{ | ||
var elementAccessSymbol = Context.SemanticModel.GetSymbolInfo(elementBinding).Symbol; | ||
var (elementAccessDiagnostics, elementAccessParts) = HandleElementAccessSymbol(elementAccessSymbol, elementBinding.ArgumentList.Arguments, elementBinding.GetLocation()); | ||
var elementType = Context.SemanticModel.GetTypeInfo(elementBinding).Type; | ||
|
||
var (elementAccessDiagnostics, elementAccessParts) = CreateIndexAccess(elementAccessSymbol, elementType, elementBinding.ArgumentList.Arguments, elementBinding.GetLocation()); | ||
if (elementAccessDiagnostics.Length > 0) | ||
{ | ||
return (elementAccessDiagnostics, elementAccessParts); | ||
|
@@ -147,7 +156,7 @@ BinaryExpressionSyntax asExpression when asExpression.Kind() == SyntaxKind.AsExp | |
return (new EquatableArray<DiagnosticInfo>([DiagnosticsFactory.UnableToResolvePath(Context.Node.GetLocation())]), new List<IPathPart>()); | ||
} | ||
|
||
private (EquatableArray<DiagnosticInfo>, List<IPathPart>) HandleElementAccessSymbol(ISymbol? elementAccessSymbol, SeparatedSyntaxList<ArgumentSyntax> argumentList, Location location) | ||
private (EquatableArray<DiagnosticInfo>, List<IPathPart>) CreateIndexAccess(ISymbol? elementAccessSymbol, ITypeSymbol? typeSymbol, SeparatedSyntaxList<ArgumentSyntax> argumentList, Location location) | ||
{ | ||
if (argumentList.Count != 1) | ||
{ | ||
|
@@ -162,7 +171,9 @@ BinaryExpressionSyntax asExpression when asExpression.Kind() == SyntaxKind.AsExp | |
} | ||
|
||
var name = GetIndexerName(elementAccessSymbol); | ||
IPathPart part = new IndexAccess(name, indexValue); | ||
var isReferenceType = typeSymbol?.IsReferenceType ?? false; | ||
var isNullableValueType = typeSymbol != null ? BindingGenerationUtilities.IsNullableValueType(typeSymbol) : false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's quite a lot of code duplication going on here and it's getting hard to read. We should consider moving this to a separate method at least. |
||
IPathPart part = new IndexAccess(name, indexValue, !isReferenceType, isNullableValueType); | ||
|
||
return ([], [part]); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,17 +5,14 @@ public sealed record Setter(string[] PatternMatchingExpressions, string Assignme | |
public static Setter From( | ||
TypeDescription sourceTypeDescription, | ||
EquatableArray<IPathPart> path, | ||
bool considerAllReferenceTypesPotentiallyNullable = false, | ||
string sourceVariableName = "source", | ||
string assignedValueExpression = "value") | ||
{ | ||
var builder = new SetterBuilder(sourceVariableName, assignedValueExpression); | ||
var builder = new SetterBuilder(considerAllReferenceTypesPotentiallyNullable, sourceVariableName, sourceTypeDescription, assignedValueExpression); | ||
|
||
if (path.Length > 0) | ||
{ | ||
if (sourceTypeDescription.IsNullable) | ||
{ | ||
builder.AddIsExpression("{}"); | ||
} | ||
|
||
foreach (var part in path) | ||
{ | ||
|
@@ -28,32 +25,47 @@ public static Setter From( | |
|
||
private sealed class SetterBuilder | ||
{ | ||
private readonly string _sourceVariableName; | ||
private readonly bool _considerAllReferenceTypesPotentiallyNullable; | ||
private readonly string _assignedValueExpression; | ||
|
||
private string _expression; | ||
private int _variableCounter = 0; | ||
private List<string>? _patternMatching; | ||
|
||
private IPathPart? _currentPart; | ||
private IPathPart? _previousPart; | ||
private IPathPart _sourcePart; | ||
|
||
public SetterBuilder(string sourceVariableName, string assignedValueExpression) | ||
public SetterBuilder(bool considerAllReferenceTypesPotentiallyNullable, string sourceVariableName, TypeDescription sourceTypeDescription, string assignedValueExpression) | ||
{ | ||
_sourceVariableName = sourceVariableName; | ||
_considerAllReferenceTypesPotentiallyNullable = considerAllReferenceTypesPotentiallyNullable; | ||
_assignedValueExpression = assignedValueExpression; | ||
|
||
_sourcePart = new MemberAccess(sourceVariableName, sourceTypeDescription.IsValueType, sourceTypeDescription.IsValueType && sourceTypeDescription.IsNullable); | ||
_currentPart = _sourcePart; | ||
|
||
_expression = sourceVariableName; | ||
} | ||
|
||
public void AddPart(IPathPart nextPart) | ||
{ | ||
_previousPart = HandlePreviousPart(nextPart); | ||
var newPart = HandleCurrentPart(nextPart); | ||
_previousPart = _currentPart; | ||
_currentPart = newPart; | ||
|
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking out loud: this needs refactoring, the |
||
|
||
private IPathPart? HandlePreviousPart(IPathPart? nextPart) | ||
private IPathPart? HandleCurrentPart(IPathPart? nextPart) | ||
{ | ||
if (_previousPart is {} previousPart) | ||
|
||
var previousReferenceType = _previousPart is MemberAccess previousPartAccess | ||
&& !previousPartAccess.IsValueType || _previousPart is IndexAccess previousPartIndexAccess | ||
&& !previousPartIndexAccess.IsValueType || _previousPart is ConditionalAccess; | ||
|
||
|
||
if (_currentPart is { } currentPart && currentPart != _sourcePart) | ||
{ | ||
if (previousPart is Cast { TargetType: var targetType }) | ||
if (currentPart is Cast { TargetType: var targetType }) | ||
{ | ||
AddIsExpression(targetType.GlobalName); | ||
|
||
|
@@ -63,14 +75,19 @@ public void AddPart(IPathPart nextPart) | |
return innerPart; | ||
} | ||
} | ||
else if (previousPart is ConditionalAccess { Part: var innerPart }) | ||
else if (currentPart is ConditionalAccess { Part: var innerPart }) | ||
{ | ||
AddIsExpression("{}"); | ||
_expression = AccessExpressionBuilder.Build(_expression, innerPart); | ||
} | ||
else if (previousReferenceType && _considerAllReferenceTypesPotentiallyNullable) | ||
{ | ||
AddIsExpression("{}"); | ||
_expression = AccessExpressionBuilder.Build(_expression, currentPart); | ||
} | ||
else | ||
{ | ||
_expression = AccessExpressionBuilder.Build(_expression, previousPart); | ||
_expression = AccessExpressionBuilder.Build(_expression, currentPart); | ||
} | ||
} | ||
|
||
|
@@ -94,7 +111,7 @@ private string CreateNextUniqueVariableName() | |
|
||
private string CreateAssignmentStatement() | ||
{ | ||
HandlePreviousPart(nextPart: null); | ||
HandleCurrentPart(nextPart: null); | ||
return $"{_expression} = {_assignedValueExpression};"; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need a check for
IndexAccess
here as well + a unit test that covers that case.