Skip to content

Commit d85a540

Browse files
authored
Fixed issues of attached entities and the unique case of TargetProperty attached property. (#576)
* Fixed the issue of dual property const * Added tests for attached entities and fix typos * update * update * Switch to external WPF reference for build failure on macOS. * Fixed attached events and dropped WPF * Setting the test case of WPF conditionally on different platforms * update
1 parent fd9de01 commit d85a540

5 files changed

Lines changed: 131 additions & 53 deletions

File tree

2 MB
Binary file not shown.

mdoc/Consts.cs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,47 @@
11
using System;
22
namespace Mono.Documentation
33
{
4-
public static class Consts
5-
{
6-
public static string MonoVersion = "5.8.4";
7-
public const string DocId = "DocId";
8-
public const string CppCli = "C++ CLI";
9-
public const string CppCx = "C++ CX";
10-
public const string CppWinRt = "C++ WINRT";
4+
public static class Consts
5+
{
6+
public static string MonoVersion = "5.8.4";
7+
public const string DocId = "DocId";
8+
public const string CppCli = "C++ CLI";
9+
public const string CppCx = "C++ CX";
10+
public const string CppWinRt = "C++ WINRT";
1111
public const string CSharp = "C#";
1212
public const string VbNet = "VB.NET";
13-
public const string DocIdLowCase = "docid";
14-
public const string VbNetLowCase = "vb.net";
15-
public const string CppCliLowCase = "c++/cli";
13+
public const string DocIdLowCase = "docid";
14+
public const string VbNetLowCase = "vb.net";
15+
public const string CppCliLowCase = "c++/cli";
1616
public const string CppCxLowCase = "c++/cx";
17-
public const string CppWinRtLowCase = "c++/winrt";
18-
public const string Tab = " ";
19-
public const string FSharp = "F#";
20-
public const string FSharpLowCase = "f#";
21-
public const string Javascript = "JavaScript";
22-
public const string JavascriptLowCase = "javascript";
17+
public const string CppWinRtLowCase = "c++/winrt";
18+
public const string Tab = " ";
19+
public const string FSharp = "F#";
20+
public const string FSharpLowCase = "f#";
21+
public const string Javascript = "JavaScript";
22+
public const string JavascriptLowCase = "javascript";
2323

24-
public const string DependencyPropertyFullName = "System.Windows.DependencyProperty";
24+
public const string DependencyPropertyFullName = "System.Windows.DependencyProperty";
2525
public const string DependencyPropertyFullNameWindowsXaml = "Windows.UI.Xaml.DependencyProperty";
2626
public const string DependencyPropertyFullNameMicrosoftXaml = "Microsoft.UI.Xaml.DependencyProperty";
2727

2828
public const string DependencyObjectFullName = "System.Windows.DependencyObject";
29-
public const string DependencyObjectFullNameXaml = "Windows.UI.Xaml.DependencyObject";
29+
public const string DependencyObjectFullNameWinRT = "Windows.UI.Xaml.DependencyObject";
30+
public const string DependencyObjectFullNameWinUI = "Microsoft.UI.Xaml.DependencyObject";
31+
32+
public const string RoutedEventFullName = "System.Windows.RoutedEvent";
33+
public const string RoutedEventFullNameWinRT = "Windows.UI.Xaml.RoutedEvent";
34+
public const string RoutedEventFullNameWinUI = "Microsoft.UI.Xaml.RoutedEvent";
35+
3036
public const string DependencyPropertyFullNameIInputElement = "System.Windows.IInputElement";
3137
public const string DependencyPropertyFullNameObject = "System.Object";
3238
public const string VoidFullName = "System.Void";
33-
public const string RefTypeObsoleteString = "Types with embedded references are not supported in this version of your compiler.";
34-
public const string FrameworksIndexFolderName = "FrameworksIndex";
35-
public const string CompilerGeneratedAttribute = "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
36-
public const string CompilationMappingAttribute = "Microsoft.FSharp.Core.CompilationMappingAttribute";
39+
public const string RefTypeObsoleteString = "Types with embedded references are not supported in this version of your compiler.";
40+
public const string FrameworksIndexFolderName = "FrameworksIndex";
41+
public const string CompilerGeneratedAttribute = "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
42+
public const string CompilationMappingAttribute = "Microsoft.FSharp.Core.CompilationMappingAttribute";
3743
public const string FrameworksIndex = "FrameworksIndex";
38-
public const string FrameworkAlternate = "FrameworkAlternate";
44+
public const string FrameworkAlternate = "FrameworkAlternate";
3945
public const string Index = "Index";
4046

4147
public static bool CollapseInheritedInterfaces = true;

mdoc/Mono.Documentation/Util/AttachedEntitiesHelper.cs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ public static IEnumerable<MemberReference> GetAttachedEntities(TypeDefinition ty
3232
{
3333
yield return attachedEventReference;
3434
}
35-
foreach (var attachedEventProperty in GetAttachedProperties(type, methodsLookUpTable))
35+
foreach (var attachedPropertyReference in GetAttachedProperties(type, methodsLookUpTable))
3636
{
37-
yield return attachedEventProperty;
37+
yield return attachedPropertyReference;
3838
}
3939
}
4040

@@ -62,7 +62,9 @@ private static bool IsAttachedEvent(FieldDefinition field, Dictionary<string, IE
6262
var removeMethodName = $"Remove{GetEventName(field.Name)}Handler";
6363
return
6464
// WPF implements attached events as routed events; the identifier to use for an event (RoutedEvent) is already defined by the WPF event system
65-
IsAssignableTo(field.FieldType, "System.Windows.RoutedEvent")
65+
(IsAssignableTo(field.FieldType, Consts.RoutedEventFullName) ||
66+
IsAssignableTo(field.FieldType, Consts.RoutedEventFullNameWinRT) ||
67+
IsAssignableTo(field.FieldType, Consts.RoutedEventFullNameWinUI))
6668
&& field.IsPublic
6769
&& field.IsStatic
6870
&& field.IsInitOnly
@@ -90,9 +92,11 @@ private static bool AreAttachedEventMethodParameters(Collection<ParameterDefinit
9092
return false;
9193
return
9294
// The first parameter is DependencyObject
93-
IsAssignableTo(parameters[0].ParameterType, "System.Windows.DependencyObject")
94-
95-
// The second parameter is the handler to add/remove
95+
(IsAssignableTo(parameters[0].ParameterType, Consts.DependencyObjectFullName) ||
96+
IsAssignableTo(parameters[0].ParameterType, Consts.DependencyObjectFullNameWinRT) ||
97+
IsAssignableTo(parameters[0].ParameterType, Consts.DependencyObjectFullNameWinUI))
98+
99+
// The second parameter is the handler to add/remove
96100
&& IsAttachedEventHandler(parameters[1].ParameterType);
97101
}
98102

@@ -130,12 +134,14 @@ private static bool IsAttachedProperty(FieldDefinition field, Dictionary<string,
130134
// https://github.com/mono/api-doc-tools/issues/63#issuecomment-328995418
131135
if (!field.Name.EndsWith(PropertyConst, StringComparison.Ordinal))
132136
return false;
133-
var propertyName = GetPropertyName(field.Name);
137+
var propertyName = GetPropertyName(field.Name);
134138
var getMethodName = $"Get{propertyName}";
135139
var setMethodName = $"Set{propertyName}";
136140

137-
var hasExistingProperty = field?.DeclaringType?.Properties.Any (p => p.Name.Equals (propertyName, System.StringComparison.Ordinal) && GetCheckVisible(p.Resolve()));
138-
var hasExistingField = field?.DeclaringType?.Fields.Any (f => f.Name.Equals (propertyName, System.StringComparison.Ordinal) && GetCheckVisible(f.Resolve()));
141+
var hasDualPropertyConst = propertyName.EndsWith(PropertyConst, StringComparison.Ordinal);
142+
var hasExistingProperty = field?.DeclaringType?.Properties.Any (p => p.Name.Equals (propertyName, StringComparison.Ordinal) && GetCheckVisible(p.Resolve()));
143+
var hasExistingField = hasDualPropertyConst ? false :
144+
field?.DeclaringType?.Fields.Any (f => f.Name.Equals (propertyName, StringComparison.Ordinal) && GetCheckVisible(f.Resolve()));
139145

140146
return !hasExistingProperty.IsTrue () && !hasExistingField.IsTrue () &&
141147
// Class X has a static field of type DependencyProperty [Name]Property
@@ -145,7 +151,7 @@ private static bool IsAttachedProperty(FieldDefinition field, Dictionary<string,
145151
&& field.IsStatic
146152
&& field.IsInitOnly
147153

148-
// Class X also has static methods with the following names: Get[Name] and Set[Name]
154+
// Class X also has static methods with the following names: Get[Name] or Set[Name]
149155
&& ((methods.ContainsKey(getMethodName) && methods[getMethodName].Any(IsAttachedPropertyGetMethod))
150156
|| (methods.ContainsKey(setMethodName) && methods[setMethodName].Any(IsAttachedPropertySetMethod)));
151157

@@ -160,16 +166,16 @@ private static bool IsAttachedProperty(PropertyDefinition property, Dictionary<s
160166
var getMethodName = $"Get{propertyName}";
161167
var setMethodName = $"Set{propertyName}";
162168

163-
var hasExistingProperty = property?.DeclaringType?.Properties.Any(p => p.Name.Equals(propertyName, System.StringComparison.Ordinal) && GetCheckVisible(p.Resolve()));
164-
var hasExistingField = property?.DeclaringType?.Fields.Any(f => f.Name.Equals(propertyName, System.StringComparison.Ordinal) && GetCheckVisible(f.Resolve()));
169+
var hasExistingProperty = property?.DeclaringType?.Properties.Any(p => p.Name.Equals(propertyName, StringComparison.Ordinal) && GetCheckVisible(p.Resolve()));
170+
var hasExistingField = property?.DeclaringType?.Fields.Any(f => f.Name.Equals(propertyName, StringComparison.Ordinal) && GetCheckVisible(f.Resolve()));
165171

166172
return !hasExistingProperty.IsTrue() && !hasExistingField.IsTrue() &&
167173
// Class X has a static field of type DependencyProperty [Name]Property
168174
(property.PropertyType.FullName == Consts.DependencyPropertyFullName || property.PropertyType.FullName == Consts.DependencyPropertyFullNameWindowsXaml
169175
|| property.PropertyType.FullName == Consts.DependencyPropertyFullNameMicrosoftXaml)
170176

171177

172-
// Class X also has static methods with the following names: Get[Name] and Set[Name]
178+
// Class X also has static methods with the following names: Get[Name] or Set[Name]
173179
&& ((methods.ContainsKey(getMethodName) && methods[getMethodName].Any(IsAttachedPropertyGetMethod))
174180
|| (methods.ContainsKey(setMethodName) && methods[setMethodName].Any(IsAttachedPropertySetMethod)));
175181

@@ -183,16 +189,21 @@ private static bool IsAttachedPropertyGetMethod(MethodDefinition method)
183189
// && IsAssignableTo(method.ReturnType, "");
184190

185191
// The Get method takes one argument of type DependencyObject(or something IsAssignableTo(DependencyObject),
186-
&& (IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullName) || IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullNameXaml));
192+
&& (IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullName) ||
193+
IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullNameWinRT) ||
194+
IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullNameWinUI));
187195
}
188196

189197
private static bool IsAttachedPropertySetMethod(MethodDefinition method)
190198
{
191199
return method.Parameters.Count == 2// The Set method takes two arguments.
192200

193201
// The first has type DependencyObject(or IsAssignableTo…),
194-
&& (IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullName) || IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullNameXaml)
195-
|| IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyPropertyFullNameIInputElement) || IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyPropertyFullNameObject))
202+
&& (IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullName) ||
203+
IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullNameWinRT) ||
204+
IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyObjectFullNameWinUI) ||
205+
IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyPropertyFullNameIInputElement) ||
206+
IsAssignableTo(method.Parameters[0].ParameterType, Consts.DependencyPropertyFullNameObject))
196207

