Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1,122 changes: 563 additions & 559 deletions .editorconfig

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
<!-- MAUI version varies by target framework -->
<PropertyGroup>
<MauiVersion Condition="$(TargetFramework.StartsWith('net10'))">10.0.90</MauiVersion>
<MauiVersion Condition="$(TargetFramework.StartsWith('net11'))">11.0.0-preview.6.26360.8</MauiVersion>
<MauiVersion Condition="$(TargetFramework.StartsWith('net11'))">11.0.0-preview.7.26406.9</MauiVersion>
</PropertyGroup>

<PropertyGroup>
<!-- StyleSharp.Analyzers, PerformanceSharp.Analyzers and SecuritySharp.Analyzers ship from the
same release pipeline and always share a version. -->
<RoslynCommonAnalyzersVersion>3.39.2</RoslynCommonAnalyzersVersion>
<RoslynCommonAnalyzersVersion>3.45.0</RoslynCommonAnalyzersVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
19 changes: 5 additions & 14 deletions src/ReactiveUI.Binding.Analyzer/Analyzers/AnalyzerHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,9 @@ internal static class AnalyzerHelpers
/// <param name="methodSymbol">The method symbol to check.</param>
/// <returns>true if the method is from our generated extension class.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool IsBindingExtensionMethod(IMethodSymbol methodSymbol)
{
var containingType = methodSymbol.ContainingType;
if (containingType is null)
{
return false;
}

var name = containingType.Name;
return name is SourceGenerators.Constants.GeneratedExtensionClassName
internal static bool IsBindingExtensionMethod(IMethodSymbol methodSymbol) =>
methodSymbol.ContainingType?.Name is SourceGenerators.Constants.GeneratedExtensionClassName
or SourceGenerators.Constants.StubExtensionClassName;
}

/// <summary>Checks if an expression is an inline lambda (not a variable reference or method call).</summary>
/// <param name="expression">The expression to check.</param>
Expand Down Expand Up @@ -125,7 +116,7 @@ internal static bool LacksObservableMechanism(
out INamedTypeSymbol? sourceType)
{
sourceType = ExtractFirstTypeArgument(methodSymbol);
return sourceType is null ? false : !TypeAnalyzer.HasObservableMechanism(sourceType, compilation);
return sourceType is not null && !TypeAnalyzer.HasObservableMechanism(sourceType, compilation);
}

