Repository: dotnet/maui
File: src/Controls/src/SourceGen/SetPropertyHelpers.cs (C#)

Code before:
	{
		var fullName = $"{bpFieldSymbol.ContainingType.ToFQDisplayString()}.{bpFieldSymbol.Name}";
		return TwoWayBindableProperties.Contains(fullName);
	}

	/// <summary>
	/// Checks if the terminal property in a C# expression chain is writable (has a public setter).
	/// For example, "Name" is writable if Name has a public set accessor, but "ReadOnlyProp" is not
	/// if it only has a getter (expression-bodied or getter-only property).
	/// Returns false for complex expressions that are not simple property chains.
	/// </summary>
	static bool IsExpressionWritable(string expression, ITypeSymbol dataType, SourceGenContext context)
	{
		if (string.IsNullOrWhiteSpace(expression))
			return false;

		var expr = expression.Trim();

		// Strip leading dot prefix (e.g., ".Name" → "Name"), but avoid the ".." range operator
		if (expr.StartsWith(".", StringComparison.Ordinal) &&
			!expr.StartsWith("..", StringComparison.Ordinal))
			expr = expr.Substring(1);

		// Strip "BindingContext." prefix (e.g., "BindingContext.Name" → "Name")
		if (expr.StartsWith("BindingContext.", StringComparison.Ordinal))
			expr = expr.Substring("BindingContext.".Length);

		if (string.IsNullOrEmpty(expr))
			return false;

		// Walk the dot-separated property chain (also handle ?. null-conditional access)
		var parts = expr.Replace("?.", ".").Split('.');
		var currentType = dataType;
		IPropertySymbol? lastProperty = null;

		foreach (var part in parts)
		{
			var memberName = part.Trim().TrimEnd('!');

			// If it contains parens, operators, or special chars, it's not a simple property chain
			if (memberName.Contains('(') || memberName.Contains(' ') || memberName.Contains('[') || string.IsNullOrEmpty(memberName))
				return false;

			var member = currentType.GetAllMembers(memberName, context).FirstOrDefault();
			if (member is IPropertySymbol prop)
			{
				lastProperty = prop;
				currentType = prop.Type;
			}
			else if (member is IFieldSymbol field)
			{

Review comment (suggestion):
Should this somehow check if it is actually `BindableObject.BindingContext`?

You could have a POCO that has `public Person BindingContext;`

Code after:
	/// </summary>
	static bool IsTwoWayByDefault(IFieldSymbol bpFieldSymbol)
	{
		var fullName = $"{bpFieldSymbol.ContainingType.ToFQDisplayString()}.{bpFieldSymbol.Name}";
		return TwoWayBindableProperties.Contains(fullName);
	}

	/// <summary>
	/// Checks if the terminal property in a C# expression chain is writable (has a public setter).
	/// For example, "Name" is writable if Name has a public set accessor, but "ReadOnlyProp" is not
	/// if it only has a getter (expression-bodied or getter-only property).
	/// Returns false for complex expressions that are not simple property chains.
	/// </summary>
	static bool IsExpressionWritable(string expression, ITypeSymbol dataType, SourceGenContext context)
	{
		if (string.IsNullOrWhiteSpace(expression))
			return false;

		var expr = expression.Trim();

		// Strip leading dot prefix (e.g., ".Name" → "Name"), but avoid the ".." range operator
		if (expr.StartsWith(".", StringComparison.Ordinal) &&
			!expr.StartsWith("..", StringComparison.Ordinal))
			expr = expr.Substring(1);

		// Strip "BindingContext." prefix only when it refers to BindableObject.BindingContext,
		// not a user-defined member with the same name (e.g., a POCO with `public Person BindingContext;`)
		if (expr.StartsWith("BindingContext.", StringComparison.Ordinal)
			&& !dataType.GetAllMembers("BindingContext", context).Any())
			expr = expr.Substring("BindingContext.".Length);

		if (string.IsNullOrEmpty(expr))
			return false;

		// Walk the dot-separated property chain (also handle ?. null-conditional access)
		var parts = expr.Replace("?.", ".").Split('.');
		var currentType = dataType;
		IPropertySymbol? lastProperty = null;

		foreach (var part in parts)
		{
			var memberName = part.Trim().TrimEnd('!');

			// If it contains parens, operators, or special chars, it's not a simple property chain
			if (memberName.Contains('(') || memberName.Contains(' ') || memberName.Contains('[') || string.IsNullOrEmpty(memberName))
				return false;

			var member = currentType.GetAllMembers(memberName, context).FirstOrDefault();
			if (member is IPropertySymbol prop)
			{
				lastProperty = prop;