Skip to content

Commit 4fae4dd

Browse files
authored
Merge pull request #398 from zhuman/fix_cslang_80
Fix for using C# 8.0 projects (e.g. UWP projects stuck on .NET Core 3)
2 parents bb4e41e + 9b7d871 commit 4fae4dd

File tree

2 files changed

+91
-10
lines changed

2 files changed

+91
-10
lines changed

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ private static FieldDeclarationSyntax CreateFieldDeclaration(string typeName, st
978978
.AddVariables(
979979
VariableDeclarator(Identifier(propertyName))
980980
.WithInitializer(EqualsValueClause(
981-
ImplicitObjectCreationExpression()
981+
ObjectCreationExpression(IdentifierName(typeName))
982982
.AddArgumentListArguments(Argument(
983983
LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(propertyName))))))))
984984
.AddModifiers(

tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/Test_SourceGeneratorsDiagnostics.cs

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ public partial class SampleViewModel
247247
VerifyGeneratedDiagnostics<INotifyPropertyChangedGenerator>(
248248
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)),
249249
"MVVMTK0008");
250+
251+
VerifySuccessfulGeneration(source);
250252
}
251253

252254
[TestMethod]
@@ -266,6 +268,8 @@ public partial class SampleViewModel
266268
VerifyGeneratedDiagnostics<ObservableObjectGenerator>(
267269
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)),
268270
"MVVMTK0008");
271+
272+
VerifySuccessfulGeneration(source);
269273
}
270274

271275
[TestMethod]
@@ -287,12 +291,16 @@ public partial class SampleViewModel
287291
VerifyGeneratedDiagnostics<ObservablePropertyGenerator>(
288292
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)),
289293
"MVVMTK0008");
294+
295+
VerifySuccessfulGeneration(source);
290296
}
291297

292298
[TestMethod]
299+
[Ignore("The generator should just not trigger at all in this scenario, update this after migrating diagnostics")]
293300
public void UnsupportedCSharpLanguageVersion_FromObservableValidatorValidateAllPropertiesGenerator()
294301
{
295302
string source = @"
303+
using System.ComponentModel.DataAnnotations;
296304
using CommunityToolkit.Mvvm.ComponentModel;
297305
298306
namespace MyApp
@@ -304,9 +312,11 @@ public partial class SampleViewModel : ObservableValidator
304312
}
305313
}";
306314

307-
// This is explicitly allowed in C# < 8.0, as it doesn't use any new features
315+
// Compilation should be fine on C# 7.3 as well (the generator just doesn't trigger)
308316
VerifyGeneratedDiagnostics<ObservableValidatorValidateAllPropertiesGenerator>(
309317
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)));
318+
319+
VerifySuccessfulGeneration(source);
310320
}
311321

312322
[TestMethod]
@@ -329,6 +339,8 @@ private void GreetUser(object value)
329339
VerifyGeneratedDiagnostics<RelayCommandGenerator>(
330340
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)),
331341
"MVVMTK0008");
342+
343+
VerifySuccessfulGeneration(source);
332344
}
333345

334346
[TestMethod]
@@ -351,9 +363,12 @@ public void Receive(MyMessage message)
351363
}
352364
}";
353365

354-
// This is explicitly allowed in C# < 8.0, as it doesn't use any new features
366+
// This should run fine on C# 8.0 too, as it doesn't use any newer features. Additionally, when not supported this
367+
// generator should just not run, not cause issues. The MVVM Toolkit has a reflection-based fallback path for this.
355368
VerifyGeneratedDiagnostics<IMessengerRegisterAllGenerator>(
356-
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)));
369+
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
370+
371+
VerifySuccessfulGeneration(source);
357372
}
358373

359374
[TestMethod]
@@ -1410,6 +1425,50 @@ private void GreetUser(User user)
14101425
VerifyGeneratedDiagnostics<RelayCommandGenerator>(source, "MVVMTK0031");
14111426
}
14121427