/// <summary>
Expand All @@ -145,7 +136,7 @@ internal static bool LacksBeforeChangeSupport(
{
mechanism = string.Empty;
receiverType = ExtractFirstTypeArgument(methodSymbol);
return receiverType is null ? false : !HasBeforeChangeSupport(receiverType, compilation, out mechanism);
return receiverType is not null && !HasBeforeChangeSupport(receiverType, compilation, out mechanism);
}

/// <summary>
Expand All @@ -171,7 +162,7 @@ internal static bool ImplementsDataErrorInfo(

var dataErrorInfo =
compilation.GetTypeByMetadataName(SourceGenerators.Constants.INotifyDataErrorInfoMetadataName);
return dataErrorInfo is null ? false : ImplementsInterface(sourceType, dataErrorInfo);
return dataErrorInfo is not null && ImplementsInterface(sourceType, dataErrorInfo);
}

/// <summary>Determines whether a type implements a specific interface.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal static void AnalyzeInvocation(in OperationAnalysisContext context)
var arguments = invocationOp.Arguments;

// Check RXUIBIND001: Non-inline lambda
CheckNonInlineLambda(context, arguments, methodName);
CheckNonInlineLambda(context, arguments);

// Check RXUIBIND003: Private/protected member access
CheckPrivateMember(context, arguments);
Expand Down Expand Up @@ -95,11 +95,9 @@ internal static void AnalyzeInvocation(in OperationAnalysisContext context)
/// <summary>Checks for RXUIBIND001: Expression arguments that are not inline lambdas.</summary>
/// <param name="context">The operation analysis context.</param>
/// <param name="arguments">The invocation arguments to inspect.</param>
/// <param name="methodName">The name of the method being invoked.</param>
internal static void CheckNonInlineLambda(
in OperationAnalysisContext context,
ImmutableArray<IArgumentOperation> arguments,
string methodName)
ImmutableArray<IArgumentOperation> arguments)
{
// Find the Expression<Func<...>> arguments
for (var i = 0; i < arguments.Length; i++)
Expand Down Expand Up @@ -458,22 +456,13 @@ internal static void WalkForUnsupportedSegments(
}

/// <summary>Extracts the body expression from a lambda expression syntax node.</summary>
/// <remarks>Only <see cref="SimpleLambdaExpressionSyntax"/> and <see cref="ParenthesizedLambdaExpressionSyntax"/> exist in Roslyn's C# syntax model.</remarks>
/// <param name="lambda">The lambda expression syntax node to extract the body from.</param>
/// <returns>
/// The body as an <see cref="ExpressionSyntax"/>, or <c>null</c> if the lambda body is a block statement.
/// </returns>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
internal static ExpressionSyntax? GetLambdaBody(LambdaExpressionSyntax lambda)
{
if (lambda is SimpleLambdaExpressionSyntax simple)
{
return simple.Body as ExpressionSyntax;
}

var parenthesized = (ParenthesizedLambdaExpressionSyntax)lambda;
return parenthesized.Body as ExpressionSyntax;
}
internal static ExpressionSyntax? GetLambdaBody(LambdaExpressionSyntax lambda) =>
lambda.Body as ExpressionSyntax;

/// <summary>Determines whether a non-empty constant <c>toEvent</c> argument was explicitly supplied.</summary>
/// <param name="arguments">The invocation arguments to inspect.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ public enum BooleanToVisibilityHints
Inverse = 1 << 1,

/// <summary>Use the Hidden value rather than Collapsed (MAUI only; ignored on WinUI where Hidden is not available).</summary>
UseHidden = 1 << 2
UseHidden = 1 << 2,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// ReactiveUI Association Incorporated 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;
using Splat.Builder;

#if REACTIVE_SHIM
Expand All @@ -22,6 +23,7 @@ public static class MauiBindingBuilderExtensions
/// observation (on Windows) and Visibility converters.
/// </summary>
/// <returns>The builder instance for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IReactiveUIBindingBuilder WithMaui() =>
((IReactiveUIBindingBuilder)builder).WithMaui();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang

var dependencyProperty = dependencyPropertyFetcher();
var token = depSender.RegisterPropertyChangedCallback(dependencyProperty, handler);
return new ActionDisposable<(DependencyObject sender, DependencyProperty property, long token)>(
return new ActionDisposable<(DependencyObject Sender, DependencyProperty Property, long Token)>(
(depSender, dependencyProperty, token),
static state => state.sender.UnregisterPropertyChangedCallback(state.property, state.token));
static state => state.Sender.UnregisterPropertyChangedCallback(state.Property, state.Token));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace ReactiveUI.Binding.Observables;
/// Runs a teardown action against a state value exactly once. Carrying the state lets the platform
/// observers unhook with a non-capturing lambda, so no closure is allocated per subscription.
/// </summary>
/// <remarks>Each platform assembly compiles its own internal copy; nothing here touches the seam.</remarks>
/// <typeparam name="TState">The type of the state handed to the teardown action.</typeparam>
/// <remarks>Each platform assembly compiles its own internal copy; nothing here touches the seam.</remarks>
internal sealed class ActionDisposable<TState> : IDisposable
{
/// <summary>The state handed to <see cref="_action"/> on disposal.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ namespace ReactiveUI.Binding.Observables;
/// An observable whose subscription logic is supplied as a delegate, for the platform observers that
/// hook an event on subscribe and hand back the unhook as the subscription.
/// </summary>
/// <typeparam name="T">The type of the elements in the sequence.</typeparam>
/// <remarks>
/// Each platform assembly compiles its own internal copy, so this stays off the public surface of every
/// package and out of the seam: it names no scheduler and no notification type.
/// </remarks>
/// <typeparam name="T">The type of the elements in the sequence.</typeparam>
internal sealed class AnonymousObservable<T> : IObservable<T>
{
/// <summary>Produces the subscription for an observer, returning the resource that tears it down.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace ReactiveUI.Binding;
/// object-based shim (<see cref="TryConvertTyped(object?, object?, out object?)"/>), allowing the dispatch
/// layer to avoid reflection.
/// </remarks>
[DebuggerDisplay("{FromType.Name,nq} -> {ToType.Name,nq} converter")]
public abstract class BindingTypeConverter<TFrom, TTo> : IBindingTypeConverter<TFrom, TTo>
{
/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
namespace ReactiveUI.Binding;
#endif

/// <summary>Converts <see cref="byte"/> to a nullable <see cref="byte"/>.</summary>
[DebuggerDisplay("byte -> byte? (affinity {Affinity})")]
public sealed class ByteToNullableByteTypeConverter : IBindingTypeConverter<byte, byte?>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -21,6 +24,7 @@ public sealed class ByteToNullableByteTypeConverter : IBindingTypeConverter<byte
public Type ToType => typeof(byte?);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
namespace ReactiveUI.Binding;
#endif

/// <summary>Converts <see cref="decimal"/> to a nullable <see cref="decimal"/>.</summary>
[DebuggerDisplay("decimal -> decimal? (affinity {Affinity})")]
public sealed class DecimalToNullableDecimalTypeConverter : IBindingTypeConverter<decimal, decimal?>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -21,6 +24,7 @@ public sealed class DecimalToNullableDecimalTypeConverter : IBindingTypeConverte
public Type ToType => typeof(decimal?);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
namespace ReactiveUI.Binding;
#endif

/// <summary>Converts <see cref="double"/> to a nullable <see cref="double"/>.</summary>
[DebuggerDisplay("double -> double? (affinity {Affinity})")]
public sealed class DoubleToNullableDoubleTypeConverter : IBindingTypeConverter<double, double?>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -21,6 +24,7 @@ public sealed class DoubleToNullableDoubleTypeConverter : IBindingTypeConverter<
public Type ToType => typeof(double?);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
Expand All @@ -19,6 +21,7 @@ namespace ReactiveUI.Binding;
/// Example: Convert an enum value to bool by comparing with a specific enum member.
/// </para>
/// </remarks>
[DebuggerDisplay("{FromType.Name,nq} -> {ToType.Name,nq} by equality with the conversion hint")]
public sealed class EqualityTypeConverter : IBindingTypeConverter
{
/// <inheritdoc/>
Expand All @@ -28,6 +31,7 @@ public sealed class EqualityTypeConverter : IBindingTypeConverter
public Type ToType => typeof(bool);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => 1;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
namespace ReactiveUI.Binding;
#endif

/// <summary>Converts <see cref="int"/> to a nullable <see cref="int"/>.</summary>
[DebuggerDisplay("int -> int? (affinity {Affinity})")]
public sealed class IntegerToNullableIntegerTypeConverter : IBindingTypeConverter<int, int?>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -21,6 +24,7 @@ public sealed class IntegerToNullableIntegerTypeConverter : IBindingTypeConverte
public Type ToType => typeof(int?);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
namespace ReactiveUI.Binding;
#endif

/// <summary>Converts <see cref="long"/> to a nullable <see cref="long"/>.</summary>
[DebuggerDisplay("long -> long? (affinity {Affinity})")]
public sealed class LongToNullableLongTypeConverter : IBindingTypeConverter<long, long?>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -21,6 +24,7 @@ public sealed class LongToNullableLongTypeConverter : IBindingTypeConverter<long
public Type ToType => typeof(long?);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
Expand All @@ -12,6 +14,7 @@ namespace ReactiveUI.Binding;
/// <remarks>
/// When the nullable value is null, the conversion fails and returns false.
/// </remarks>
[DebuggerDisplay("byte? -> byte (affinity {Affinity})")]
public sealed class NullableByteToByteTypeConverter : IBindingTypeConverter<byte?, byte>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -24,6 +27,7 @@ public sealed class NullableByteToByteTypeConverter : IBindingTypeConverter<byte
public Type ToType => typeof(byte);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// ReactiveUI Association Incorporated 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;

#if REACTIVE_SHIM
namespace ReactiveUI.Binding.Reactive;
#else
Expand All @@ -12,6 +14,7 @@ namespace ReactiveUI.Binding;
/// <remarks>
/// When the nullable value is null, the conversion fails and returns false.
/// </remarks>
[DebuggerDisplay("decimal? -> decimal (affinity {Affinity})")]
public sealed class NullableDecimalToDecimalTypeConverter : IBindingTypeConverter<decimal?, decimal>
{
/// <summary>The affinity returned by <see cref="GetAffinityForObjects"/> indicating a strong match.</summary>
Expand All @@ -24,6 +27,7 @@ public sealed class NullableDecimalToDecimalTypeConverter : IBindingTypeConverte
public Type ToType => typeof(decimal);

/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetAffinityForObjects() => Affinity;

/// <inheritdoc/>
Expand Down
Loading
Loading