Skip to content

Commit 64931ff

Browse files
Support target-typed new expressions (#12)
* Recognize ImplicitObjectCreationExpressionSyntax * Add tests and sample for target-typed new * Simplify syntax node identification * Return pattern matching * Minor improvements cherry picked from 309d875 Cherry picked changes from 309d875 Minor improvements to syntax, null checking and unit test. --------- Co-authored-by: Andreas Gullberg Larsen <andreas.larsen84@gmail.com>
1 parent aed375d commit 64931ff

File tree

4 files changed

+63
-19
lines changed

4 files changed

+63
-19
lines changed

AssignAll/AssignAll.Test/UnitTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,5 +713,36 @@ private class Derived : Base
713713
var expected = VerifyCS.Diagnostic("AssignAll").WithLocation(0).WithArguments("Derived", "BasePropUnassigned, DerivedPropUnassigned" );
714714
await VerifyCS.VerifyAnalyzerAsync(test, expected);
715715
}
716+
717+
[Fact]
718+
public async Task TargetTypedNew_UnassignedMembers_AddsDiagnostic()
719+
{
720+
var test = @"
721+
namespace SampleConsoleApp
722+
{
723+
internal static class Program
724+
{
725+
private static void Main(string[] args)
726+
{
727+
// AssignAll enable
728+
Foo foo = {|#0:new()
729+
{
730+
// PropString not assigned, diagnostic error
731+
PropInt = 1,
732+
}|#0};
733+
}
734+
735+
private class Foo
736+
{
737+
public int PropInt { get; set; }
738+
public string PropString { get; set; }
739+
}
740+
}
741+
}
742+
";
743+
744+
var expected = VerifyCS.Diagnostic("AssignAll").WithLocation(0).WithArguments("Foo", "PropString");
745+
await VerifyCS.VerifyAnalyzerAsync(test, expected);
746+
}
716747
}
717748
}

AssignAll/AssignAll/AssignAllCodeFixProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext ctx)
4343
return;
4444

4545
// Find the object initializer identified by the diagnostic
46-
var objectCreation = root.FindNode(diagnosticSpan) as ObjectCreationExpressionSyntax;
46+
var objectCreation = root.FindNode(diagnosticSpan) as BaseObjectCreationExpressionSyntax;
4747
InitializerExpressionSyntax objectInitializer = objectCreation?.Initializer;
4848
if (objectInitializer == null)
4949
return;

AssignAll/AssignAll/AssignAllMembers/ObjectInitializerAnalyzer.cs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@ internal void AnalyzeObjectInitializers(SyntaxNodeAnalysisContext ctx)
2525
// TODO Support other means to enable, such as static configuration (analyze all/none by default), attributes on types and members
2626
if (!_regionsToAnalyze.TextSpans.Any(enabledTextSpan => enabledTextSpan.Contains(objectInitializer.SpanStart))) return;
2727

28-
// Only handle initializers immediately following object creation,
29-
// not sure what the scenario would be since we are only registered for
28+
// Only handle initializers immediately following object creation.
29+
// Not sure what the scenario would be since we are only registered for
3030
// object initializers, not things like list/collection initializers.
31-
if (!(objectInitializer.Parent is ObjectCreationExpressionSyntax objectCreation))
31+
if (!(objectInitializer.Parent is BaseObjectCreationExpressionSyntax objectCreation))
3232
return;
3333

34-
var objectCreationNamedType =
35-
(INamedTypeSymbol) ctx.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol;
36-
if (objectCreationNamedType == null)
34+
if (!(ctx.SemanticModel.GetTypeInfo(objectCreation).Type is INamedTypeSymbol objectCreationNamedType))
3735
return;
3836

3937
IEnumerable<ISymbol> membersEnumerable = objectCreationNamedType.GetMembers();
@@ -110,20 +108,10 @@ internal void AnalyzeObjectInitializers(SyntaxNodeAnalysisContext ctx)
110108
}
111109
}
112110

113-
// public void CodeBlockEndAction(CodeBlockAnalysisContext ctx)
114-
// {
115-
// }
116-
117-
private static ImmutableArray<string> GetIgnoredPropertyNames(ObjectCreationExpressionSyntax objectCreation)
111+
private static ImmutableArray<string> GetIgnoredPropertyNames(BaseObjectCreationExpressionSyntax objectCreation)
118112
{
119-
ImmutableArray<string> propertiesByCommentedAssignment =
120-
GetIgnoredPropertyNamesFromCommentedAssignments(objectCreation);
121-
return propertiesByCommentedAssignment;
122-
}
113+
if (objectCreation.Initializer == null) return ImmutableArray<string>.Empty;
123114

124-
private static ImmutableArray<string> GetIgnoredPropertyNamesFromCommentedAssignments(
125-
ObjectCreationExpressionSyntax objectCreation)
126-
{
127115
// Case 1: Commented member assignments before one or more actual member assignments
128116
// return new Foo {
129117
// // Prop1 = null,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// AssignAll enable
2+
// EXAMPLE 005 - Target-typed new expressions.
3+
// https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-new
4+
namespace Samples.ConsoleNet6;
5+
6+
public static class Example005_TargetTypedNew
7+
{
8+
public static void Irrelevant()
9+
{
10+
// This should give analyzer error:
11+
// Missing member assignments in object initializer for type 'Foo'. Properties: PropUnassigned
12+
Foo foo = new()
13+
{
14+
// Commented assignments after opening brace.
15+
// PropCommented1 = 1,
16+
17+
// Assigned property, OK by analyzer
18+
PropAssigned = 1,
19+
20+
// Commented assignments just before closing brace
21+
//PropCommented2 = ,
22+
// PropCommented3=,
23+
};
24+
}
25+
}

0 commit comments

Comments
 (0)