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
Expand Up @@ -148,7 +148,16 @@ public override void Initialize(AnalysisContext context)
// We expect a top-level block operation, that immediately returns an expression
if (context.OperationBlocks is not [IBlockOperation { Operations: [IReturnOperation returnOperation] }])
{
return;
// Special case for nested blocks (e.g. for code generated by some other tooling)
if (context.OperationBlocks is [IBlockOperation { Operations: [IBlockOperation { Operations: [IReturnOperation nestedReturnOperation] }] }])
{
returnOperation = nestedReturnOperation;
}
else
{
// Invalid 'get' accessor structure, we have to stop here
return;
}
}

// Next, we expect the return to produce a field reference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,123 @@ public partial class SampleViewModel : ObservableObject
await test.RunAsync();
}

[TestMethod]
public async Task SimplePropertyWithBlockAccessorSyntax()
{
string original = """
using CommunityToolkit.Mvvm.ComponentModel;

namespace MyApp;

public class SampleViewModel : ObservableObject
{
public string Name
{
get
{
return field;
}
set
{
SetProperty(ref field, value);
}
}
}
""";

string @fixed = """
using CommunityToolkit.Mvvm.ComponentModel;

namespace MyApp;

public partial class SampleViewModel : ObservableObject
{
[ObservableProperty]
public partial string Name { get; set; }
}
""";

CSharpCodeFixTest test = new(LanguageVersion.Preview)
{
TestCode = original,
FixedCode = @fixed,
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
};

test.TestState.AdditionalReferences.Add(typeof(ObservableObject).Assembly);
test.ExpectedDiagnostics.AddRange(new[]
{
// /0/Test0.cs(7,19): info MVVMTK0056: The semi-auto property MyApp.SampleViewModel.Name can be converted to a partial property using [ObservableProperty], which is recommended (doing so makes the code less verbose and results in more optimized code)
CSharpCodeFixVerifier.Diagnostic().WithSpan(7, 19, 7, 23).WithArguments("MyApp.SampleViewModel", "Name"),
});

test.FixedState.ExpectedDiagnostics.AddRange(new[]
{
// /0/Test0.cs(8,27): error CS9248: Partial property 'SampleViewModel.Name' must have an implementation part.
DiagnosticResult.CompilerError("CS9248").WithSpan(8, 27, 8, 31).WithArguments("MyApp.SampleViewModel.Name"),
});

await test.RunAsync();
}

[TestMethod]
public async Task SimplePropertyWithNestedBlockSyntax()
{
string original = """
using CommunityToolkit.Mvvm.ComponentModel;

namespace MyApp;

public class SampleViewModel : ObservableObject
{
public string Name
{
get
{
{
return field;
}
}
set => SetProperty(ref field, value);
}
}
""";

string @fixed = """
using CommunityToolkit.Mvvm.ComponentModel;

namespace MyApp;

public partial class SampleViewModel : ObservableObject
{
[ObservableProperty]
public partial string Name { get; set; }
}
""";

CSharpCodeFixTest test = new(LanguageVersion.Preview)
{
TestCode = original,
FixedCode = @fixed,
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
};

test.TestState.AdditionalReferences.Add(typeof(ObservableObject).Assembly);
test.ExpectedDiagnostics.AddRange(new[]
{
// /0/Test0.cs(7,19): info MVVMTK0056: The semi-auto property MyApp.SampleViewModel.Name can be converted to a partial property using [ObservableProperty], which is recommended (doing so makes the code less verbose and results in more optimized code)
CSharpCodeFixVerifier.Diagnostic().WithSpan(7, 19, 7, 23).WithArguments("MyApp.SampleViewModel", "Name"),
});

test.FixedState.ExpectedDiagnostics.AddRange(new[]
{
// /0/Test0.cs(8,27): error CS9248: Partial property 'SampleViewModel.Name' must have an implementation part.
DiagnosticResult.CompilerError("CS9248").WithSpan(8, 27, 8, 31).WithArguments("MyApp.SampleViewModel.Name"),
});

await test.RunAsync();
}

[TestMethod]
public async Task SimpleProperty_WithSemicolonTokenGetAccessor()
{
Expand Down