Skip to content

Commit

Permalink
Attached properties will now accept a Property DP.
Browse files Browse the repository at this point in the history
Closes #426
  • Loading branch information
joelmartinez committed May 23, 2019
1 parent 96bdf48 commit 1d93914
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 32 deletions.
64 changes: 46 additions & 18 deletions mdoc/Mono.Documentation/Util/AttachedEntitiesHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,34 +114,62 @@ private static IEnumerable<AttachedPropertyReference> GetAttachedProperties(Type
if (IsAttachedProperty(field, methods))
yield return new AttachedPropertyReference(field);
}
foreach (var prop in type.Properties)
{
if (IsAttachedProperty(prop, methods))
yield return new AttachedPropertyReference(prop);
}
}

private static bool IsAttachedProperty(FieldDefinition field, Dictionary<string, IEnumerable<MethodDefinition>> methods)
{
// https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/attached-properties-overview
// https://github.com/mono/api-doc-tools/issues/63#issuecomment-328995418
if (!field.Name.EndsWith(PropertyConst, StringComparison.Ordinal))
string fieldName = field.Name;
TypeReference fieldType = field.FieldType;
TypeDefinition declaringType = field?.DeclaringType;
bool isPublic = field.IsPublic;
bool isStatic = field.IsStatic;
bool isInitOnly = field.IsInitOnly;
return IsAttachedPropertyCore(methods, fieldName, fieldType, declaringType, isPublic, isStatic, isInitOnly);

}

private static bool IsAttachedProperty(PropertyDefinition prop, Dictionary<string, IEnumerable<MethodDefinition>> methods)
{
string fieldName = prop.Name;
TypeReference fieldType = prop.PropertyType;
TypeDefinition declaringType = prop?.DeclaringType;
bool isPublic = prop.GetMethod.IsPublic;
bool isStatic = prop.GetMethod.IsStatic;
bool isInitOnly = prop.SetMethod == null || !prop.SetMethod.IsPublic;
return IsAttachedPropertyCore(methods, fieldName, fieldType, declaringType, isPublic, isStatic, isInitOnly);

}

private static bool IsAttachedPropertyCore(Dictionary<string, IEnumerable<MethodDefinition>> methods, string fieldName, TypeReference fieldType, TypeDefinition declaringType, bool isPublic, bool isStatic, bool isInitOnly)
{
// https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/attached-properties-overview
// https://github.com/mono/api-doc-tools/issues/63#issuecomment-328995418
if (!fieldName.EndsWith(PropertyConst, StringComparison.Ordinal))
return false;
var propertyName = GetPropertyName(field.Name);
var propertyName = GetPropertyName(fieldName);
var getMethodName = $"Get{propertyName}";
var setMethodName = $"Set{propertyName}";

var hasExistingProperty = field?.DeclaringType?.Properties.Any (p => p.Name.Equals (propertyName, System.StringComparison.Ordinal));
var hasExistingField = field?.DeclaringType?.Fields.Any (f => f.Name.Equals (propertyName, System.StringComparison.Ordinal));
var hasExistingProperty = declaringType?.Properties.Any(p => p.Name.Equals(propertyName, System.StringComparison.Ordinal));
var hasExistingField = declaringType?.Fields.Any(f => f.Name.Equals(propertyName, System.StringComparison.Ordinal));

return !hasExistingProperty.IsTrue () && !hasExistingField.IsTrue () &&
// Class X has a static field of type DependencyProperty [Name]Property
(field.FieldType.FullName == Consts.DependencyPropertyFullName || field.FieldType.FullName == Consts.DependencyPropertyFullNameXaml)
&& field.IsPublic
&& field.IsStatic
&& field.IsInitOnly

// Class X also has static methods with the following names: Get[Name] and Set[Name]
return !hasExistingProperty.IsTrue() && !hasExistingField.IsTrue() &&
// Class X has a static field of type DependencyProperty [Name]Property
(fieldType.FullName == Consts.DependencyPropertyFullName || fieldType.FullName == Consts.DependencyPropertyFullNameXaml)
&& isPublic
&& isStatic
&& isInitOnly

// Class X also has static methods with the following names: Get[Name] and Set[Name]
&& ((methods.ContainsKey(getMethodName) && methods[getMethodName].Any(IsAttachedPropertyGetMethod))
|| (methods.ContainsKey(setMethodName) && methods[setMethodName].Any(IsAttachedPropertySetMethod)));

}

|| (methods.ContainsKey(setMethodName) && methods[setMethodName].Any(IsAttachedPropertySetMethod)));
}