197208
// the second has type dp.PropertyType (or IsAssignableTo…).
198209
// && IsAssignableTo(method.Parameters[1].ParameterType, "")

mdoc/mdoc.Test/Enumeration/AttachedEntityTests.cs

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
using NUnit.Framework;
22
using System;
3-
using System.Collections.Generic;
43
using System.Linq;
5-
using System.Text;
6-
using System.Threading.Tasks;
7-
using Mono.Documentation.Util;
84
using Windows.UI.Xaml;
5+
using Mono.Documentation.Util;
96
using Mono.Documentation.Updater;
107
using Mono.Documentation.Updater.Formatters;
118

@@ -26,7 +23,7 @@ public void Test_NoEntities()
2623
[TestCase]
2724
public void Test_AttachedProperty()
2825
{
29-
var type = GetTypeDef<AttachedTestClass>();
26+
var type = GetTypeDef<AttachedPropertyTestClass>();
3027
var list = AttachedEntitiesHelper.GetAttachedEntities(type);
3128

3229
Assert.AreEqual(3, list.Count());
@@ -37,7 +34,7 @@ public void Test_AttachedProperty_Formatter()
3734
{
3835
string expected = "see GetSome, and SetSome";
3936

40-
var type = GetTypeDef<AttachedTestClass>();
37+
var type = GetTypeDef<AttachedPropertyTestClass>();
4138
var list = AttachedEntitiesHelper.GetAttachedEntities(type);
4239

4340
MemberFormatter formatter = new CSharpMemberFormatter();
@@ -50,7 +47,7 @@ public void Test_AttachedProperty_Formatter_GetOnly()
5047
{
5148
string expected = "see GetSomeGet";
5249

53-
var type = GetTypeDef<AttachedTestClass>();
50+
var type = GetTypeDef<AttachedPropertyTestClass>();
5451
var list = AttachedEntitiesHelper.GetAttachedEntities(type);
5552

5653
MemberFormatter formatter = new CSharpMemberFormatter();
@@ -63,7 +60,7 @@ public void Test_AttachedProperty_Formatter_SetOnly()
6360
{
6461
string expected = "see SetSomeSet";
6562

66-
var type = GetTypeDef<AttachedTestClass>();
63+
var type = GetTypeDef<AttachedPropertyTestClass>();
6764
var list = AttachedEntitiesHelper.GetAttachedEntities(type);
6865

6966
MemberFormatter formatter = new CSharpMemberFormatter();
@@ -72,17 +69,56 @@ public void Test_AttachedProperty_Formatter_SetOnly()
7269
}
7370

7471
[TestCase]
75-
public void Test_AttachedProperty_Property()
72+
public void Test_AttachedEntities()
7673
{
77-
var type = GetTypeDef<AttachedPropertyTestClass>();
78-
Assert.AreEqual(1, type.Properties.Count(t => t.Name == "AttributeAttachProperty"));
74+
var type = GetTypeDef<AttachedEntitiesTestClass>();
75+
Assert.IsTrue(type.Fields.Any(t => t.Name == "TestingEvent"));
76+
Assert.IsTrue(type.Fields.Any(t => t.Name == "TargetProperty"));
77+
Assert.IsTrue(type.Fields.Any(t => t.Name == "TargetPropertyProperty"));
78+
Assert.IsTrue(type.Properties.Any(t => t.Name == "AttributeAttachProperty"));
79+
80+
var list = AttachedEntitiesHelper.GetAttachedEntities(type);
81+
Assert.AreEqual(4, list.Count());
82+
Assert.IsTrue(list.Any(t => t.Name == "Testing" && t is AttachedEventReference));
83+
Assert.IsTrue(list.Any(t => t.Name == "Target" && t is AttachedPropertyReference));
84+
Assert.IsTrue(list.Any(t => t.Name == "TargetProperty" && t is AttachedPropertyReference));
85+
Assert.IsTrue(list.Any(t => t.Name == "AttributeAttach" && t is AttachedPropertyReference));
86+
}
87+
88+
[TestCase(IncludePlatform = "Win32NT")]
89+
public void Test_AttachedEntities_NetFramework()
90+
{
91+
var os = Environment.OSVersion;
92+
Console.WriteLine("OS platform is: {0}", os.Platform.ToString());
93+
94+
var type = GetTypeDef<System.Windows.Media.Animation.Storyboard>();
7995
var list = AttachedEntitiesHelper.GetAttachedEntities(type);
80-
Assert.AreEqual("AttributeAttach", list.FirstOrDefault(t => t.Name == "AttributeAttach").Name);
96+
Assert.AreEqual(3, list.Count());
97+
Assert.IsTrue(type.Fields.Any(t => t.Name == "TargetProperty"));
98+
Assert.IsTrue(type.Fields.Any(t => t.Name == "TargetPropertyProperty"));
99+
Assert.IsTrue(list.Any(t => t.Name == "Target" && t is AttachedPropertyReference));
100+
Assert.IsTrue(list.Any(t => t.Name == "TargetProperty" && t is AttachedPropertyReference));
101+
102+
type = GetTypeDef<System.Windows.Controls.Primitives.Selector>();
103+
list = AttachedEntitiesHelper.GetAttachedEntities(type);
104+
Assert.AreEqual(4, list.Count());
105+
Assert.IsTrue(list.Any(t => t.Name == "IsSelected" && t is AttachedPropertyReference));
106+
Assert.IsTrue(list.Any(t => t.Name == "IsSelectionActive" && t is AttachedPropertyReference));
107+
Assert.IsTrue(list.Any(t => t.Name == "Selected" && t is AttachedEventReference));
108+
Assert.IsTrue(list.Any(t => t.Name == "Unselected" && t is AttachedEventReference));
109+
110+
type = GetTypeDef<Windows.UI.Xaml.Media.Animation.Storyboard>();
111+
list = AttachedEntitiesHelper.GetAttachedEntities(type);
112+
Assert.AreEqual(2, list.Count());
113+
Assert.IsTrue(type.Properties.Any(t => t.Name == "TargetNameProperty"));
114+
Assert.IsTrue(type.Properties.Any(t => t.Name == "TargetPropertyProperty"));
115+
Assert.IsTrue(list.Any(t => t.Name == "TargetName" && t is AttachedPropertyReference));
116+
Assert.IsTrue(list.Any(t => t.Name == "TargetProperty" && t is AttachedPropertyReference));
81117
}
82118

83119
public class AttachedTestClassNoAttachedEntities { }
84120

85-
public class AttachedTestClass
121+
public class AttachedPropertyTestClass
86122
{
87123
public static readonly DependencyProperty SomeProperty;
88124
public static bool GetSome(DependencyObject obj) { return false; }
@@ -102,11 +138,32 @@ public static void SetSomeSet(DependencyObject obj, bool val) { }
102138
public static void SetSomeNotReadOnly(DependencyObject obj, bool val) { }
103139
}
104140

105-
public class AttachedPropertyTestClass
141+
public class AttachedEntitiesTestClass
106142
{
107143
public DependencyProperty AttributeAttachProperty { get; set; }
108144
public static bool GetAttributeAttach(DependencyObject obj) { return false; }
109145
public static void SetAttributeAttach(DependencyObject obj, bool val) { }
146+
147+
public static readonly DependencyProperty TargetProperty;
148+
public static bool GetTarget(DependencyObject obj) { return false; }
149+
public static void SetTarget(DependencyObject obj, bool val) { }
150+
151+
public delegate void EventHandler(object sender, EventArgs e);
152+
public static readonly RoutedEvent TestingEvent;
153+
public static void AddTestingHandler(DependencyObject element, EventHandler handler) { }
154+
public static void RemoveTestingHandler(DependencyObject element, EventHandler handler) { }
155+
156+
public static readonly DependencyProperty TargetPropertyProperty;
157+
public static string GetTargetProperty(DependencyObject obj)
158+
{
159+
if (obj == null) { throw new ArgumentNullException("obj"); }
160+
return (string)obj.GetValue(TargetPropertyProperty);
161+
}
162+
public static void SetTargetProperty(DependencyObject obj, string val)
163+
{
164+
if (obj == null) { throw new ArgumentNullException("obj"); }
165+
obj.SetValue(TargetPropertyProperty, val);
166+
}
110167
}
111168
}
112169
}

0 commit comments

Comments
 (0)