in ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/DeclaredElement/FSharpPropertyBase.cs [28:79]
private static (bool isReadable, bool isWriteable) GetReadWriteRights([NotNull] FSharpMemberOrFunctionOrValue prop)
{
bool IsWriteable(FSharpMemberOrFunctionOrValue mfv) =>
mfv.IsMutable || mfv.HasSetterMethod || mfv.IsPropertySetterMethod;
bool IsReadable(FSharpMemberOrFunctionOrValue mfv) =>
mfv.HasGetterMethod || mfv.IsPropertyGetterMethod ||
mfv.IsModuleValueOrMember && !mfv.IsMember;
var entity = prop.DeclaringEntity?.Value;
if (entity == null)
return (IsReadable(prop), IsWriteable(prop));
// Property returned in AccessorProperty currently returns HasSetterMethod = false.
// Workaround it by getting mfv property from declaring entity.
var name = prop.LogicalName;
var range = prop.DeclarationLocation;
var mfvs = entity.MembersFunctionsAndValues;
var propMfv = mfvs.FirstOrDefault(m => RangeModule.equals(m.DeclarationLocation, range) && m.LogicalName == name);
if (propMfv != null)
// Matching property is returned by Fcs
return (IsReadable(propMfv), IsWriteable(propMfv));
// Property isn't returned by Fcs for some reason, e.g. in explicit implementation.
// Trying to calculate info from accessors.
var isReadable = false;
var isWriteable = false;
foreach (var mfv in mfvs)
{
if (RangeModule.equals(mfv.DeclarationLocation, range) && mfv.DisplayNameCore == name)
{
if ($"get_{name}" == mfv.LogicalName)
{
var getterType = mfv.FullType;
if (getterType.IsFunctionType && getterType.GenericArguments[1].Equals(prop.FullType))
isReadable = true;
continue;
}
if ($"set_{name}" == mfv.LogicalName)
{
var getterType = mfv.FullType;
if (getterType.IsFunctionType && getterType.GenericArguments[0].Equals(prop.FullType))
isWriteable = true;
}
}
}
return (isReadable, isWriteable);
}