private static bool IsAttachedPropertyGetMethod(MethodDefinition method)
{
return method.Parameters.Count == 1
Expand Down
43 changes: 31 additions & 12 deletions mdoc/Mono.Documentation/Util/AttachedPropertyDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,65 @@ namespace Mono.Documentation.Util
{
public class AttachedPropertyDefinition : AttachedPropertyReference, IMemberDefinition
{
private readonly FieldDefinition fieldDefinition;
string defName;
Collection<CustomAttribute> defAttributes;
bool defHasAttributes, defIsSpecialName, defIsRuntimeSpecialName;
TypeDefinition defDeclaringType;


public AttachedPropertyDefinition(FieldDefinition fieldDefinition, MetadataToken metadataToken) : base(fieldDefinition)
{
this.fieldDefinition = fieldDefinition;
MetadataToken = metadataToken;
defName = fieldDefinition.Name;
defAttributes = fieldDefinition.CustomAttributes;
defHasAttributes = fieldDefinition.HasCustomAttributes;
defIsSpecialName = fieldDefinition.IsSpecialName;
defIsRuntimeSpecialName = fieldDefinition.IsRuntimeSpecialName;
defDeclaringType = fieldDefinition.DeclaringType;
}
public AttachedPropertyDefinition(PropertyDefinition propDefinition, MetadataToken metadataToken) : base(propDefinition)
{
MetadataToken = metadataToken;
defName = propDefinition.Name;
defAttributes = propDefinition.CustomAttributes;
defHasAttributes = propDefinition.HasCustomAttributes;
defIsSpecialName = propDefinition.IsSpecialName;
defIsRuntimeSpecialName = propDefinition.IsRuntimeSpecialName;
defDeclaringType = propDefinition.DeclaringType;
}

public MemberReference GetMethod
{
get => this.DeclaringType.GetMember(
$"Get{AttachedEntitiesHelper.GetPropertyName(fieldDefinition.Name)}",
$"Get{AttachedEntitiesHelper.GetPropertyName(defName)}",
m => (m as MethodReference)?.Parameters.Count == 1);
}
public MemberReference SetMethod
{
get => this.DeclaringType.GetMember(
$"Set{AttachedEntitiesHelper.GetPropertyName(fieldDefinition.Name)}",
$"Set{AttachedEntitiesHelper.GetPropertyName(defName)}",
m => (m as MethodReference)?.Parameters.Count == 2);
}

public Collection<CustomAttribute> CustomAttributes => fieldDefinition.CustomAttributes;
public bool HasCustomAttributes => fieldDefinition.HasCustomAttributes;
public Collection<CustomAttribute> CustomAttributes => defAttributes;
public bool HasCustomAttributes => defHasAttributes;

public bool IsSpecialName
{
get { return fieldDefinition.IsSpecialName; }
set { fieldDefinition.IsSpecialName = value; }
get { return defIsSpecialName; }
set { defIsSpecialName = value; }
}

public bool IsRuntimeSpecialName
{
get { return fieldDefinition.IsRuntimeSpecialName; }
set { fieldDefinition.IsRuntimeSpecialName = value; }
get { return defIsRuntimeSpecialName; }
set { defIsRuntimeSpecialName = value; }
}

public new TypeDefinition DeclaringType
{
get { return fieldDefinition.DeclaringType; }
set { fieldDefinition.DeclaringType = value; }
get { return defDeclaringType; }
set { defDeclaringType = value; }
}
}
}
16 changes: 14 additions & 2 deletions mdoc/Mono.Documentation/Util/AttachedPropertyReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,29 @@ namespace Mono.Documentation.Util
public class AttachedPropertyReference : FieldReference
{
private readonly FieldDefinition fieldDefinition;
private readonly PropertyDefinition propDefinition;
private AttachedPropertyDefinition definition;

public AttachedPropertyReference(FieldDefinition fieldDefinition) : base(AttachedEntitiesHelper.GetPropertyName(fieldDefinition.Name), fieldDefinition.FieldType, fieldDefinition.DeclaringType)
{
this.fieldDefinition = fieldDefinition;
}
public AttachedPropertyReference(PropertyDefinition propDefinition) : base(AttachedEntitiesHelper.GetPropertyName(propDefinition.Name), propDefinition.PropertyType, propDefinition.DeclaringType)
{
this.propDefinition = propDefinition;
}

protected override IMemberDefinition ResolveDefinition()
{
return definition ??
(definition = new AttachedPropertyDefinition(fieldDefinition, MetadataToken));
if (definition == null)
{
if (fieldDefinition != null)
definition = new AttachedPropertyDefinition(fieldDefinition, MetadataToken);

if (propDefinition != null)
definition = new AttachedPropertyDefinition(propDefinition, MetadataToken);
}
return definition;
}
}
}

0 comments on commit 1d93914

Please sign in to comment.