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 @@ -10,9 +10,9 @@ namespace TestNs
/// <summary>
/// Partial class for the TestVM which contains ReactiveUI Reactive property initialization.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveGenerator", "1.1.0.0")]
public partial class TestVM
{
[global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveGenerator", "1.1.0.0")]
/// <inheritdoc cref="_test3"/>
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[System.Text.Json.Serialization.JsonInclude]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace TestNs
/// <summary>
/// Partial class for the TestVM which contains ReactiveUI Reactive property initialization.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveGenerator", "1.1.0.0")]
public partial class TestVM
{
[global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveGenerator", "1.1.0.0")]
/// <inheritdoc cref="_test1"/>
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public int Test1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace TestNs
/// <summary>
/// Partial class for the TestVM which contains ReactiveUI Reactive property initialization.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveGenerator", "1.1.0.0")]
public partial class TestVM
{
[global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveGenerator", "1.1.0.0")]
/// <inheritdoc cref="_test2"/>
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public int Test2
Expand Down
37 changes: 26 additions & 11 deletions src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,20 @@ public sealed class TestHelper<T>(ITestOutputHelper testOutput) : IDisposable
new("ReactiveUI", VersionRange.AllStableFloating, LibraryDependencyTarget.Package);
#pragma warning restore CS0618 // Type or member is obsolete

private static readonly string mscorlibPath = Path.Combine(
System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(),
"mscorlib.dll");

private static readonly MetadataReference[] References =
[
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
MetadataReference.CreateFromFile(typeof(T).Assembly.Location),
MetadataReference.CreateFromFile(typeof(TestHelper<T>).Assembly.Location),

// Create mscorlib Reference
MetadataReference.CreateFromFile(mscorlibPath)

// Wpf references
////MetadataReference.CreateFromFile(Assembly.Load("PresentationCore").Location),
////MetadataReference.CreateFromFile(Assembly.Load("PresentationFramework").Location),
Expand Down Expand Up @@ -127,19 +134,22 @@ public void TestFail(
/// Tests a generator expecting it to pass successfully.
/// </summary>
/// <param name="source">The source code to test.</param>
/// <param name="withPreDiagnosics">if set to <c>true</c> [with pre diagnosics].</param>
/// <returns>
/// The driver.
/// </returns>
/// <exception cref="InvalidOperationException">Must have valid compiler instance.</exception>
/// <exception cref="ArgumentNullException">callerType.</exception>
public GeneratorDriver TestPass(
string source)
string source,
bool withPreDiagnosics = false)
{
if (_eventCompiler is null)
{
throw new InvalidOperationException("Must have valid compiler instance.");
}

return RunGeneratorAndCheck(source);
return RunGeneratorAndCheck(source, withPreDiagnosics);
}

/// <inheritdoc/>
Expand All @@ -149,13 +159,15 @@ public GeneratorDriver TestPass(
/// Runs the specified source generator and validates the generated code.
/// </summary>
/// <param name="code">The code to be parsed and processed by the generator.</param>
/// <param name="withPreDiagnosics">if set to <c>true</c> [with pre diagnosics].</param>
/// <param name="rerunCompilation">Indicates whether to rerun the compilation after running the generator.</param>
/// <returns>The generator driver used to run the generator.</returns>
/// <exception cref="InvalidOperationException">
/// Thrown if the compiler instance is not valid or if the compilation fails.
/// </exception>
/// <returns>
/// The generator driver used to run the generator.
/// </returns>
/// <exception cref="InvalidOperationException">Thrown if the compiler instance is not valid or if the compilation fails.</exception>
public GeneratorDriver RunGeneratorAndCheck(
string code,
bool withPreDiagnosics = false,
bool rerunCompilation = true)
{
if (_eventCompiler is null)
Expand All @@ -180,11 +192,14 @@ public GeneratorDriver RunGeneratorAndCheck(
assemblies,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, deterministic: true));

// Validate diagnostics before running the generator.
////var prediagnostics = compilation.GetDiagnostics()
//// .Where(d => !d.Id.Contains("CS0518") && d.Severity > DiagnosticSeverity.Warning)
//// .ToList();
////prediagnostics.Should().BeEmpty();
if (withPreDiagnosics)
{
// Validate diagnostics before running the generator.
var prediagnostics = compilation.GetDiagnostics()
.Where(d => d.Severity > DiagnosticSeverity.Warning)
.ToList();
prediagnostics.Should().BeEmpty();
}

var generator = new T();
var driver = CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ namespace TestNs;
public partial class TestVM : ReactiveObject
{
[ReactiveCommand]
private void Test1()
{
var a = 10;
}
private int Test1() => 10;
}
""";

Expand Down Expand Up @@ -68,10 +65,8 @@ namespace TestNs;
public partial class TestVM : ReactiveObject
{
[ReactiveCommand]
private void Test3(string baseString)
{
var a = baseString;
}
[property: JsonInclude]
private int Test3(string baseString) => int.Parse(baseString);
}
""";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,66 @@ public static string GetFullyQualifiedMetadataName(this ITypeSymbol symbol)
return builder.ToString();
}

public static bool IsTaskReturnType(this ITypeSymbol? typeSymbol)
{
var nameFormat = SymbolDisplayFormat.FullyQualifiedFormat;
do
{
var typeName = typeSymbol?.ToDisplayString(nameFormat);
if (typeName == "global::System.Threading.Tasks.Task")
{
return true;
}

typeSymbol = typeSymbol?.BaseType;
}
while (typeSymbol != null);

return false;
}

public static bool IsObservableReturnType(this ITypeSymbol? typeSymbol)
{
var nameFormat = SymbolDisplayFormat.FullyQualifiedFormat;
do
{
var typeName = typeSymbol?.ToDisplayString(nameFormat);
if (typeName?.Contains("global::System.IObservable") == true)
{
return true;
}

typeSymbol = typeSymbol?.BaseType;
}
while (typeSymbol != null);

return false;
}

public static bool IsObservableBoolType(this ITypeSymbol? typeSymbol)
{
var nameFormat = SymbolDisplayFormat.FullyQualifiedFormat;
do
{
var typeName = typeSymbol?.ToDisplayString(nameFormat);
if (typeName?.Contains("global::System.IObservable<bool>") == true)
{
return true;
}

typeSymbol = typeSymbol?.BaseType;
}
while (typeSymbol != null);

return false;
}

public static ITypeSymbol GetTaskReturnType(this ITypeSymbol typeSymbol, Compilation compilation) => typeSymbol switch
{
INamedTypeSymbol { TypeArguments.Length: 1 } namedTypeSymbol => namedTypeSymbol.TypeArguments[0],
_ => compilation.GetSpecialType(SpecialType.System_Void)
};

/// <summary>
/// Appends the fully qualified metadata name for a given symbol to a target builder.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/ReactiveUI.SourceGenerators/Core/Helpers/AttributeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,6 @@ public AttributeSyntax GetSyntax()

return Attribute(IdentifierName(TypeName), AttributeArgumentList(SeparatedList(arguments.Concat(namedArguments))));
}

public override string ToString() => $"[{GetSyntax()}]";
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ namespace {{containingNamespace}}
{{AddTabs(1)}}/// <summary>
{{AddTabs(1)}}/// Partial class for the {{containingTypeName}} which contains ReactiveUI Reactive property initialization.
{{AddTabs(1)}}/// </summary>
{{AddTabs(1)}}[global::System.CodeDom.Compiler.GeneratedCode("{{GeneratorName}}", "{{GeneratorVersion}}")]
{{AddTabs(1)}}{{containingClassVisibility}} partial {{containingType}} {{containingTypeName}}
{{AddTabs(1)}}{
{{AddTabs(2)}}[global::System.CodeDom.Compiler.GeneratedCode("{{GeneratorName}}", "{{GeneratorVersion}}")]
{{propertyDeclarations}}
{{AddTabs(1)}}}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal record CommandInfo(
bool IsObservable,
string? CanExecuteObservableName,
CanExecuteTypeInfo? CanExecuteTypeInfo,
EquatableArray<AttributeInfo> ForwardedPropertyAttributes)
EquatableArray<string> ForwardedPropertyAttributes)
{
private const string UnitTypeName = "global::System.Reactive.Unit";

Expand Down
Loading