1428+
[TestMethod]
1429+
public void ValidObservablePropertyGeneratorScenarios()
1430+
{
1431+
string source = @"
1432+
using CommunityToolkit.Mvvm.ComponentModel;
1433+
1434+
namespace MyApp
1435+
{
1436+
[ObservableObject]
1437+
public partial class SampleViewModel
1438+
{
1439+
[ObservableProperty]
1440+
string name;
1441+
1442+
[ObservableProperty]
1443+
[NotifyPropertyChangedFor(nameof(Name))]
1444+
int number;
1445+
}
1446+
}";
1447+
1448+
VerifySuccessfulGeneration(source);
1449+
}
1450+
1451+
/// <summary>
1452+
/// Verifies that all available source generators can run successfully with the input source (including subsequent compilation).
1453+
/// </summary>
1454+
/// <param name="source">The input source to process.</param>
1455+
private static void VerifySuccessfulGeneration(string source)
1456+
{
1457+
IIncrementalGenerator[] generators =
1458+
{
1459+
new IMessengerRegisterAllGenerator(),
1460+
new NullabilityAttributesGenerator(),
1461+
new ObservableObjectGenerator(),
1462+
new INotifyPropertyChangedGenerator(),
1463+
new ObservablePropertyGenerator(),
1464+
new ObservableRecipientGenerator(),
1465+
new ObservableValidatorValidateAllPropertiesGenerator(),
1466+
new RelayCommandGenerator()
1467+
};
1468+
1469+
VerifyGeneratedDiagnostics(CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)), generators, Array.Empty<string>());
1470+
}
1471+
14131472
/// <summary>
14141473
/// Verifies the output of a source generator.
14151474
/// </summary>
@@ -1419,17 +1478,32 @@ private void GreetUser(User user)
14191478
private static void VerifyGeneratedDiagnostics<TGenerator>(string source, params string[] diagnosticsIds)
14201479
where TGenerator : class, IIncrementalGenerator, new()
14211480
{
1422-
VerifyGeneratedDiagnostics<TGenerator>(CSharpSyntaxTree.ParseText(source), diagnosticsIds);
1481+
IIncrementalGenerator generator = new TGenerator();
1482+
1483+
VerifyGeneratedDiagnostics(CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)), new[] { generator }, diagnosticsIds);
14231484
}
14241485

14251486
/// <summary>
14261487
/// Verifies the output of a source generator.
14271488
/// </summary>
14281489
/// <typeparam name="TGenerator">The generator type to use.</typeparam>
1429-
/// <param name="syntaxTree">The input source tree to process.</param>
1490+
/// <param name="syntaxTree">The input source to process.</param>
14301491
/// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
14311492
private static void VerifyGeneratedDiagnostics<TGenerator>(SyntaxTree syntaxTree, params string[] diagnosticsIds)
14321493
where TGenerator : class, IIncrementalGenerator, new()
1494+
{
1495+
IIncrementalGenerator generator = new TGenerator();
1496+
1497+
VerifyGeneratedDiagnostics(syntaxTree, new[] { generator }, diagnosticsIds);
1498+
}
1499+
1500+
/// <summary>
1501+
/// Verifies the output of one or more source generators.
1502+
/// </summary>
1503+
/// <param name="syntaxTree">The input source tree to process.</param>
1504+
/// <param name="generators">The generators to apply to the input syntax tree.</param>
1505+
/// <param name="generatorDiagnosticsIds">The diagnostic ids to expect for the input source code.</param>
1506+
private static void VerifyGeneratedDiagnostics(SyntaxTree syntaxTree, IIncrementalGenerator[] generators, string[] generatorDiagnosticsIds)
14331507
{
14341508
Type observableObjectType = typeof(ObservableObject);
14351509
Type validationAttributeType = typeof(ValidationAttribute);
@@ -1446,15 +1520,22 @@ from assembly in AppDomain.CurrentDomain.GetAssemblies()
14461520
references,
14471521
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
14481522

1449-
IIncrementalGenerator generator = new TGenerator();
1450-
1451-
GeneratorDriver driver = CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
1523+
GeneratorDriver driver = CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
14521524

14531525
_ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray<Diagnostic> diagnostics);
14541526

14551527
HashSet<string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();
14561528

1457-
CollectionAssert.AreEquivalent(diagnosticsIds, resultingIds.ToArray());
1529+
CollectionAssert.AreEquivalent(generatorDiagnosticsIds, resultingIds.ToArray(), $"resultingIds: {string.Join(", ", resultingIds)}");
1530+
1531+
// If the compilation was supposed to succeed, ensure that no further errors were generated
1532+
if (resultingIds.Count == 0)
1533+
{
1534+
// Compute diagnostics for the final compiled output (just include errors)
1535+
List<Diagnostic> outputCompilationDiagnostics = outputCompilation.GetDiagnostics().Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error).ToList();
1536+
1537+
Assert.IsTrue(outputCompilationDiagnostics.Count == 0, $"resultingIds:{Environment.NewLine} {string.Join(Environment.NewLine, outputCompilationDiagnostics)}");
1538+
}
14581539

14591540
GC.KeepAlive(observableObjectType);
14601541
GC.KeepAlive(validationAttributeType);

0 commit comments

Comments
 (0)