diff --git a/src/Benchmarks/Directory.Packages.props b/src/Benchmarks/Directory.Packages.props new file mode 100644 index 0000000000..4a39f3d824 --- /dev/null +++ b/src/Benchmarks/Directory.Packages.props @@ -0,0 +1,13 @@ + + + true + true + + + + + + + + diff --git a/src/Benchmarks/ReactiveUI.Benchmarks.csproj b/src/Benchmarks/ReactiveUI.Benchmarks.csproj index 6747ab71c8..34ab2ff5fd 100644 --- a/src/Benchmarks/ReactiveUI.Benchmarks.csproj +++ b/src/Benchmarks/ReactiveUI.Benchmarks.csproj @@ -1,28 +1,19 @@ - false - net472;netcoreapp3.1 - BenchmarkDotNet.Samples + net8.0 AnyCPU - pdbonly - true Exe ;1591;1701;1702;1705;CA1822 A MVVM framework that integrates with the Reactive Extensions for .NET to create elegant, testable User Interfaces that run on any mobile or desktop platform. This is the base package with the base platform implementations - - - - - - - + + diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props new file mode 100644 index 0000000000..c001fd2662 --- /dev/null +++ b/src/Directory.Packages.props @@ -0,0 +1,98 @@ + + + true + true + + + 6.8.0 + 14.8.12 + 28.0.0.3 + 2.6.6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Directory.build.props b/src/Directory.build.props index 80b2fc2cfb..331fd93c9f 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -18,9 +18,8 @@ https://github.com/reactiveui/reactiveui git $(NoWarn);SA1010;RCS1198;RCS1158;RCS1163;RCS1256;IDE0060;IDE1006;VSSpell001 - - true + true true @@ -33,52 +32,44 @@ true true true - 2.6.6 - portable - true - - - - - - - - - - - + + + + + + + + + + - - + - - + $(MSBuildThisFileDirectory) - - + - - - - - + + + + diff --git a/src/ReactiveUI.AndroidSupport/ReactiveUI.AndroidSupport.csproj b/src/ReactiveUI.AndroidSupport/ReactiveUI.AndroidSupport.csproj index 19acb364b0..fecc1eaa86 100644 --- a/src/ReactiveUI.AndroidSupport/ReactiveUI.AndroidSupport.csproj +++ b/src/ReactiveUI.AndroidSupport/ReactiveUI.AndroidSupport.csproj @@ -1,32 +1,28 @@  - MonoAndroid13.0 Provides ReactiveUI extensions for the Android Support Library ReactiveUI.AndroidSupport mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;xamarin;android;forms;monodroid;monotouch;xamarin.android;net; - - - ..\Java.Interop.dll - + + ..\Java.Interop.dll + - - - - - - - - + + + + + + + - - + \ No newline at end of file diff --git a/src/ReactiveUI.AndroidX/ReactiveUI.AndroidX.csproj b/src/ReactiveUI.AndroidX/ReactiveUI.AndroidX.csproj index a2cc9c3307..371833524b 100644 --- a/src/ReactiveUI.AndroidX/ReactiveUI.AndroidX.csproj +++ b/src/ReactiveUI.AndroidX/ReactiveUI.AndroidX.csproj @@ -1,31 +1,27 @@  - MonoAndroid13.0 Provides ReactiveUI extensions for the AndroidX Library ReactiveUI.AndroidX mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;xamarin;android;forms;monodroid;monotouch;xamarin.android;net; - - - ..\Java.Interop.dll - + + ..\Java.Interop.dll + - - - - - - - + + + + + + - - + \ No newline at end of file diff --git a/src/ReactiveUI.Blazor/ReactiveUI.Blazor.csproj b/src/ReactiveUI.Blazor/ReactiveUI.Blazor.csproj index 109687840f..c5101cf79f 100644 --- a/src/ReactiveUI.Blazor/ReactiveUI.Blazor.csproj +++ b/src/ReactiveUI.Blazor/ReactiveUI.Blazor.csproj @@ -5,27 +5,12 @@ mvvm;reactiveui;rx;reactive extensions;observable;LINQ;eventsnet;netstandard;blazor;web; $(NoWarn);BL0007; - - + - - - - - - - - - - - - - - - + + - diff --git a/src/ReactiveUI.Blend/ReactiveUI.Blend.csproj b/src/ReactiveUI.Blend/ReactiveUI.Blend.csproj index d424bf5cd1..34ef945ac0 100644 --- a/src/ReactiveUI.Blend/ReactiveUI.Blend.csproj +++ b/src/ReactiveUI.Blend/ReactiveUI.Blend.csproj @@ -1,5 +1,4 @@  - net462;net472;net6.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net8.0-windows10.0.17763.0 ReactiveUI.Blend @@ -9,22 +8,18 @@ mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;Blend;wpf;net; true - - - - + - - + \ No newline at end of file diff --git a/src/ReactiveUI.Drawing/ReactiveUI.Drawing.csproj b/src/ReactiveUI.Drawing/ReactiveUI.Drawing.csproj index a141b3a168..7fba8e3276 100644 --- a/src/ReactiveUI.Drawing/ReactiveUI.Drawing.csproj +++ b/src/ReactiveUI.Drawing/ReactiveUI.Drawing.csproj @@ -7,32 +7,28 @@ A extension to the ReactiveUI platform that provides Splat bitmap operation support. ReactiveUI.Drawing 14.2 - 14.0 - 21.0 - 10.0.17763.0 - 10.0.17763.0 - 6.5 - - + 14.0 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + 6.5 + - - ..\Java.Interop.dll - + + ..\Java.Interop.dll + - - - - + - + \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs b/src/ReactiveUI.Fody.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs deleted file mode 100644 index 03ac0600aa..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Simplification; - -namespace TestHelper; - -/// -/// Diagnostic Producer class with extra methods dealing with applying code fixes -/// All methods are static. -/// -public abstract class CodeFixVerifier : DiagnosticVerifier -{ - /// - /// Apply the inputted CodeAction to the inputted document. - /// Meant to be used to apply code fixes. - /// - /// The Document to apply the fix on. - /// A CodeAction that will be applied to the Document. - /// A Document with the changes from the CodeAction. - private static Document? ApplyFix(Document document, CodeAction codeAction) - { - var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result; - var solution = operations.OfType().Single().ChangedSolution; - return solution.GetDocument(document.Id); - } - - /// - /// Compare two collections of Diagnostics,and return a list of any new diagnostics that appear only in the second collection. - /// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row, - /// this method may not necessarily return the new one. - /// - /// The Diagnostics that existed in the code before the CodeFix was applied. - /// The Diagnostics that exist in the code after the CodeFix was applied. - /// A list of Diagnostics that only surfaced in the code after the CodeFix was applied. - private static IEnumerable GetNewDiagnostics(IEnumerable diagnostics, IEnumerable newDiagnostics) - { - var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - var newArray = newDiagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - - var oldIndex = 0; - var newIndex = 0; - - while (newIndex < newArray.Length) - { - if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id) - { - ++oldIndex; - ++newIndex; - } - else - { - yield return newArray[newIndex++]; - } - } - } - - /// - /// Get the existing compiler diagnostics on the inputted document. - /// - /// The Document to run the compiler diagnostic analyzers on. - /// The compiler diagnostics that were found in the code. - private static IEnumerable GetCompilerDiagnostics(Document? document) => document?.GetSemanticModelAsync()?.Result?.GetDiagnostics() ?? Enumerable.Empty(); - - /// - /// Given a document, turn it into a string based on the syntax root. - /// - /// The Document to be converted to a string. - /// A string containing the syntax of the Document after formatting. - private static string GetStringFromDocument(Document document) - { - var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; - var root = simplifiedDoc.GetSyntaxRootAsync().Result; - - if (root is null) - { - throw new InvalidOperationException("The root node for the document is null."); - } - - root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace); - return root.GetText().ToString(); - } -} diff --git a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticResult.cs b/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticResult.cs deleted file mode 100644 index a79ee1a700..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticResult.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; - -using Microsoft.CodeAnalysis; - -namespace TestHelper; - -/// -/// Struct that stores information about a Diagnostic appearing in a source. -/// -public struct DiagnosticResult : IEquatable -{ - private IList _locations; - - /// - /// Gets or sets the locations of the Analysis Result. - /// - public IList Locations - { - get => _locations ??= Array.Empty(); - - set => _locations = value; - } - - /// - /// Gets or Sets Severity of the Analysis Result. - /// - public DiagnosticSeverity Severity { get; set; } - - /// - /// Gets or sets the Id of the Analysis Result. - /// - public string Id { get; set; } - - /// - /// Gets or sets the Analysis Result Message. - /// - public string Message { get; set; } - - /// - /// Gets the Path of the source file that caused the Analysis Result. - /// - public string Path => Locations.Count > 0 ? Locations[0].Path : string.Empty; - - /// - /// Gets the line number of the source that caused the Analysis Result. - /// - public int Line => Locations.Count > 0 ? Locations[0].Line : -1; - - /// - /// Gets the column number of the source that caused the Analysis Result. - /// - public int Column => Locations.Count > 0 ? Locations[0].Column : -1; - - /// - /// Performs equality against left and right. - /// - /// Left side to compare. - /// Right side to compare. - /// If the two values are equal. - public static bool operator ==(DiagnosticResult left, DiagnosticResult right) => left.Equals(right); - - /// - /// Performs inequality against left and right. - /// - /// Left side to compare. - /// Right side to compare. - /// If the two values are not equal. - public static bool operator !=(DiagnosticResult left, DiagnosticResult right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is DiagnosticResult result && Equals(result); - - /// - public bool Equals(DiagnosticResult other) => - EqualityComparer>.Default.Equals(_locations, other._locations) && - EqualityComparer>.Default.Equals(Locations, other.Locations) && - Severity == other.Severity && - Id == other.Id && - Message == other.Message && - Path == other.Path && - Line == other.Line && - Column == other.Column; - - /// - public override int GetHashCode() - { - var hashCode = 1054991603; - hashCode = (hashCode * -1521134295) + EqualityComparer>.Default.GetHashCode(_locations); - hashCode = (hashCode * -1521134295) + EqualityComparer>.Default.GetHashCode(Locations); - hashCode = (hashCode * -1521134295) + Severity.GetHashCode(); - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Id); - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Message); - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Path); - hashCode = (hashCode * -1521134295) + Line.GetHashCode(); - hashCode = (hashCode * -1521134295) + Column.GetHashCode(); - return hashCode; - } -} diff --git a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticResultLocation.cs b/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticResultLocation.cs deleted file mode 100644 index 1198c23d46..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticResultLocation.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; - -namespace TestHelper; - -/// -/// Location where the diagnostic appears, as determined by path, line number, and column number. -/// -public readonly struct DiagnosticResultLocation : IEquatable -{ - /// - /// Initializes a new instance of the struct. - /// - /// The Source File where the issues exists. - /// The line number of the result. - /// The column of the Result. - public DiagnosticResultLocation(string path, int line, int column) - { - if (line < -1) - { - throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); - } - - if (column < -1) - { - throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); - } - - Path = path; - Line = line; - Column = column; - } - - /// - /// Gets Path of the source file, which has issues. - /// - public string Path { get; } - - /// - /// Gets the line number of the issue. - /// - public int Line { get; } - - /// - /// Gets the columns of the issue. - /// - public int Column { get; } - - /// - /// Compares two DiagnosticResultLocation for Equality. - /// - /// Left. - /// Right. - /// Are Equal. - public static bool operator ==(DiagnosticResultLocation left, DiagnosticResultLocation right) => left.Equals(right); - - /// - /// Implements the operator !=. - /// - /// The left. - /// The right. - /// - /// The result of the operator. - /// - public static bool operator !=(DiagnosticResultLocation left, DiagnosticResultLocation right) => !left.Equals(right); - - /// - /// Compares two DiagnosticResultLocation for Equality. - /// - /// Other object to compare to. - /// Are Equal. - public bool Equals(DiagnosticResultLocation other) => string.Equals(Path, other.Path, StringComparison.InvariantCultureIgnoreCase) && Line == other.Line && Column == other.Column; - - /// - /// Compares two DiagnosticResultLocation for Equality. - /// - /// Other object to compare to. - /// Are Equal. - public override bool Equals(object? obj) => obj is DiagnosticResultLocation other && Equals(other); - - /// - /// Gets HashCode. - /// - /// HashCode. - public override int GetHashCode() - { - unchecked - { - var hashCode = Path is not null ? Path.GetHashCode() : 0; - hashCode = (hashCode * 397) ^ Line; - hashCode = (hashCode * 397) ^ Column; - return hashCode; - } - } -} diff --git a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs b/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs deleted file mode 100644 index 3a99841838..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Text; - -using ReactiveUI; -using ReactiveUI.Fody.Helpers; - -namespace TestHelper; - -/// -/// Class for turning strings into documents and getting the diagnostics on them -/// All methods are static. -/// -public abstract partial class DiagnosticVerifier -{ - private const string DefaultFilePathPrefix = "Test"; - private const string CSharpDefaultFileExt = "cs"; - private const string VisualBasicDefaultExt = "vb"; - private const string TestProjectName = "TestProject"; - private static readonly MetadataReference CorlibReference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); - private static readonly MetadataReference SystemCoreReference = MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location); - private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location); - private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); - private static readonly MetadataReference ReactiveUi = MetadataReference.CreateFromFile(typeof(IReactiveObject).Assembly.Location); - private static readonly MetadataReference ReactiveUiHelper = MetadataReference.CreateFromFile(typeof(ReactiveAttribute).Assembly.Location); - - /// - /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. - /// The returned diagnostics are then ordered by location in the source document. - /// - /// The analyzer to run on the documents. - /// The Documents that the analyzer will be run on. - /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location. - protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(documents); -#else - if (documents is null) - { - throw new ArgumentNullException(nameof(documents)); - } -#endif - - var projects = new HashSet(); - foreach (var document in documents) - { - projects.Add(document.Project); - } - - var diagnostics = new List(); - foreach (var project in projects) - { - var compilationWithAnalyzers = project.GetCompilationAsync().Result?.WithAnalyzers([analyzer]); - var currentDiagnostics = compilationWithAnalyzers?.GetAnalyzerDiagnosticsAsync().Result; - - if (currentDiagnostics is null) - { - continue; - } - - foreach (var diagnostic in currentDiagnostics) - { - if (diagnostic.Location == Location.None || diagnostic.Location.IsInMetadata) - { - diagnostics.Add(diagnostic); - } - else - { - foreach (var document in documents) - { - var tree = document.GetSyntaxTreeAsync().Result; - if (tree == diagnostic.Location.SourceTree) - { - diagnostics.Add(diagnostic); - } - } - } - } - } - - var results = SortDiagnostics(diagnostics); - diagnostics.Clear(); - return results; - } - - /// - /// Create a Document from a string through creating a project that contains it. - /// - /// Classes in the form of a string. - /// The language the source code is in. - /// A Document created from the source string. - protected static Document? CreateDocument(string source, string language = LanguageNames.CSharp) => CreateProject([source], language)?.Documents.First(); - - /// - /// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. - /// - /// Classes in the form of strings. - /// The language the source classes are in. - /// The analyzer to be run on the sources. - /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location. - private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) => GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); - - /// - /// Sort diagnostics by location in source document. - /// - /// The list of Diagnostics to be sorted. - /// An IEnumerable containing the Diagnostics in order of Location. - private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) => diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - - /// - /// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it. - /// - /// Classes in the form of strings. - /// The language the source code is in. - /// A Tuple containing the Documents produced from the sources and their TextSpans if relevant. - private static Document[] GetDocuments(string[] sources, string language) - { - if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic) - { - throw new ArgumentException("Unsupported Language"); - } - - var project = CreateProject(sources, language); - var documents = project?.Documents.ToArray() ?? []; - - if (sources.Length != documents.Length) - { - throw new InvalidOperationException("Amount of sources did not match amount of Documents created"); - } - - return documents; - } - - /// - /// Create a project using the inputted strings as sources. - /// - /// Classes in the form of strings. - /// The language the source code is in. - /// A Project created out of the Documents created from the source strings. - private static Project? CreateProject(string[] sources, string language = LanguageNames.CSharp) - { - const string fileNamePrefix = DefaultFilePathPrefix; - var fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt; - - var projectId = ProjectId.CreateNewId(debugName: TestProjectName); - - var solution = new AdhocWorkspace() - .CurrentSolution - .AddProject(projectId, TestProjectName, TestProjectName, language) - .AddMetadataReference(projectId, CorlibReference) - .AddMetadataReference(projectId, SystemCoreReference) - .AddMetadataReference(projectId, CSharpSymbolsReference) - .AddMetadataReference(projectId, CodeAnalysisReference) - .AddMetadataReference(projectId, ReactiveUi) - .AddMetadataReference(projectId, ReactiveUiHelper); - - var count = 0; - foreach (var source in sources) - { - var newFileName = fileNamePrefix + count + "." + fileExt; - var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); - solution = solution.AddDocument(documentId, newFileName, SourceText.From(source)); - count++; - } - - return solution.GetProject(projectId); - } -} diff --git a/src/ReactiveUI.Fody.Analyzer.Test/ReactiveObjectAnalyzerTest.cs b/src/ReactiveUI.Fody.Analyzer.Test/ReactiveObjectAnalyzerTest.cs deleted file mode 100644 index efbab3733a..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/ReactiveObjectAnalyzerTest.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace ReactiveUI.Fody.Analyzer.Test; - -/// -/// Unit Tests to check the proper operation of ReactiveObjectAnalyzer. -/// -public class ReactiveObjectAnalyzerTest : DiagnosticVerifier -{ - /// - /// Unit Test to ensure that we do not flag an empty file with errors. - /// - [Fact(Skip = "An issue has been introduced when running fody in the cloud")] - public void CheckEmptyFileReturnsNoFailures() - { - var test = string.Empty; - VerifyCSharpDiagnostic(test); - } - - /// - /// Check that a class which does not implement IReactiveObject throws an error, when it uses - /// the [Reactive] attribute in one of its properties. - /// - [Fact(Skip = "An issue has been introduced when running fody in the cloud")] - public void ShouldGiveAnErrorWhenClassDoesNotImplement() - { - const string test = @" - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using System.Diagnostics; - using ReactiveUI; - using ReactiveUI.Fody.Helpers; - - namespace ConsoleApplication1 - { - public class TypeName - { - [Reactive] public string Prop { get; set; } - } - }"; - - var expected = new DiagnosticResult - { - Id = "RUI_0001", - Message = "Type 'TypeName' does not implement IReactiveObject", - Severity = DiagnosticSeverity.Error, - Locations = - new[] { new DiagnosticResultLocation("Test0.cs", 15, 14) } - }; - VerifyCSharpDiagnostic(test, expected); - } - - /// - /// Check that a class which does inherits ReactiveObject does not throw - /// an error, when it uses the [Reactive] attribute in one of its properties. - /// - [Fact(Skip = "An issue has been introduced when running fody in the cloud")] - public void ShouldNotGiveAnErrorWhenClassInherits() - { - const string test = @" - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using System.Diagnostics; - using ReactiveUI; - using ReactiveUI.Fody.Helpers; - - namespace ConsoleApplication1 - { - public class TypeName : ReactiveObject - { - [Reactive] public string Prop { get; set; } - } - }"; - VerifyCSharpDiagnostic(test); - } - - /// - /// Check that a class which does implements IReactiveObject does not throw - /// an error, when it uses the [Reactive] attribute in one of its properties. - /// - [Fact(Skip = "An issue has been introduced when running fody in the cloud")] - public void ShouldNotGiveAnErrorWhenClassImplements() - { - const string test = @" - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using System.Diagnostics; - using ReactiveUI; - using ReactiveUI.Fody.Helpers; - - namespace ConsoleApplication1 - { - public class TypeName : IReactiveObject - { - [Reactive] public string Prop { get; set; } - } - }"; - VerifyCSharpDiagnostic(test); - } - - /// - /// Check that a class should not be allowed to have a non-auto-property - /// when used with the [Reactive] attribute. - /// - [Fact(Skip = "An issue has been introduced when running fody in the cloud")] - public void ShouldGiveErrorForNonAutoProperty() - { - const string test = @" - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using System.Diagnostics; - using ReactiveUI; - using ReactiveUI.Fody.Helpers; - - namespace ConsoleApplication1 - { - public class TypeName : IReactiveObject - { - [Reactive] public string Prop - { - get => _prop; - set => _prop = value; - } - private string _prop; - } - }"; - - var expected = new DiagnosticResult - { - Id = "RUI_0002", - Message = "Property 'Prop' on 'TypeName' should be an auto property", - Severity = DiagnosticSeverity.Error, - Locations = - new[] { new DiagnosticResultLocation("Test0.cs", 15, 14) } - }; - VerifyCSharpDiagnostic(test, expected); - } - - /// - /// Returns the Roslyn Analyzer under test. - /// - /// ReactiveObjectAnalyzer. - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() => new ReactiveObjectAnalyzer(); -} diff --git a/src/ReactiveUI.Fody.Analyzer.Test/ReactiveUI.Fody.Analyzer.Tests.csproj b/src/ReactiveUI.Fody.Analyzer.Test/ReactiveUI.Fody.Analyzer.Tests.csproj deleted file mode 100644 index 225e1c4d7f..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/ReactiveUI.Fody.Analyzer.Tests.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - net472;net6.0 - false - $(NoWarn);MSB3243 - - - - - - - - - - - - - - - diff --git a/src/ReactiveUI.Fody.Analyzer.Test/Verifiers/DiagnosticVerifier.cs b/src/ReactiveUI.Fody.Analyzer.Test/Verifiers/DiagnosticVerifier.cs deleted file mode 100644 index 277ccd1706..0000000000 --- a/src/ReactiveUI.Fody.Analyzer.Test/Verifiers/DiagnosticVerifier.cs +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; - -using Xunit; - -namespace TestHelper; - -/// -/// Superclass of all Unit Tests for DiagnosticAnalyzers. -/// -public abstract partial class DiagnosticVerifier -{ - /// - /// Get the CSharp analyzer being tested - to be implemented in non-abstract class. - /// - /// DiagnosticAnalyzer to be tested. - protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() => null!; - - /// - /// Get the Visual Basic analyzer being tested (C#) - to be implemented in non-abstract class. - /// - /// DiagnosticAnalyzer to be tested. - protected virtual DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() => null!; - - /// - /// Called to test a C# DiagnosticAnalyzer when applied on the single inputted string as a source - /// Note: input a DiagnosticResult for each Diagnostic expected. - /// - /// A class in the form of a string to run the analyzer on. - /// DiagnosticResults that should appear after the analyzer is run on the source. - protected void VerifyCSharpDiagnostic(string source, params DiagnosticResult[] expected) => VerifyDiagnostics([source], LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); - - /// - /// Called to test a VB DiagnosticAnalyzer when applied on the single inputted string as a source - /// Note: input a DiagnosticResult for each Diagnostic expected. - /// - /// A class in the form of a string to run the analyzer on. - /// DiagnosticResults that should appear after the analyzer is run on the source. - protected void VerifyBasicDiagnostic(string source, params DiagnosticResult[] expected) => VerifyDiagnostics([source], LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); - - /// - /// Called to test a C# DiagnosticAnalyzer when applied on the inputted strings as a source - /// Note: input a DiagnosticResult for each Diagnostic expected. - /// - /// An array of strings to create source documents from to run the analyzers on. - /// DiagnosticResults that should appear after the analyzer is run on the sources. - protected void VerifyCSharpDiagnostic(string[] sources, params DiagnosticResult[] expected) => VerifyDiagnostics(sources, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); - - /// - /// Called to test a VB DiagnosticAnalyzer when applied on the inputted strings as a source - /// Note: input a DiagnosticResult for each Diagnostic expected. - /// - /// An array of strings to create source documents from to run the analyzers on. - /// DiagnosticResults that should appear after the analyzer is run on the sources. - protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[] expected) => VerifyDiagnostics(sources, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); - - /// - /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. - /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. - /// - /// The Diagnostics found by the compiler after running the analyzer on the source code. - /// The analyzer that was being run on the sources. - /// Diagnostic Results that should have appeared in the code. - private static void VerifyDiagnosticResults(IEnumerable actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) - { - var expectedCount = expectedResults.Length; - var actualCountList = actualResults.ToList(); - var actualCount = actualCountList.Count; - - if (expectedCount != actualCount) - { - var diagnosticsOutput = actualCountList.Count > 0 ? FormatDiagnostics(analyzer, actualCountList.ToArray()) : " NONE."; - - Assert.True( - false, - $"Mismatch between number of diagnostics returned, expected \"{expectedCount}\" actual \"{actualCount}\"\r\n\r\nDiagnostics:\r\n{diagnosticsOutput}\r\n"); - } - - for (var i = 0; i < expectedResults.Length; i++) - { - var actual = actualCountList[i]; - var expected = expectedResults[i]; - - if (expected.Line == -1 && expected.Column == -1) - { - if (actual.Location != Location.None) - { - Assert.True( - false, - $"Expected:\nA project diagnostic with No location\nActual:\n{FormatDiagnostics(analyzer, actual)}"); - } - } - else - { - VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First()); - var additionalLocations = actual.AdditionalLocations.ToArray(); - - if (additionalLocations.Length != expected.Locations.Count - 1) - { - Assert.True( - false, - $"Expected {expected.Locations.Count - 1} additional locations but got {additionalLocations.Length} for Diagnostic:\r\n {FormatDiagnostics(analyzer, actual)}\r\n"); - } - - for (var j = 0; j < additionalLocations.Length; ++j) - { - VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); - } - } - - if (actual.Id != expected.Id) - { - Assert.True( - false, - $"Expected diagnostic id to be \"{expected.Id}\" was \"{actual.Id}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, actual)}\r\n"); - } - - if (actual.Severity != expected.Severity) - { - Assert.True( - false, - $"Expected diagnostic severity to be \"{expected.Severity}\" was \"{actual.Severity}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, actual)}\r\n"); - } - - if (actual.GetMessage() != expected.Message) - { - Assert.True( - false, - $"Expected diagnostic message to be \"{expected.Message}\" was \"{actual.GetMessage()}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, actual)}\r\n"); - } - } - } - - /// - /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. - /// - /// The analyzer that was being run on the sources. - /// The diagnostic that was found in the code. - /// The Location of the Diagnostic found in the code. - /// The DiagnosticResultLocation that should have been found. - private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) - { - var actualSpan = actual.GetLineSpan(); - - Assert.True( - actualSpan.Path == expected.Path || (actualSpan.Path is not null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), - $"Expected diagnostic to be in file \"{expected.Path}\" was actually in file \"{actualSpan.Path}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); - - var actualLinePosition = actualSpan.StartLinePosition; - - // Only check line position if there is an actual line in the real diagnostic - if (actualLinePosition.Line > 0) - { - if (actualLinePosition.Line + 1 != expected.Line) - { - Assert.True( - false, - $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); - } - } - - // Only check column position if there is an actual column position in the real diagnostic - if (actualLinePosition.Character > 0) - { - if (actualLinePosition.Character + 1 != expected.Column) - { - Assert.True( - false, - $"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); - } - } - } - - /// - /// Helper method to format a Diagnostic into an easily readable string. - /// - /// The analyzer that this verifier tests. - /// The Diagnostics to be formatted. - /// The Diagnostics formatted as a string. - private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diagnostic[] diagnostics) - { - var builder = new StringBuilder(); - for (var i = 0; i < diagnostics.Length; ++i) - { - builder.Append("// ").AppendLine(diagnostics[i].ToString()); - - var analyzerType = analyzer.GetType(); - var rules = analyzer.SupportedDiagnostics; - - foreach (var rule in rules) - { - if (rule is not null && rule.Id == diagnostics[i].Id) - { - var location = diagnostics[i].Location; - if (location == Location.None) - { - builder.AppendFormat(CultureInfo.InvariantCulture, "GetGlobalResult({0}.{1})", analyzerType.Name, rule.Id); - } - else - { - Assert.True( - location.IsInSource, - $"Test base does not currently handle diagnostics in metadata locations. Diagnostic in metadata: {diagnostics[i]}\r\n"); - - var resultMethodName = diagnostics[i].Location.SourceTree!.FilePath.EndsWith(".cs", StringComparison.Ordinal) ? "GetCSharpResultAt" : "GetBasicResultAt"; - var linePosition = diagnostics[i].Location.GetLineSpan().StartLinePosition; - - builder.Append(resultMethodName).Append('(').Append(linePosition.Line + 1).Append(", ").Append(linePosition.Character + 1).Append(", ").Append(analyzerType.Name).Append('.').Append(rule.Id).Append(')'); - } - - if (i != diagnostics.Length - 1) - { - builder.Append(','); - } - - builder.AppendLine(); - break; - } - } - } - - return builder.ToString(); - } - - /// - /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, - /// then verifies each of them. - /// - /// An array of strings to create source documents from to run the analyzers on. - /// The language of the classes represented by the source strings. - /// The analyzer to be run on the source code. - /// DiagnosticResults that should appear after the analyzer is run on the sources. - private static void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) - { - var diagnostics = GetSortedDiagnostics(sources, language, analyzer); - VerifyDiagnosticResults(diagnostics, analyzer, expected); - } -} diff --git a/src/ReactiveUI.Fody.Analyzer/AnalyzerReleases.Shipped.md b/src/ReactiveUI.Fody.Analyzer/AnalyzerReleases.Shipped.md deleted file mode 100644 index d567f14248..0000000000 --- a/src/ReactiveUI.Fody.Analyzer/AnalyzerReleases.Shipped.md +++ /dev/null @@ -1,3 +0,0 @@ -; Shipped analyzer releases -; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md - diff --git a/src/ReactiveUI.Fody.Analyzer/AnalyzerReleases.Unshipped.md b/src/ReactiveUI.Fody.Analyzer/AnalyzerReleases.Unshipped.md deleted file mode 100644 index 6cedf63361..0000000000 --- a/src/ReactiveUI.Fody.Analyzer/AnalyzerReleases.Unshipped.md +++ /dev/null @@ -1,8 +0,0 @@ -; Unshipped analyzer release -; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md - -### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------- -RUI_0001 | Fody | Error | ReactiveObjectAnalyzer -RUI_0002 | Fody | Error | ReactiveObjectAnalyzer \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Analyzer/ReactiveObjectAnalyzer.cs b/src/ReactiveUI.Fody.Analyzer/ReactiveObjectAnalyzer.cs deleted file mode 100644 index 55b96915ed..0000000000 --- a/src/ReactiveUI.Fody.Analyzer/ReactiveObjectAnalyzer.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace ReactiveUI.Fody.Analyzer; - -/// -/// Roslyn Analyzer to check validity of ReactiveObjects. -/// -[DiagnosticAnalyzer(LanguageNames.CSharp)] -public class ReactiveObjectAnalyzer : DiagnosticAnalyzer -{ - // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat. - // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md for more on localization - private static readonly DiagnosticDescriptor InheritanceRule = new( - "RUI_0001", - "Type must implement IReactiveObject", - "Type '{0}' does not implement IReactiveObject", - "Fody", - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: "[Reactive] may only be applied to a IReactiveObject."); - - private static readonly DiagnosticDescriptor AutoPropertyRule = new( - "RUI_0002", - "[Reactive] properties should be an auto property", - "Property '{0}' on '{1}' should be an auto property", - "Fody", - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: "[Reactive] properties should be an auto property."); - - /// - /// Gets checks that this Analyzer supports. - /// - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(InheritanceRule, AutoPropertyRule); - - /// - /// Initializes the AnalysisContext. - /// - /// The Roslyn Context. - public override void Initialize(AnalysisContext context) - { -#if NET6_0_OR_GREATER - System.ArgumentNullException.ThrowIfNull(context); -#else - if (context is null) - { - throw new System.ArgumentNullException(nameof(context)); - } -#endif - - context.EnableConcurrentExecution(); - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - - // TODO: Consider registering other actions that act on syntax instead of or in addition to symbols - // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Analyzer%20Actions%20Semantics.md for more information - context.RegisterSyntaxNodeAction(AnalyzeAttribute, SyntaxKind.Attribute); - } - - private static void AnalyzeAttribute(SyntaxNodeAnalysisContext context) - { - var attr = context.ContainingSymbol? - .GetAttributes() - .FirstOrDefault(a => a.ApplicationSyntaxReference!.Span == context.Node.Span); - - if (attr?.AttributeClass?.ToDisplayString() != "ReactiveUI.Fody.Helpers.ReactiveAttribute") - { - return; - } - - if (context.Node.Parent?.Parent is not PropertyDeclarationSyntax property) - { - return; - } - - if (context.ContainingSymbol is not null) - { - var reactiveObject = context.ContainingSymbol.ContainingType; - if (!reactiveObject.AllInterfaces.Any(interfaceTypeSymbol => interfaceTypeSymbol.ToDisplayString() == "ReactiveUI.IReactiveObject")) - { - context.ReportDiagnostic( - Diagnostic.Create( - InheritanceRule, - context.Node.GetLocation(), - reactiveObject.Name)); - } - } - - if (HasBackingField(property)) - { - var propertySymbol = context.ContainingSymbol; - if (propertySymbol is not null) - { - context.ReportDiagnostic( - Diagnostic.Create( - AutoPropertyRule, - context.Node.GetLocation(), - propertySymbol.Name, - propertySymbol.ContainingType.Name)); - } - } - } - - private static bool HasBackingField(PropertyDeclarationSyntax property) - { - var getter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration)); - var setter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetAccessorDeclaration)); - - if (setter?.Body is null || getter?.Body is null) - { - return setter?.ExpressionBody is not null && getter?.ExpressionBody is not null; - } - - var setterHasBodyStatements = setter.Body.Statements.Any(); - var getterHasBodyStatements = getter.Body.Statements.Any(); - - return setterHasBodyStatements && getterHasBodyStatements; - } -} diff --git a/src/ReactiveUI.Fody.Analyzer/ReactiveUI.Fody.Analyzer.csproj b/src/ReactiveUI.Fody.Analyzer/ReactiveUI.Fody.Analyzer.csproj deleted file mode 100644 index d8735a8c99..0000000000 --- a/src/ReactiveUI.Fody.Analyzer/ReactiveUI.Fody.Analyzer.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - netstandard2.0;net6.0;net7.0;net8.0 - ReactiveUI.Fody.Analyzer - ReactiveUI.Fody.Analyzer - Rosyln extension that checks correct usage of the Fody extension. - mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;xamarin;android;ios;mac;forms;monodroid;monotouch;xamarin.android;xamarin.ios;xamarin.forms;xamarin.mac;xamarin.tvos;wpf;net;netstandard;net472;uwp;tizen;unoplatform;fody; - False - true - - - - - - - - - diff --git a/src/ReactiveUI.Fody.Helpers/ObservableAsPropertyAttribute.cs b/src/ReactiveUI.Fody.Helpers/ObservableAsPropertyAttribute.cs deleted file mode 100644 index 1e0cc0d904..0000000000 --- a/src/ReactiveUI.Fody.Helpers/ObservableAsPropertyAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; - -namespace ReactiveUI.Fody.Helpers; - -/// -/// Attribute that marks an ObservableAsPropertyHelper for weaving. -/// -/// -[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] -public sealed class ObservableAsPropertyAttribute : Attribute -{ -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Helpers/ObservableAsPropertyExtensions.cs b/src/ReactiveUI.Fody.Helpers/ObservableAsPropertyExtensions.cs deleted file mode 100644 index 02816c7226..0000000000 --- a/src/ReactiveUI.Fody.Helpers/ObservableAsPropertyExtensions.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq.Expressions; -using System.Reactive.Concurrency; -using System.Reflection; - -namespace ReactiveUI.Fody.Helpers; - -/// -/// Extension methods for observable as property helpers. -/// -public static class ObservableAsPropertyExtensions -{ - /// - /// To the property execute. - /// - /// The type of the object. - /// The type of the ret. - /// The observable with the return value. - /// The source. - /// The property. - /// if set to true [defer subscription]. - /// The scheduler. - /// An observable property helper with the specified return value. - /// - /// Could not resolve expression " + property + " into a property. - /// or - /// Backing field not found for " + propertyInfo. - /// - public static ObservableAsPropertyHelper ToPropertyEx( - this IObservable item, - TObj source, - Expression> property, - bool deferSubscription = false, - IScheduler? scheduler = null) - where TObj : ReactiveObject - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(item); - ArgumentNullException.ThrowIfNull(property); -#else - if (item is null) - { - throw new ArgumentNullException(nameof(item)); - } - - if (property is null) - { - throw new ArgumentNullException(nameof(property)); - } -#endif - - var result = item.ToProperty(source, property, deferSubscription, scheduler); - - // Now assign the field via reflection. - var propertyInfo = property.GetPropertyInfo() ?? throw new Exception("Could not resolve expression " + property + " into a property."); - var field = propertyInfo.DeclaringType?.GetTypeInfo().GetDeclaredField("$" + propertyInfo.Name) ?? throw new Exception("Backing field not found for " + propertyInfo); - field.SetValue(source, result); - - return result; - } - - /// - /// To the property execute. - /// - /// The type of the object. - /// The type of the ret. - /// The observable with the return value. - /// The source. - /// The property. - /// The initial value. - /// if set to true [defer subscription]. - /// The scheduler. - /// An observable property helper with the specified return value. - /// - /// Could not resolve expression " + property + " into a property. - /// or - /// Backing field not found for " + propertyInfo. - /// - public static ObservableAsPropertyHelper ToPropertyEx( - this IObservable item, - TObj source, - Expression> property, - TRet initialValue, - bool deferSubscription = false, - IScheduler? scheduler = null) - where TObj : ReactiveObject - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(item); - ArgumentNullException.ThrowIfNull(property); -#else - if (item is null) - { - throw new ArgumentNullException(nameof(item)); - } - - if (property is null) - { - throw new ArgumentNullException(nameof(property)); - } -#endif - - var result = item.ToProperty(source, property, initialValue, deferSubscription, scheduler); - - // Now assign the field via reflection. - var propertyInfo = property.GetPropertyInfo() ?? throw new Exception("Could not resolve expression " + property + " into a property."); - var field = propertyInfo.DeclaringType?.GetTypeInfo().GetDeclaredField("$" + propertyInfo.Name) ?? throw new Exception("Backing field not found for " + propertyInfo); - field.SetValue(source, result); - - return result; - } - - private static PropertyInfo GetPropertyInfo(this LambdaExpression expression) - { - var current = expression.Body; - if (current is UnaryExpression unary) - { - current = unary.Operand; - } - - var call = (MemberExpression)current; - return (PropertyInfo)call.Member; - } -} diff --git a/src/ReactiveUI.Fody.Helpers/Properties/AssemblyInfo.cs b/src/ReactiveUI.Fody.Helpers/Properties/AssemblyInfo.cs deleted file mode 100644 index 4700ec8817..0000000000 --- a/src/ReactiveUI.Fody.Helpers/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("ReactiveUI.Tests")] -[assembly: InternalsVisibleTo("ReactiveUI.Winforms")] -[assembly: InternalsVisibleTo("ReactiveUI.Wpf")] -[assembly: InternalsVisibleTo("ReactiveUI.XamForms")] -[assembly: InternalsVisibleTo("ReactiveUI.AndroidSupport")] diff --git a/src/ReactiveUI.Fody.Helpers/ReactiveAttribute.cs b/src/ReactiveUI.Fody.Helpers/ReactiveAttribute.cs deleted file mode 100644 index 49821559c1..0000000000 --- a/src/ReactiveUI.Fody.Helpers/ReactiveAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; - -namespace ReactiveUI.Fody.Helpers; - -/// -/// Attribute that marks property for INotifyPropertyChanged weaving. -/// -/// -[AttributeUsage(AttributeTargets.Property)] -public sealed class ReactiveAttribute : Attribute -{ -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Helpers/ReactiveDependencyAttribute.cs b/src/ReactiveUI.Fody.Helpers/ReactiveDependencyAttribute.cs deleted file mode 100644 index 371a353f0e..0000000000 --- a/src/ReactiveUI.Fody.Helpers/ReactiveDependencyAttribute.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; - -namespace ReactiveUI.Fody.Helpers; - -/// -/// Attribute that marks a property as a Reactive Dependency. -/// -/// -/// -/// Initializes a new instance of the class. -/// -/// Name of the target. -[AttributeUsage(AttributeTargets.Property)] -public sealed class ReactiveDependencyAttribute(string targetName) : Attribute -{ - /// - /// Gets the name of the backing property. - /// - public string Target { get; } = targetName; - - /// - /// Gets or sets the target property on the backing property. - /// - public string? TargetProperty { get; set; } -} diff --git a/src/ReactiveUI.Fody.Helpers/ReactiveUI.Fody.Helpers.csproj b/src/ReactiveUI.Fody.Helpers/ReactiveUI.Fody.Helpers.csproj deleted file mode 100644 index a0e6601084..0000000000 --- a/src/ReactiveUI.Fody.Helpers/ReactiveUI.Fody.Helpers.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - netstandard2.0;net6.0;net7.0;net8.0;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10;MonoAndroid13.0 - $(TargetFrameworks);net462;net472 - Fody extension to generate RaisePropertyChange notifications for properties and ObservableAsPropertyHelper properties. - mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;xamarin;android;ios;mac;forms;monodroid;monotouch;xamarin.android;xamarin.ios;xamarin.forms;xamarin.mac;xamarin.tvos;wpf;net;netstandard;net472;uwp;tizen;unoplatform;fody; - - - ReactiveUI.Fody - ..\$(PackageId)\bin\$(Configuration)\ - False - - - - - - - - - - - - diff --git a/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.ReactiveUIFody.DotNet6_0.verified.txt b/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.ReactiveUIFody.DotNet6_0.verified.txt deleted file mode 100644 index 591b73b116..0000000000 --- a/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.ReactiveUIFody.DotNet6_0.verified.txt +++ /dev/null @@ -1,33 +0,0 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AndroidSupport")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Tests")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Winforms")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Wpf")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.XamForms")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] -namespace ReactiveUI.Fody.Helpers -{ - [System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Property)] - public sealed class ObservableAsPropertyAttribute : System.Attribute - { - public ObservableAsPropertyAttribute() { } - } - public static class ObservableAsPropertyExtensions - { - public static ReactiveUI.ObservableAsPropertyHelper ToPropertyEx(this System.IObservable item, TObj source, System.Linq.Expressions.Expression> property, bool deferSubscription = false, System.Reactive.Concurrency.IScheduler? scheduler = null) - where TObj : ReactiveUI.ReactiveObject { } - public static ReactiveUI.ObservableAsPropertyHelper ToPropertyEx(this System.IObservable item, TObj source, System.Linq.Expressions.Expression> property, TRet initialValue, bool deferSubscription = false, System.Reactive.Concurrency.IScheduler? scheduler = null) - where TObj : ReactiveUI.ReactiveObject { } - } - [System.AttributeUsage(System.AttributeTargets.Property)] - public sealed class ReactiveAttribute : System.Attribute - { - public ReactiveAttribute() { } - } - [System.AttributeUsage(System.AttributeTargets.Property)] - public sealed class ReactiveDependencyAttribute : System.Attribute - { - public ReactiveDependencyAttribute(string targetName) { } - public string Target { get; } - public string? TargetProperty { get; set; } - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.ReactiveUIFody.Net4_7.verified.txt b/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.ReactiveUIFody.Net4_7.verified.txt deleted file mode 100644 index 20ec941c3a..0000000000 --- a/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.ReactiveUIFody.Net4_7.verified.txt +++ /dev/null @@ -1,33 +0,0 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AndroidSupport")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Tests")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Winforms")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Wpf")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.XamForms")] -[assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName=".NET Framework 4.7.2")] -namespace ReactiveUI.Fody.Helpers -{ - [System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Property)] - public sealed class ObservableAsPropertyAttribute : System.Attribute - { - public ObservableAsPropertyAttribute() { } - } - public static class ObservableAsPropertyExtensions - { - public static ReactiveUI.ObservableAsPropertyHelper ToPropertyEx(this System.IObservable item, TObj source, System.Linq.Expressions.Expression> property, bool deferSubscription = false, System.Reactive.Concurrency.IScheduler? scheduler = null) - where TObj : ReactiveUI.ReactiveObject { } - public static ReactiveUI.ObservableAsPropertyHelper ToPropertyEx(this System.IObservable item, TObj source, System.Linq.Expressions.Expression> property, TRet initialValue, bool deferSubscription = false, System.Reactive.Concurrency.IScheduler? scheduler = null) - where TObj : ReactiveUI.ReactiveObject { } - } - [System.AttributeUsage(System.AttributeTargets.Property)] - public sealed class ReactiveAttribute : System.Attribute - { - public ReactiveAttribute() { } - } - [System.AttributeUsage(System.AttributeTargets.Property)] - public sealed class ReactiveDependencyAttribute : System.Attribute - { - public ReactiveDependencyAttribute(string targetName) { } - public string Target { get; } - public string? TargetProperty { get; set; } - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.cs b/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.cs deleted file mode 100644 index 4fe4d74f1c..0000000000 --- a/src/ReactiveUI.Fody.Tests/API/ApiApprovalTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; -using ReactiveUI.Fody.Helpers; -using ReactiveUI.Tests; -using Xunit; - -namespace ReactiveUI.Fody.Tests.API; - -/// -/// Tests for checking if the Fody public API is not changing. -/// We have a file checked into the repository with the approved public API. -/// If it is changing you'll need to override to make it obvious the API has changed -/// for version changing reasons. -/// -[ExcludeFromCodeCoverage] -public class ApiApprovalTests -{ - /// - /// Checks the version API. - /// - /// A task to monitor the process. - [Fact] - public Task ReactiveUIFody() => typeof(ReactiveAttribute).Assembly.CheckApproval(["ReactiveUI"]); -} diff --git a/src/ReactiveUI.Fody.Tests/ApiExtensions.cs b/src/ReactiveUI.Fody.Tests/ApiExtensions.cs deleted file mode 100644 index 9b65359686..0000000000 --- a/src/ReactiveUI.Fody.Tests/ApiExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using PublicApiGenerator; -using VerifyXunit; - -namespace ReactiveUI.Tests; - -/// -/// A helper for doing API approvals. -/// -[ExcludeFromCodeCoverage] -public static class ApiExtensions -{ - /// - /// Checks to make sure the API is approved. - /// - /// The assembly that is being checked. - /// The namespaces. - /// The caller file path. - /// - /// A Task. - /// - public static async Task CheckApproval(this Assembly assembly, string[] namespaces, [CallerFilePath] string filePath = "") - { - var generatorOptions = new ApiGeneratorOptions { AllowNamespacePrefixes = namespaces }; - var apiText = assembly.GeneratePublicApi(generatorOptions); - var result = await Verifier.Verify(apiText, null, filePath) - .UniqueForRuntimeAndVersion() - .ScrubEmptyLines() - .ScrubLines(l => - l.StartsWith("[assembly: AssemblyVersion(", StringComparison.InvariantCulture) || - l.StartsWith("[assembly: AssemblyFileVersion(", StringComparison.InvariantCulture) || - l.StartsWith("[assembly: AssemblyInformationalVersion(", StringComparison.InvariantCulture) || - l.StartsWith("[assembly: System.Reflection.AssemblyMetadata(", StringComparison.InvariantCulture)); - } -} diff --git a/src/ReactiveUI.Fody.Tests/FodyWeavers.xml b/src/ReactiveUI.Fody.Tests/FodyWeavers.xml deleted file mode 100644 index a1ede75480..0000000000 --- a/src/ReactiveUI.Fody.Tests/FodyWeavers.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/src/ReactiveUI.Fody.Tests/FodyWeavers.xsd b/src/ReactiveUI.Fody.Tests/FodyWeavers.xsd deleted file mode 100644 index 5cedd530b9..0000000000 --- a/src/ReactiveUI.Fody.Tests/FodyWeavers.xsd +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. - - - - - A comma-separated list of error codes that can be safely ignored in assembly verification. - - - - - 'false' to turn off automatic generation of the XML Schema file. - - - - - \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/Issues/ChainExpressionTests.cs b/src/ReactiveUI.Fody.Tests/Issues/ChainExpressionTests.cs deleted file mode 100644 index cb3d0b4eb5..0000000000 --- a/src/ReactiveUI.Fody.Tests/Issues/ChainExpressionTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Reactive.Linq; -using ReactiveUI.Fody.Helpers; -using Xunit; - -namespace ReactiveUI.Fody.Tests.Issues; - -/// -/// Tests for determining if a chain expression works. -/// -public class ChainExpressionTests -{ - /// - /// Checks to make sure that if double property chaining doesn't cause a exception. - /// - [Fact] - public void AccessingAChainedObservableAsPropertyOfDoubleDoesntThrow() - { - var vm = new TestModel(); - Assert.Equal(0.0, vm.P2); - } - - private class TestModel : ReactiveObject - { - public TestModel() - { - Observable.Return(0.0).ToPropertyEx(this, vm => vm.P1); - this.WhenAnyValue(vm => vm.P1).ToPropertyEx(this, vm => vm.P2); - } - - [ObservableAsProperty] - public double P1 { get; } - - [ObservableAsProperty] - public double P2 { get; } - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/Issues/ExternPropertyTests.cs b/src/ReactiveUI.Fody.Tests/Issues/ExternPropertyTests.cs deleted file mode 100644 index 62ce3c93dd..0000000000 --- a/src/ReactiveUI.Fody.Tests/Issues/ExternPropertyTests.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Reactive.Linq; - -using ReactiveUI.Fody.Helpers; - -using Xunit; - -namespace ReactiveUI.Fody.Tests.Issues; - -/// -/// Checks to make sure that extern properties work. -/// -public class ExternPropertyTests -{ - /// - /// Checks that observables passed as a parameter are supported. - /// - [Fact] - public void AllowObservableAsPropertyAttributeOnAccessor() - { - var model = new TestModel("foo"); - Assert.Equal("foo", model.MyProperty); - } - - private class TestModel : ReactiveObject - { - public TestModel(string myProperty) => Observable.Return(myProperty).ToPropertyEx(this, x => x.MyProperty); - - public extern string MyProperty - { - [ObservableAsProperty] - get; - } - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/Issues/NumericValueWorkTests.cs b/src/ReactiveUI.Fody.Tests/Issues/NumericValueWorkTests.cs deleted file mode 100644 index c5e74a28cd..0000000000 --- a/src/ReactiveUI.Fody.Tests/Issues/NumericValueWorkTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using FluentAssertions; - -using ReactiveUI.Fody.Helpers; - -namespace ReactiveUI.Fody.Tests.Issues; - -/// -/// A set of tests to make sure that they produce valid numeric values for different types. -/// -public static class NumericValueWorkTests -{ - /// - /// A test to make sure that all the default values are kept after generation. - /// - public static void KeepsDefaultValuesTest() - { - var testModel = new TestModel(); - - testModel.DoubleProperty.Should().Be(default); - testModel.IntProperty.Should().Be(default); - testModel.FloatProperty.Should().Be(default); - testModel.LongProperty.Should().Be(default); - } - - /// - /// The "test" here is simply for these to compile - /// Tests ObservableAsPropertyWeaver.EmitDefaultValue. - /// - private class TestModel : ReactiveObject - { - [ObservableAsProperty] - public int IntProperty { get; } - - [ObservableAsProperty] - public double DoubleProperty { get; } - - [ObservableAsProperty] - public float FloatProperty { get; } - - [ObservableAsProperty] - public long LongProperty { get; } - } -} diff --git a/src/ReactiveUI.Fody.Tests/Issues/UninitializedValuesWorkTests.cs b/src/ReactiveUI.Fody.Tests/Issues/UninitializedValuesWorkTests.cs deleted file mode 100644 index 278b6344fc..0000000000 --- a/src/ReactiveUI.Fody.Tests/Issues/UninitializedValuesWorkTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using ReactiveUI.Fody.Helpers; -using Xunit; - -namespace ReactiveUI.Fody.Tests.Issues; - -/// -/// Makes sure that uninitialized values, which don't have ToPropertyEx called work. -/// -public class UninitializedValuesWorkTests -{ - /// - /// Test to make sure that properties without PropertyHelper return the correct value. - /// - [Fact] - public void UninitializedObservableAsPropertyHelperDoesntThrowAndReturnsDefaultValue() - { - var model = new TestModel(); - Assert.Equal(null, model.MyProperty); - Assert.Equal(0, model.MyIntProperty); - Assert.Equal(default, model.MyDateTimeProperty); - } - - private class TestModel : ReactiveObject - { - public TestModel() => OtherProperty = MyProperty; - - [ObservableAsProperty] - public string? MyProperty { get; } - - [ObservableAsProperty] - public int MyIntProperty { get; } - - [ObservableAsProperty] - public DateTime MyDateTimeProperty { get; private set; } - - public string? OtherProperty { get; } - } -} diff --git a/src/ReactiveUI.Fody.Tests/Mocks/BaseModel.cs b/src/ReactiveUI.Fody.Tests/Mocks/BaseModel.cs deleted file mode 100644 index 5db178a223..0000000000 --- a/src/ReactiveUI.Fody.Tests/Mocks/BaseModel.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -namespace ReactiveUI.Fody.Tests; - -/// -/// A base model for the mocks. -/// -public class BaseModel : ReactiveObject -{ - /// - /// Gets or sets a integer property with a initial value. - /// - public virtual int IntProperty { get; set; } = 5; - - /// - /// Gets or sets a string property with a initial value. - /// - public virtual string? StringProperty { get; set; } = "Initial Value"; -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/Mocks/DecoratorModel.cs b/src/ReactiveUI.Fody.Tests/Mocks/DecoratorModel.cs deleted file mode 100644 index c4dd7540ae..0000000000 --- a/src/ReactiveUI.Fody.Tests/Mocks/DecoratorModel.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using ReactiveUI.Fody.Helpers; - -namespace ReactiveUI.Fody.Tests; - -/// -/// A view model that is decorated with rx fody attributes. -/// -public class DecoratorModel : BaseModel -{ - private readonly BaseModel _model; - - /// - /// Initializes a new instance of the class. - /// - public DecoratorModel() => _model = new(); - - /// - /// Initializes a new instance of the class. - /// - /// The base model which to do ReactiveDependency off. - public DecoratorModel(BaseModel baseModel) => _model = baseModel; - - /// - /// Gets or sets a property decorated with the ReactiveAttribute. - /// - [Reactive] - public string? SomeCoolNewProperty { get; set; } - - /// - /// Gets or sets a property decorated with the ReactiveDependencyAttribute. - /// - [ReactiveDependency(nameof(_model))] - public override string? StringProperty { get; set; } - - /// - /// Gets or sets a property which interacts with the base model. - /// - public override int IntProperty - { - get => _model.IntProperty * 2; - set - { - _model.IntProperty = value; - this.RaisePropertyChanged(); - } - } - - /// - /// Sets the string. This is independent of the fody generation. - /// - /// The new value to set. - public void UpdateCoolProperty(string coolNewProperty) => SomeCoolNewProperty = coolNewProperty; -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/Mocks/FacadeModel.cs b/src/ReactiveUI.Fody.Tests/Mocks/FacadeModel.cs deleted file mode 100644 index 51e9a660b8..0000000000 --- a/src/ReactiveUI.Fody.Tests/Mocks/FacadeModel.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using ReactiveUI.Fody.Helpers; - -namespace ReactiveUI.Fody.Tests; - -/// -/// A model which is facading another object. -/// -public class FacadeModel : ReactiveObject -{ - /// - /// Initializes a new instance of the class. - /// - public FacadeModel() => Dependency = new(); - - /// - /// Initializes a new instance of the class. - /// - /// The dependency to base again. - public FacadeModel(BaseModel dependency) => Dependency = dependency; - - /// - /// Gets the base dependency. - /// - public BaseModel Dependency { get; } - - /// - /// Gets or sets a property with the same name in the dependency. - /// - [ReactiveDependency(nameof(Dependency))] - public int IntProperty { get; set; } - - /// - /// Gets or sets a string value that will be generated to pass through and from the dependency. - /// - [ReactiveDependency(nameof(Dependency), TargetProperty = "StringProperty")] - public string? AnotherStringProperty { get; set; } -} diff --git a/src/ReactiveUI.Fody.Tests/Mocks/ObservableAsTestModel.cs b/src/ReactiveUI.Fody.Tests/Mocks/ObservableAsTestModel.cs deleted file mode 100644 index 2e6bb4077e..0000000000 --- a/src/ReactiveUI.Fody.Tests/Mocks/ObservableAsTestModel.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Reactive.Linq; -using ReactiveUI.Fody.Helpers; - -namespace ReactiveUI.Fody.Tests; - -/// -/// A test model for the ObservabeAsPropertyAttribute. -/// -public class ObservableAsTestModel : ReactiveObject -{ - /// - /// Initializes a new instance of the class. - /// - public ObservableAsTestModel() => Observable.Return("foo").ToPropertyEx(this, x => x.TestProperty); - - /// - /// Gets the test property which will reference our generated observable. - /// - [ObservableAsProperty] - public string? TestProperty { get; } -} diff --git a/src/ReactiveUI.Fody.Tests/ObservableAsPropertyTests.cs b/src/ReactiveUI.Fody.Tests/ObservableAsPropertyTests.cs deleted file mode 100644 index 9c7abc00e1..0000000000 --- a/src/ReactiveUI.Fody.Tests/ObservableAsPropertyTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Xunit; - -namespace ReactiveUI.Fody.Tests; - -/// -/// Tests for the ObservableAsPropertyAttribute. -/// -public class ObservableAsPropertyTests -{ - /// - /// Confirms the mock generated class returns the correct value. - /// - [Fact] - public void TestPropertyReturnsFoo() - { - var model = new ObservableAsTestModel(); - Assert.Equal("foo", model.TestProperty); - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody.Tests/ReactiveDependencyTests.cs b/src/ReactiveUI.Fody.Tests/ReactiveDependencyTests.cs deleted file mode 100644 index 25eaf53534..0000000000 --- a/src/ReactiveUI.Fody.Tests/ReactiveDependencyTests.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.ComponentModel; -using Xunit; - -namespace ReactiveUI.Fody.Tests; - -/// -/// Tests for the ReactiveDependencyAttribute. -/// -public class ReactiveDependencyTests -{ - /// - /// Tests to make sure that the facade returns the same valid as the dependency for the int property. - /// - [Fact] - public void IntPropertyOnWeavedFacadeReturnsBaseModelIntPropertyDefaultValueTest() - { - var model = new BaseModel(); - var expectedResult = model.IntProperty; - - var facade = new FacadeModel(model); - - Assert.Equal(expectedResult, facade.IntProperty); - } - - /// - /// Tests to make sure that the facade returns the same valid as the dependency for the string property. - /// - [Fact] - public void AnotherStringPropertyOnFacadeReturnsBaseModelStringPropertyDefaultValueTest() - { - var model = new BaseModel(); - var expectedResult = model.StringProperty; - - var facade = new FacadeModel(model); - - Assert.Equal(expectedResult, facade.AnotherStringProperty); - } - - /// - /// Tests to make sure that the facade returns the same valid as the dependency for the string property after being updated. - /// - [Fact] - public void SettingAnotherStringPropertyUpdatesTheDependencyStringProperty() - { - const string? expectedResult = "New String Value"; - var facade = new FacadeModel(new()) { AnotherStringProperty = expectedResult }; - - Assert.Equal(expectedResult, facade.Dependency.StringProperty); - } - - /// - /// Tests to make sure that the facade returns the same valid as the dependency for the int property after being updated. - /// - [Fact] - public void SettingFacadeIntPropertyUpdatesDependencyIntProperty() - { - const int expectedResult = 999; - var facade = new FacadeModel(new()) { IntProperty = expectedResult }; - - Assert.Equal(expectedResult, facade.Dependency.IntProperty); - } - - /// - /// Checks to make sure that the property changed event is fired after first assignment. - /// - [Fact] - public void FacadeIntPropertyChangedEventFiresOnAssignmentTest() - { - const string? expectedPropertyChanged = "IntProperty"; - var resultPropertyChanged = string.Empty; - - var facade = new FacadeModel(new()); - - var obj = (INotifyPropertyChanged)facade; - obj.PropertyChanged += (_, args) => resultPropertyChanged = args.PropertyName; - - facade.IntProperty = 999; - - Assert.Equal(expectedPropertyChanged, resultPropertyChanged); - } - - /// - /// Checks to make sure that the property changed event is fired after first assignment. - /// - [Fact] - public void FacadeAnotherStringPropertyChangedEventFiresOnAssignmentTest() - { - const string? expectedPropertyChanged = "AnotherStringProperty"; - var resultPropertyChanged = string.Empty; - - var facade = new FacadeModel(new()); - - var obj = (INotifyPropertyChanged)facade; - obj.PropertyChanged += (_, args) => resultPropertyChanged = args.PropertyName; - - facade.AnotherStringProperty = "Some New Value"; - - Assert.Equal(expectedPropertyChanged, resultPropertyChanged); - } - - /// - /// Checks to make sure that the facade and the decorate return the same value. - /// - [Fact] - public void StringPropertyOnWeavedDecoratorReturnsBaseModelDefaultStringValue() - { - var model = new BaseModel(); - var expectedResult = model.StringProperty; - - var decorator = new DecoratorModel(model); - - Assert.Equal(expectedResult, decorator.StringProperty); - } - - /// - /// Checks to make sure that the decorator property changed is fired. - /// - [Fact] - public void DecoratorStringPropertyRaisesPropertyChanged() - { - const string? expectedPropertyChanged = "StringProperty"; - var resultPropertyChanged = string.Empty; - - var decorator = new DecoratorModel(new()); - - var obj = (INotifyPropertyChanged)decorator; - obj.PropertyChanged += (_, args) => resultPropertyChanged = args.PropertyName; - - decorator.StringProperty = "Some New Value"; - - Assert.Equal(expectedPropertyChanged, resultPropertyChanged); - } - - /// - /// Checks to make sure that the decorator property changed is fired. - /// - [Fact] - public void DecoratorReactiveStringPropertyRaisesPropertyChanged() - { - const string? expectedPropertyChanged = "SomeCoolNewProperty"; - var resultPropertyChanged = string.Empty; - - var decorator = new DecoratorModel(new()); - - var obj = (INotifyPropertyChanged)decorator; - obj.PropertyChanged += (_, args) => resultPropertyChanged = args.PropertyName; - - decorator.UpdateCoolProperty("Some Cool Property"); - Assert.Equal(expectedPropertyChanged, resultPropertyChanged); - } -} diff --git a/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj b/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj deleted file mode 100644 index ffde27361d..0000000000 --- a/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - net472;net6.0 - netstandard2.0 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/ReactiveUI.Fody/CecilExtensions.cs b/src/ReactiveUI.Fody/CecilExtensions.cs deleted file mode 100644 index d41e3ca8b2..0000000000 --- a/src/ReactiveUI.Fody/CecilExtensions.cs +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ReactiveUI.Fody; - -/// -/// Mono.Cecil extension methods. -/// -public static class CecilExtensions -{ - /// - /// Emits the specified il. - /// - /// The body. - /// The il. - public static void Emit(this MethodBody body, Action il) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(body); - ArgumentNullException.ThrowIfNull(il); -#else - if (body is null) - { - throw new ArgumentNullException(nameof(body)); - } - - if (il is null) - { - throw new ArgumentNullException(nameof(il)); - } -#endif - - il(body.GetILProcessor()); - } - - /// - /// Makes the method generic. - /// - /// The method. - /// The generic arguments. - /// A generic method with generic typed arguments. - public static GenericInstanceMethod MakeGenericMethod(this MethodReference method, params TypeReference[] genericArguments) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(genericArguments); -#else - if (genericArguments is null) - { - throw new ArgumentNullException(nameof(genericArguments)); - } -#endif - - var result = new GenericInstanceMethod(method); - foreach (var argument in genericArguments) - { - result.GenericArguments.Add(argument); - } - - return result; - } - - /// - /// Determines whether [is assignable from] [the specified type]. - /// - /// Type of the base. - /// The type. - /// The logger. - /// - /// true if [is assignable from] [the specified type]; otherwise, false. - /// - public static bool IsAssignableFrom(this TypeReference baseType, TypeReference type, Action? logger = null) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(baseType); - ArgumentNullException.ThrowIfNull(type); -#else - if (baseType is null) - { - throw new ArgumentNullException(nameof(baseType)); - } - - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } -#endif - - return baseType.Resolve().IsAssignableFrom(type.Resolve(), logger); - } - - /// - /// Determines whether [is assignable from] [the specified type]. - /// - /// Type of the base. - /// The type. - /// The logger. - /// - /// true if [is assignable from] [the specified type]; otherwise, false. - /// - public static bool IsAssignableFrom(this TypeDefinition baseType, TypeDefinition type, Action? logger = null) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(baseType); -#else - if (baseType is null) - { - throw new ArgumentNullException(nameof(baseType)); - } -#endif - - logger ??= _ => { }; - - var queue = new Queue(); - queue.Enqueue(type); - - while (queue.Count > 0) - { - var current = queue.Dequeue(); - logger(current.FullName); - - if (baseType.FullName == current.FullName) - { - return true; - } - - if (current.BaseType is not null) - { - queue.Enqueue(current.BaseType.Resolve()); - } - - foreach (var @interface in current.Interfaces) - { - queue.Enqueue(@interface.InterfaceType.Resolve()); - } - } - - return false; - } - - /// - /// Determines whether the specified attribute type is defined. - /// - /// The member. - /// Type of the attribute. - /// - /// true if the specified attribute type is defined; otherwise, false. - /// - public static bool IsDefined(this IMemberDefinition member, TypeReference attributeType) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(member); -#else - if (member is null) - { - throw new ArgumentNullException(nameof(member)); - } -#endif - - return member.HasCustomAttributes && member.CustomAttributes.Any(x => x.AttributeType.FullName == attributeType.FullName); - } - - /// - /// Binds the method to the specified generic type. - /// - /// The method. - /// Type of the generic. - /// The method bound to the generic type. - public static MethodReference Bind(this MethodReference method, GenericInstanceType genericType) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(method); -#else - if (method is null) - { - throw new ArgumentNullException(nameof(method)); - } -#endif - - var reference = new MethodReference(method.Name, method.ReturnType, genericType) - { - HasThis = method.HasThis, - ExplicitThis = method.ExplicitThis, - CallingConvention = method.CallingConvention - }; - - foreach (var parameter in method.Parameters) - { - reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); - } - - return reference; - } - - /// - /// Binds the generic type definition to a field. - /// - /// The field. - /// The generic type definition. - /// The field bound to the generic type. - public static FieldReference BindDefinition(this FieldReference field, TypeReference genericTypeDefinition) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(field); - ArgumentNullException.ThrowIfNull(genericTypeDefinition); -#else - if (field is null) - { - throw new ArgumentNullException(nameof(field)); - } - - if (genericTypeDefinition is null) - { - throw new ArgumentNullException(nameof(genericTypeDefinition)); - } -#endif - - if (!genericTypeDefinition.HasGenericParameters) - { - return field; - } - - var genericDeclaration = new GenericInstanceType(genericTypeDefinition); - foreach (var parameter in genericTypeDefinition.GenericParameters) - { - genericDeclaration.GenericArguments.Add(parameter); - } - - return new(field.Name, field.FieldType, genericDeclaration); - } - - /// - /// Finds an assembly in a module. - /// - /// The current module. - /// Name of the assembly. - /// The assembly if found, null if not. - public static AssemblyNameReference? FindAssembly(this ModuleDefinition currentModule, string assemblyName) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(currentModule); -#else - if (currentModule is null) - { - throw new ArgumentNullException(nameof(currentModule)); - } -#endif - - var assemblyReferences = currentModule.AssemblyReferences; - - return assemblyReferences.SingleOrDefault(x => x.Name == assemblyName); - } - - /// - /// Finds a type reference in the module. - /// - /// The current module. - /// The namespace. - /// Name of the type. - /// The scope. - /// The type parameters. - /// The type reference. - public static TypeReference FindType(this ModuleDefinition currentModule, string @namespace, string typeName, IMetadataScope? scope = null, params string[] typeParameters) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(typeParameters); -#else - if (typeParameters is null) - { - throw new ArgumentNullException(nameof(typeParameters)); - } -#endif - - var result = new TypeReference(@namespace, typeName, currentModule, scope); - foreach (var typeParameter in typeParameters) - { - result.GenericParameters.Add(new GenericParameter(typeParameter, result)); - } - - return result; - } - - /// - /// Compares two type references for equality. - /// - /// The type. - /// The compare to. - /// A value indicating the result of the comparison. - public static bool CompareTo(this TypeReference type, TypeReference compareTo) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(type); - ArgumentNullException.ThrowIfNull(compareTo); -#else - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (compareTo is null) - { - throw new ArgumentNullException(nameof(compareTo)); - } -#endif - - return type.FullName == compareTo.FullName; - } -} diff --git a/src/ReactiveUI.Fody/ModuleWeaver.cs b/src/ReactiveUI.Fody/ModuleWeaver.cs deleted file mode 100644 index 763f84d623..0000000000 --- a/src/ReactiveUI.Fody/ModuleWeaver.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using Fody; - -namespace ReactiveUI.Fody; - -/// -/// ReactiveUI module weaver. -/// -/// -public class ModuleWeaver : BaseModuleWeaver -{ - /// - public override void Execute() - { - var propertyWeaver = new ReactiveUIPropertyWeaver - { - ModuleDefinition = ModuleDefinition, - LogInfo = WriteInfo, - LogError = WriteError - }; - propertyWeaver.Execute(); - - var observableAsPropertyWeaver = new ObservableAsPropertyWeaver - { - ModuleDefinition = ModuleDefinition, - LogInfo = WriteInfo, - FindType = FindTypeDefinition - }; - observableAsPropertyWeaver.Execute(); - - var reactiveDependencyWeaver = new ReactiveDependencyPropertyWeaver - { - ModuleDefinition = ModuleDefinition, - LogInfo = WriteInfo, - LogError = WriteError - }; - reactiveDependencyWeaver.Execute(); - } - - /// - public override IEnumerable GetAssembliesForScanning() - { - yield return "mscorlib"; - yield return "netstandard"; - yield return "System"; - yield return "System.Runtime"; - yield return "ReactiveUI"; - yield return "ReactiveUI.Fody.Helpers"; - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Fody/ObservableAsPropertyWeaver.cs b/src/ReactiveUI.Fody/ObservableAsPropertyWeaver.cs deleted file mode 100644 index d6f657a5c6..0000000000 --- a/src/ReactiveUI.Fody/ObservableAsPropertyWeaver.cs +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; - -namespace ReactiveUI.Fody; - -/// -/// Weaver that converts observables as property helper. -/// -public class ObservableAsPropertyWeaver -{ - /// - /// Gets or sets the module definition. - /// - /// - /// The module definition. - /// - public ModuleDefinition? ModuleDefinition { get; set; } - - /// - /// Gets or sets a action that will log an MessageImportance.High message to MSBuild. OPTIONAL. - /// - /// - /// The log information. - /// - public Action? LogInfo { get; set; } - - /// - /// Gets a function that will find a type from referenced assemblies by name. - /// - public Func? FindType { get; internal set; } - - /// - /// Executes this property weaver. - /// - public void Execute() - { - if (ModuleDefinition is null) - { - LogInfo?.Invoke("The module definition has not been defined."); - return; - } - - var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault(); - if (reactiveUI is null) - { - LogInfo?.Invoke("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); - return; - } - - LogInfo?.Invoke($"{reactiveUI.Name} {reactiveUI.Version}"); - var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault(); - if (helpers is null) - { - LogInfo?.Invoke("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); - return; - } - - LogInfo?.Invoke($"{helpers.Name} {helpers.Version}"); - - var exceptionName = typeof(Exception).FullName; - - if (exceptionName is null) - { - LogInfo?.Invoke("Could not find the full name for System.Exception"); - return; - } - - var reactiveObject = ModuleDefinition.FindType("ReactiveUI", "ReactiveObject", reactiveUI); - - // The types we will scan are subclasses of ReactiveObject - var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType is not null && reactiveObject.IsAssignableFrom(x.BaseType)); - - var observableAsPropertyHelper = ModuleDefinition.FindType("ReactiveUI", "ObservableAsPropertyHelper`1", reactiveUI, "T"); - var observableAsPropertyAttribute = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ObservableAsPropertyAttribute", helpers); - var observableAsPropertyHelperGetValue = ModuleDefinition.ImportReference(observableAsPropertyHelper.Resolve().Properties.Single(x => x.Name == "Value").GetMethod); - var exceptionDefinition = FindType?.Invoke(exceptionName); - var constructorDefinition = exceptionDefinition.GetConstructors().Single(x => x.Parameters.Count == 1); - var exceptionConstructor = ModuleDefinition.ImportReference(constructorDefinition); - - foreach (var targetType in targetTypes) - { - foreach (var property in targetType.Properties.Where(x => x.IsDefined(observableAsPropertyAttribute) || (x.GetMethod?.IsDefined(observableAsPropertyAttribute) ?? false)).ToArray()) - { - var genericObservableAsPropertyHelper = observableAsPropertyHelper.MakeGenericInstanceType(property.PropertyType); - var genericObservableAsPropertyHelperGetValue = observableAsPropertyHelperGetValue.Bind(genericObservableAsPropertyHelper); - ModuleDefinition.ImportReference(genericObservableAsPropertyHelperGetValue); - - // Declare a field to store the property value - var field = new FieldDefinition("$" + property.Name, FieldAttributes.Private, genericObservableAsPropertyHelper); - targetType.Fields.Add(field); - - // It's an auto-property, so remove the generated field - if (property.SetMethod?.HasBody == true) - { - // Remove old field (the generated backing field for the auto property) - var oldField = (FieldReference)property.GetMethod.Body.Instructions.Single(x => x.Operand is FieldReference).Operand; - var oldFieldDefinition = oldField.Resolve(); - targetType.Fields.Remove(oldFieldDefinition); - - // Re-implement setter to throw an exception - property.SetMethod.Body = new MethodBody(property.SetMethod); - property.SetMethod.Body.Emit(il => - { - il.Emit(OpCodes.Ldstr, "Never call the setter of an ObservableAsPropertyHelper property."); - il.Emit(OpCodes.Newobj, exceptionConstructor); - il.Emit(OpCodes.Throw); - il.Emit(OpCodes.Ret); - }); - } - - property.GetMethod.Body = new MethodBody(property.GetMethod); - property.GetMethod.Body.Emit(il => - { - var isValid = il.Create(OpCodes.Nop); - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldfld, field.BindDefinition(targetType)); // pop -> this.$PropertyName - il.Emit(OpCodes.Dup); // Put an extra copy of this.$PropertyName onto the stack - il.Emit(OpCodes.Brtrue, isValid); // If the helper is null, return the default value for the property - il.Emit(OpCodes.Pop); // Drop this.$PropertyName - EmitDefaultValue(property.GetMethod.Body, il, property.PropertyType); // Put the default value onto the stack - il.Emit(OpCodes.Ret); // Return that default value - il.Append(isValid); // Add a marker for if the helper is not null - il.Emit(OpCodes.Callvirt, genericObservableAsPropertyHelperGetValue); // pop -> this.$PropertyName.Value - il.Emit(OpCodes.Ret); // Return the value that is on the stack - }); - } - } - } - - /// - /// Emits the default value. - /// - /// The method body. - /// The il. - /// The type. - public void EmitDefaultValue(MethodBody methodBody, ILProcessor il, TypeReference type) - { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(methodBody); - ArgumentNullException.ThrowIfNull(il); -#else - if (methodBody is null) - { - throw new ArgumentNullException(nameof(methodBody)); - } - - if (il is null) - { - throw new ArgumentNullException(nameof(il)); - } -#endif - - if (ModuleDefinition is not null) - { - if (type.CompareTo(ModuleDefinition.TypeSystem.Boolean) || type.CompareTo(ModuleDefinition.TypeSystem.Byte) || - type.CompareTo(ModuleDefinition.TypeSystem.Int16) || type.CompareTo(ModuleDefinition.TypeSystem.Int32)) - { - il.Emit(OpCodes.Ldc_I4_0); - } - else if (type.CompareTo(ModuleDefinition.TypeSystem.Single)) - { - il.Emit(OpCodes.Ldc_R4, 0F); - } - else if (type.CompareTo(ModuleDefinition.TypeSystem.Int64)) - { - il.Emit(OpCodes.Ldc_I8, 0L); - } - else if (type.CompareTo(ModuleDefinition.TypeSystem.Double)) - { - il.Emit(OpCodes.Ldc_R8, 0D); - } - else if (type.IsGenericParameter || type.IsValueType) - { - methodBody.InitLocals = true; - var local = new VariableDefinition(type); - il.Body.Variables.Add(local); - il.Emit(OpCodes.Ldloca_S, local); - il.Emit(OpCodes.Initobj, type); - il.Emit(OpCodes.Ldloc, local); - } - else - { - il.Emit(OpCodes.Ldnull); - } - } - } -} diff --git a/src/ReactiveUI.Fody/Properties/AssemblyInfo.cs b/src/ReactiveUI.Fody/Properties/AssemblyInfo.cs deleted file mode 100644 index 4700ec8817..0000000000 --- a/src/ReactiveUI.Fody/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("ReactiveUI.Tests")] -[assembly: InternalsVisibleTo("ReactiveUI.Winforms")] -[assembly: InternalsVisibleTo("ReactiveUI.Wpf")] -[assembly: InternalsVisibleTo("ReactiveUI.XamForms")] -[assembly: InternalsVisibleTo("ReactiveUI.AndroidSupport")] diff --git a/src/ReactiveUI.Fody/ReactiveDependencyPropertyWeaver.cs b/src/ReactiveUI.Fody/ReactiveDependencyPropertyWeaver.cs deleted file mode 100644 index e66f7d8ddf..0000000000 --- a/src/ReactiveUI.Fody/ReactiveDependencyPropertyWeaver.cs +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; - -namespace ReactiveUI.Fody; - -/// -/// Weaver that generates an ObservableAsPropertyHelper. -/// -public class ReactiveDependencyPropertyWeaver -{ - /// - /// Gets or sets the module definition. - /// - /// - /// The module definition. - /// - public ModuleDefinition? ModuleDefinition { get; set; } - - /// - /// Gets or sets a action that will log an MessageImportance.High message to MSBuild. OPTIONAL. - /// - /// - /// The log information. - /// - public Action? LogInfo { get; set; } - - /// - /// Gets or sets a action which will log an error message to MSBuild. OPTIONAL. - /// - /// - /// The log error. - /// - public Action? LogError { get; set; } - - /// - /// Executes this instance. - /// - /// - /// reactiveObjectExtensions is null - /// or - /// raisePropertyChangedMethod is null - /// or - /// reactiveDecoratorAttribute is null. - /// - public void Execute() - { - if (ModuleDefinition is null) - { - LogInfo?.Invoke("The module definition has not been defined."); - return; - } - - var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault(); - if (reactiveUI is null) - { - LogInfo?.Invoke("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); - return; - } - - LogInfo?.Invoke($"{reactiveUI.Name} {reactiveUI.Version}"); - var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault(); - if (helpers is null) - { - LogInfo?.Invoke("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); - return; - } - - LogInfo?.Invoke($"{helpers.Name} {helpers.Version}"); - var reactiveObject = new TypeReference("ReactiveUI", "IReactiveObject", ModuleDefinition, reactiveUI); - - var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType is not null && reactiveObject.IsAssignableFrom(x.BaseType)).ToArray(); - var reactiveObjectExtensions = new TypeReference("ReactiveUI", "IReactiveObjectExtensions", ModuleDefinition, reactiveUI).Resolve() ?? throw new Exception("reactiveObjectExtensions is null"); - var raisePropertyChangedMethod = ModuleDefinition.ImportReference(reactiveObjectExtensions.Methods.Single(x => x.Name == "RaisePropertyChanged")) ?? throw new Exception("raisePropertyChangedMethod is null"); - var reactiveDependencyAttribute = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ReactiveDependencyAttribute", helpers) ?? throw new Exception("reactiveDecoratorAttribute is null"); - foreach (var targetType in targetTypes.Where(x => x.Properties.Any(y => y.IsDefined(reactiveDependencyAttribute))).ToArray()) - { - foreach (var facadeProperty in targetType.Properties.Where(x => x.IsDefined(reactiveDependencyAttribute)).ToArray()) - { - // If the property already has a body then do not weave to prevent loss of instructions - if (!facadeProperty.GetMethod.Body.Instructions.Any(x => x.Operand is FieldReference) || facadeProperty.GetMethod.Body.HasVariables) - { - LogError?.Invoke($"Property {facadeProperty.Name} is not an auto property and therefore not suitable for ReactiveDependency weaving"); - continue; - } - - var attribute = facadeProperty.CustomAttributes.First(x => x.AttributeType.FullName == reactiveDependencyAttribute.FullName); - - var targetNamedArgument = attribute.ConstructorArguments.FirstOrDefault(); - var targetValue = targetNamedArgument.Value?.ToString(); - if (string.IsNullOrEmpty(targetValue)) - { - LogError?.Invoke("No target property defined on the object"); - continue; - } - - if (targetType.Properties.All(x => x.Name != targetValue) && targetType.Fields.All(x => x.Name != targetValue)) - { - LogError?.Invoke($"dependency object property/field name '{targetValue}' not found on target type {targetType.Name}"); - continue; - } - - var objPropertyTarget = targetType.Properties.FirstOrDefault(x => x.Name == targetValue); - var objFieldTarget = targetType.Fields.FirstOrDefault(x => x.Name == targetValue); - - var objDependencyTargetType = objPropertyTarget is not null - ? objPropertyTarget.PropertyType.Resolve() - : objFieldTarget?.FieldType.Resolve(); - - if (objDependencyTargetType is null) - { - LogError?.Invoke("Couldn't result the dependency type"); - continue; - } - - // Look for the target property on the member obj - var destinationPropertyNamedArgument = attribute.Properties.FirstOrDefault(x => x.Name == "TargetProperty"); - var destinationPropertyName = destinationPropertyNamedArgument.Argument.Value?.ToString(); - - // If no target property was specified use this property's name as the target on the decorated object (ala a decorated property) - if (string.IsNullOrEmpty(destinationPropertyName)) - { - destinationPropertyName = facadeProperty.Name; - } - - if (objDependencyTargetType.Properties.All(x => x.Name != destinationPropertyName)) - { - LogError?.Invoke($"Target property {destinationPropertyName} on dependency of type {objDependencyTargetType.DeclaringType.Name} not found"); - continue; - } - - var destinationProperty = objDependencyTargetType.Properties.First(x => x.Name == destinationPropertyName); - - // The property on the facade/decorator should have a setter - if (facadeProperty.SetMethod is null) - { - LogError?.Invoke($"Property {facadeProperty.DeclaringType.FullName}.{facadeProperty.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [ReactiveDecorator]"); - continue; - } - - // The property on the dependency should have a setter e.g. Dependency.SomeProperty = value; - if (destinationProperty.SetMethod is null) - { - LogError?.Invoke($"Dependency object's property {destinationProperty.DeclaringType.FullName}.{destinationProperty.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [ReactiveDecorator]"); - continue; - } - - // Remove old field (the generated backing field for the auto property) - var oldField = (FieldReference)facadeProperty.GetMethod.Body.Instructions.Single(x => x.Operand is FieldReference).Operand; - var oldFieldDefinition = oldField.Resolve(); - targetType.Fields.Remove(oldFieldDefinition); - - // See if there exists an initializer for the auto-property - var constructors = targetType.Methods.Where(x => x.IsConstructor); - foreach (var constructor in constructors) - { - var fieldAssignment = constructor.Body.Instructions.SingleOrDefault(x => Equals(x.Operand, oldFieldDefinition) || Equals(x.Operand, oldField)); - if (fieldAssignment is not null) - { - // Replace field assignment with a property set (the stack semantics are the same for both, - // so happily we don't have to manipulate the byte code any further.) - var setterCall = constructor.Body.GetILProcessor().Create(facadeProperty.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, facadeProperty.SetMethod); - constructor.Body.GetILProcessor().Replace(fieldAssignment, setterCall); - } - } - - // Build out the getter which simply returns the value of the generated field - facadeProperty.GetMethod.Body = new MethodBody(facadeProperty.GetMethod); - facadeProperty.GetMethod.Body.Emit(il => - { - il.Emit(OpCodes.Ldarg_0); - if (objPropertyTarget is not null) - { - il.Emit(objPropertyTarget.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, objPropertyTarget.GetMethod); - } - else - { - il.Emit(OpCodes.Ldfld, objFieldTarget); - } - - il.Emit(destinationProperty.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, destinationProperty.GetMethod); - il.Emit(OpCodes.Ret); - }); - - TypeReference genericTargetType = targetType; - if (targetType.HasGenericParameters) - { - var genericDeclaration = new GenericInstanceType(targetType); - foreach (var parameter in targetType.GenericParameters) - { - genericDeclaration.GenericArguments.Add(parameter); - } - - genericTargetType = genericDeclaration; - } - - var methodReference = raisePropertyChangedMethod.MakeGenericMethod(genericTargetType); - facadeProperty.SetMethod.Body = new MethodBody(facadeProperty.SetMethod); - facadeProperty.SetMethod.Body.Emit(il => - { - il.Emit(OpCodes.Ldarg_0); - if (objPropertyTarget is not null) - { - il.Emit(objPropertyTarget.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, objPropertyTarget.GetMethod); - } - else - { - il.Emit(OpCodes.Ldfld, objFieldTarget); - } - - il.Emit(OpCodes.Ldarg_1); - il.Emit(destinationProperty.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, destinationProperty.SetMethod); // Set the nested property - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldstr, facadeProperty.Name); // "PropertyName" - il.Emit(OpCodes.Call, methodReference); // this.RaisePropertyChanged("PropertyName") - il.Emit(OpCodes.Ret); - }); - } - } - } -} diff --git a/src/ReactiveUI.Fody/ReactiveUI.Fody.csproj b/src/ReactiveUI.Fody/ReactiveUI.Fody.csproj deleted file mode 100644 index b3cbca782e..0000000000 --- a/src/ReactiveUI.Fody/ReactiveUI.Fody.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - netstandard2.0;net6.0;net7.0;net8.0 - $(TargetFrameworks);net472 - Fody extension that will generate RaisePropertyChange notifications for properties and ObservableAsPropertyHelper properties - False - mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;xamarin;android;ios;mac;forms;monodroid;monotouch;xamarin.android;xamarin.ios;xamarin.forms;xamarin.mac;xamarin.tvos;wpf;net;netstandard;net472;uwp;tizen;unoplatform;fody; - - - - - - diff --git a/src/ReactiveUI.Fody/ReactiveUIPropertyWeaver.cs b/src/ReactiveUI.Fody/ReactiveUIPropertyWeaver.cs deleted file mode 100644 index 1df8800e34..0000000000 --- a/src/ReactiveUI.Fody/ReactiveUIPropertyWeaver.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; - -namespace ReactiveUI.Fody; - -/// -/// Weaver that replaces properties marked with `[DataMember]` on subclasses of `ReactiveObject` with an -/// implementation that invokes `RaisePropertyChanged` as is required for ReactiveUI. -/// -public class ReactiveUIPropertyWeaver -{ - /// - /// Gets or sets the module definition. - /// - /// - /// The module definition. - /// - public ModuleDefinition? ModuleDefinition { get; set; } - - /// - /// Gets or sets a action that will log an MessageImportance.High message to MSBuild. OPTIONAL. - /// - /// - /// The log information. - /// - public Action? LogInfo { get; set; } - - /// - /// Gets or sets an action that will log an error message to MSBuild. OPTIONAL. - /// - /// - /// The log error. - /// - public Action? LogError { get; set; } - - /// - /// Executes this property weaver. - /// - /// - /// reactiveObjectExtensions is null - /// or - /// raiseAndSetIfChangedMethod is null - /// or - /// reactiveAttribute is null - /// or - /// [Reactive] is decorating " + property.DeclaringType.FullName + "." + property.Name + ", but the property has no setter so there would be nothing to react to. Consider removing the attribute. - /// - public void Execute() - { - if (ModuleDefinition is null) - { - LogInfo?.Invoke("The module definition has not been defined."); - return; - } - - var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault(); - if (reactiveUI is null) - { - LogInfo?.Invoke("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); - return; - } - - LogInfo?.Invoke($"{reactiveUI.Name} {reactiveUI.Version}"); - var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault(); - if (helpers is null) - { - LogInfo?.Invoke("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); - return; - } - - LogInfo?.Invoke($"{helpers.Name} {helpers.Version}"); - var reactiveObject = new TypeReference("ReactiveUI", "IReactiveObject", ModuleDefinition, reactiveUI); - var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType is not null && reactiveObject.IsAssignableFrom(x.BaseType)).ToArray(); - var reactiveObjectExtensions = new TypeReference("ReactiveUI", "IReactiveObjectExtensions", ModuleDefinition, reactiveUI).Resolve() ?? throw new Exception("reactiveObjectExtensions is null"); - var raiseAndSetIfChangedMethod = ModuleDefinition.ImportReference(reactiveObjectExtensions.Methods.Single(x => x.Name == "RaiseAndSetIfChanged")) ?? throw new Exception("raiseAndSetIfChangedMethod is null"); - var reactiveAttribute = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ReactiveAttribute", helpers) ?? throw new Exception("reactiveAttribute is null"); - foreach (var targetType in targetTypes) - { - foreach (var property in targetType.Properties.Where(x => x.IsDefined(reactiveAttribute)).ToArray()) - { - if (property.SetMethod is null) - { - LogError?.Invoke($"Property {property.DeclaringType.FullName}.{property.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [Reactive]"); - continue; - } - - // Declare a field to store the property value - var field = new FieldDefinition("$" + property.Name, FieldAttributes.Private, property.PropertyType); - targetType.Fields.Add(field); - - // Remove old field (the generated backing field for the auto property) - var oldField = (FieldReference)property.GetMethod.Body.Instructions.Single(x => x.Operand is FieldReference).Operand; - var oldFieldDefinition = oldField.Resolve(); - targetType.Fields.Remove(oldFieldDefinition); - - // See if there exists an initializer for the auto-property - var constructors = targetType.Methods.Where(x => x.IsConstructor); - foreach (var constructor in constructors) - { - var fieldAssignment = constructor.Body.Instructions.SingleOrDefault(x => Equals(x.Operand, oldFieldDefinition) || Equals(x.Operand, oldField)); - if (fieldAssignment is not null) - { - // Replace field assignment with a property set (the stack semantics are the same for both, - // so happily we don't have to manipulate the bytecode any further.) - var setterCall = constructor.Body.GetILProcessor().Create(property.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, property.SetMethod); - constructor.Body.GetILProcessor().Replace(fieldAssignment, setterCall); - } - } - - // Build out the getter which simply returns the value of the generated field - property.GetMethod.Body = new MethodBody(property.GetMethod); - property.GetMethod.Body.Emit(il => - { - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldfld, field.BindDefinition(targetType)); // pop -> this.$PropertyName - il.Emit(OpCodes.Ret); // Return the field value that is lying on the stack - }); - - TypeReference genericTargetType = targetType; - if (targetType.HasGenericParameters) - { - var genericDeclaration = new GenericInstanceType(targetType); - foreach (var parameter in targetType.GenericParameters) - { - genericDeclaration.GenericArguments.Add(parameter); - } - - genericTargetType = genericDeclaration; - } - - var methodReference = raiseAndSetIfChangedMethod.MakeGenericMethod(genericTargetType, property.PropertyType); - - // Build out the setter which fires the RaiseAndSetIfChanged method - if (property.SetMethod is null) - { - throw new Exception("[Reactive] is decorating " + property.DeclaringType.FullName + "." + property.Name + ", but the property has no setter so there would be nothing to react to. Consider removing the attribute."); - } - - property.SetMethod.Body = new MethodBody(property.SetMethod); - property.SetMethod.Body.Emit(il => - { - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldflda, field.BindDefinition(targetType)); // pop -> this.$PropertyName - il.Emit(OpCodes.Ldarg_1); // value - il.Emit(OpCodes.Ldstr, property.Name); // "PropertyName" - il.Emit(OpCodes.Call, methodReference); // pop * 4 -> this.RaiseAndSetIfChanged(this.$PropertyName, value, "PropertyName") - il.Emit(OpCodes.Pop); // We don't care about the result of RaiseAndSetIfChanged, so pop it off the stack (stack is now empty) - il.Emit(OpCodes.Ret); // Return out of the function - }); - } - } - } -} diff --git a/src/ReactiveUI.LeakTests/ReactiveUI.LeakTests.csproj b/src/ReactiveUI.LeakTests/ReactiveUI.LeakTests.csproj index 110df71dc7..c5de82f509 100644 --- a/src/ReactiveUI.LeakTests/ReactiveUI.LeakTests.csproj +++ b/src/ReactiveUI.LeakTests/ReactiveUI.LeakTests.csproj @@ -4,9 +4,9 @@ false - + - + \ No newline at end of file diff --git a/src/ReactiveUI.Maui/ReactiveUI.Maui.csproj b/src/ReactiveUI.Maui/ReactiveUI.Maui.csproj index 65896bf468..5034a22788 100644 --- a/src/ReactiveUI.Maui/ReactiveUI.Maui.csproj +++ b/src/ReactiveUI.Maui/ReactiveUI.Maui.csproj @@ -1,5 +1,4 @@  - net7.0;net8.0 $(TargetFrameworks);net7.0-windows10.0.19041.0;net8.0-windows10.0.19041.0 @@ -7,7 +6,6 @@ mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;maui;android;ios;mac;windows;net true $(DefineConstants);IS_MAUI - 11.0 13.1 21.0 @@ -15,24 +13,19 @@ 10.0.17763.0 6.5 - - - $(DefineConstants);WINUI_TARGET - - - - - - + + $(DefineConstants);WINUI_TARGET + + + + - - + + - - - + \ No newline at end of file diff --git a/src/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj b/src/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj index 5580c54709..9f17c551ab 100644 --- a/src/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj +++ b/src/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj @@ -1,17 +1,14 @@  - net472;net6.0 false - - - - + + + - - + \ No newline at end of file diff --git a/src/ReactiveUI.Testing/ReactiveUI.Testing.csproj b/src/ReactiveUI.Testing/ReactiveUI.Testing.csproj index a1609fdfeb..e70d0365ba 100644 --- a/src/ReactiveUI.Testing/ReactiveUI.Testing.csproj +++ b/src/ReactiveUI.Testing/ReactiveUI.Testing.csproj @@ -8,21 +8,18 @@ ReactiveUI.Testing mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;test; - - - ..\Java.Interop.dll - + + ..\Java.Interop.dll + - - + - - + \ No newline at end of file diff --git a/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj b/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj index 017db2d0d3..28b4b7af6d 100644 --- a/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj +++ b/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj @@ -1,25 +1,20 @@  - net6.0;net7.0;net8.0 net472;net6.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net8.0-windows10.0.17763.0 $(NoWarn);CS1591 - - + - - - @@ -45,7 +40,7 @@ - + @@ -53,7 +48,6 @@ - @@ -65,7 +59,6 @@ - True @@ -81,11 +74,9 @@ TestFormNotCanActivate.resx - $(DefaultXamlRuntime) - - + \ No newline at end of file diff --git a/src/ReactiveUI.WinUI/ReactiveUI.WinUI.csproj b/src/ReactiveUI.WinUI/ReactiveUI.WinUI.csproj index 5a6c0c7b9d..b525e902d3 100644 --- a/src/ReactiveUI.WinUI/ReactiveUI.WinUI.csproj +++ b/src/ReactiveUI.WinUI/ReactiveUI.WinUI.csproj @@ -12,12 +12,10 @@ 10.0.19041.0 10.0.19041.0 - - - + + - @@ -27,5 +25,4 @@ - - + \ No newline at end of file diff --git a/src/ReactiveUI.XamForms.Tests/ReactiveUI.XamForms.Tests.csproj b/src/ReactiveUI.XamForms.Tests/ReactiveUI.XamForms.Tests.csproj index e4117e6d89..ee4dd5d253 100644 --- a/src/ReactiveUI.XamForms.Tests/ReactiveUI.XamForms.Tests.csproj +++ b/src/ReactiveUI.XamForms.Tests/ReactiveUI.XamForms.Tests.csproj @@ -3,12 +3,10 @@ net6.0 false - - + - - + \ No newline at end of file diff --git a/src/ReactiveUI.XamForms/ReactiveUI.XamForms.csproj b/src/ReactiveUI.XamForms/ReactiveUI.XamForms.csproj index 19bbee81be..f6ec4b7ef3 100644 --- a/src/ReactiveUI.XamForms/ReactiveUI.XamForms.csproj +++ b/src/ReactiveUI.XamForms/ReactiveUI.XamForms.csproj @@ -5,12 +5,10 @@ ReactiveUI.XamForms mvvm;reactiveui;rx;reactive extensions;observable;LINQ;events;frp;xamarin;android;ios;mac;forms;monodroid;monotouch;xamarin.forms;net - - + - - + \ No newline at end of file diff --git a/src/ReactiveUI.sln b/src/ReactiveUI.sln index 49a701b553..2680eb9bc0 100644 --- a/src/ReactiveUI.sln +++ b/src/ReactiveUI.sln @@ -37,12 +37,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Wpf", "ReactiveU EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.LeakTests", "ReactiveUI.LeakTests\ReactiveUI.LeakTests.csproj", "{1AC71A71-F5F3-4F96-BDA9-A9DC7F572DB9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Fody", "ReactiveUI.Fody\ReactiveUI.Fody.csproj", "{7DE43BB9-5AC8-446A-8D8B-88C9201D802E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Fody.Helpers", "ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.csproj", "{20750BB4-36DD-4F8C-B970-D7809810EC98}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Fody.Tests", "ReactiveUI.Fody.Tests\ReactiveUI.Fody.Tests.csproj", "{404B0F3F-7343-4E54-A863-F27B99FE788B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Splat.Tests", "ReactiveUI.Splat.Tests\ReactiveUI.Splat.Tests.csproj", "{7ED6D69F-138F-40BD-9F37-3E4050E4D19B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Testing.Tests", "ReactiveUI.Testing.Tests\ReactiveUI.Testing.Tests.csproj", "{CD8B19A9-316E-4FBC-8F0C-87ADC6AAD684}" @@ -51,10 +45,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Blazor", "Reacti EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.AndroidX", "ReactiveUI.AndroidX\ReactiveUI.AndroidX.csproj", "{86430CEC-BAA3-4ED4-A90D-982437137D19}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Fody.Analyzer", "ReactiveUI.Fody.Analyzer\ReactiveUI.Fody.Analyzer.csproj", "{366789D4-4117-46CE-864F-BF1201F35319}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Fody.Analyzer.Tests", "ReactiveUI.Fody.Analyzer.Test\ReactiveUI.Fody.Analyzer.Tests.csproj", "{1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Drawing", "ReactiveUI.Drawing\ReactiveUI.Drawing.csproj", "{999D555D-C567-457C-95F7-8AD61310C56E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.XamForms.Tests", "ReactiveUI.XamForms.Tests\ReactiveUI.XamForms.Tests.csproj", "{46D5C71E-2E58-4454-BE3A-30B9047A2D1E}" @@ -221,54 +211,6 @@ Global {1AC71A71-F5F3-4F96-BDA9-A9DC7F572DB9}.Release|x64.Build.0 = Release|Any CPU {1AC71A71-F5F3-4F96-BDA9-A9DC7F572DB9}.Release|x86.ActiveCfg = Release|Any CPU {1AC71A71-F5F3-4F96-BDA9-A9DC7F572DB9}.Release|x86.Build.0 = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|arm64.ActiveCfg = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|arm64.Build.0 = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|x64.ActiveCfg = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|x64.Build.0 = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|x86.ActiveCfg = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Debug|x86.Build.0 = Debug|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|Any CPU.Build.0 = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|arm64.ActiveCfg = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|arm64.Build.0 = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|x64.ActiveCfg = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|x64.Build.0 = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|x86.ActiveCfg = Release|Any CPU - {7DE43BB9-5AC8-446A-8D8B-88C9201D802E}.Release|x86.Build.0 = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|Any CPU.Build.0 = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|arm64.ActiveCfg = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|arm64.Build.0 = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|x64.ActiveCfg = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|x64.Build.0 = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|x86.ActiveCfg = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Debug|x86.Build.0 = Debug|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|Any CPU.ActiveCfg = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|Any CPU.Build.0 = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|arm64.ActiveCfg = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|arm64.Build.0 = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|x64.ActiveCfg = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|x64.Build.0 = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|x86.ActiveCfg = Release|Any CPU - {20750BB4-36DD-4F8C-B970-D7809810EC98}.Release|x86.Build.0 = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|arm64.ActiveCfg = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|arm64.Build.0 = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|x64.ActiveCfg = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|x64.Build.0 = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|x86.ActiveCfg = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Debug|x86.Build.0 = Debug|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|Any CPU.Build.0 = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|arm64.ActiveCfg = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|arm64.Build.0 = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|x64.ActiveCfg = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|x64.Build.0 = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|x86.ActiveCfg = Release|Any CPU - {404B0F3F-7343-4E54-A863-F27B99FE788B}.Release|x86.Build.0 = Release|Any CPU {7ED6D69F-138F-40BD-9F37-3E4050E4D19B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7ED6D69F-138F-40BD-9F37-3E4050E4D19B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7ED6D69F-138F-40BD-9F37-3E4050E4D19B}.Debug|arm64.ActiveCfg = Debug|Any CPU @@ -327,38 +269,6 @@ Global {86430CEC-BAA3-4ED4-A90D-982437137D19}.Release|x64.Build.0 = Release|Any CPU {86430CEC-BAA3-4ED4-A90D-982437137D19}.Release|x86.ActiveCfg = Release|Any CPU {86430CEC-BAA3-4ED4-A90D-982437137D19}.Release|x86.Build.0 = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|Any CPU.Build.0 = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|arm64.ActiveCfg = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|arm64.Build.0 = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|x64.ActiveCfg = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|x64.Build.0 = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|x86.ActiveCfg = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Debug|x86.Build.0 = Debug|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|Any CPU.ActiveCfg = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|Any CPU.Build.0 = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|arm64.ActiveCfg = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|arm64.Build.0 = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|x64.ActiveCfg = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|x64.Build.0 = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|x86.ActiveCfg = Release|Any CPU - {366789D4-4117-46CE-864F-BF1201F35319}.Release|x86.Build.0 = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|arm64.ActiveCfg = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|arm64.Build.0 = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|x64.ActiveCfg = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|x64.Build.0 = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|x86.ActiveCfg = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Debug|x86.Build.0 = Debug|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|Any CPU.Build.0 = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|arm64.ActiveCfg = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|arm64.Build.0 = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|x64.ActiveCfg = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|x64.Build.0 = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|x86.ActiveCfg = Release|Any CPU - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90}.Release|x86.Build.0 = Release|Any CPU {999D555D-C567-457C-95F7-8AD61310C56E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {999D555D-C567-457C-95F7-8AD61310C56E}.Debug|Any CPU.Build.0 = Debug|Any CPU {999D555D-C567-457C-95F7-8AD61310C56E}.Debug|arm64.ActiveCfg = Debug|Any CPU @@ -430,10 +340,8 @@ Global GlobalSection(NestedProjects) = preSolution {2ADE0A50-5012-4341-8F4F-97597C2D6920} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} {1AC71A71-F5F3-4F96-BDA9-A9DC7F572DB9} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} - {404B0F3F-7343-4E54-A863-F27B99FE788B} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} {7ED6D69F-138F-40BD-9F37-3E4050E4D19B} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} {CD8B19A9-316E-4FBC-8F0C-87ADC6AAD684} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} - {1FD70B38-E2FB-4A46-BE07-C0F6ACE6FD90} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} {46D5C71E-2E58-4454-BE3A-30B9047A2D1E} = {2AE709FA-BE58-4287-BFD3-E80BEB605125} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/ReactiveUI/ReactiveUI.csproj b/src/ReactiveUI/ReactiveUI.csproj index f19d426158..3fa438d7a4 100644 --- a/src/ReactiveUI/ReactiveUI.csproj +++ b/src/ReactiveUI/ReactiveUI.csproj @@ -9,13 +9,12 @@ $(NoWarn);SYSLIB0011;IDE1006 14.2 - 14.0 - 21.0 - 10.0.17763.0 - 10.0.17763.0 - 6.5 - - + 14.0 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + 6.5 + @@ -23,7 +22,6 @@ - @@ -31,17 +29,15 @@ ..\Java.Interop.dll - - - - - - + + + + + - @@ -49,15 +45,12 @@ - - - @@ -65,20 +58,17 @@ - - - @@ -86,61 +76,52 @@ - - - - - + - - - - - - - - - - - - - - + + + + + + + + + + + - - - + + + - - - + \ No newline at end of file