Skip to content

Commit

Permalink
Translate DS array to NET array for description (#11040)
Browse files Browse the repository at this point in the history
This fixes a bug where the description of Curve.SplitByParameter in the
library would show up a description of an obsoleted overload.

The cause of the issue was the inability of XmlDocumentationExtensions
to handle conversion from primitve DS arrays to their equivalent .NET
arrays. This made the module unable to find the exact overload, so it
resorted to a fallback which returns the first overload available,
which in this case was the incorrect one.

The problem is fixed for this particular instance, as it is now able to
find the exact overload. Note, however, that the mechanism is not
bullet-proof, as there is no guaranteed way to translate back a type
from DS to the original .NET type.
  • Loading branch information
mmisol authored Aug 24, 2020
1 parent f10b6bd commit c04ea0b
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 62 deletions.
14 changes: 14 additions & 0 deletions src/DynamoCore/Library/XmlDocumentationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ private static MemberDocumentNode GetMemberDocumentNode(
documentNode = documentNodes[fullyQualifiedName];
else
{
// Note that the following may take the incorrect overload.
// Unfortunately we can't map back to the exact .NET parameter types from the DS function descriptor.
var overloadedName = documentNodes.Keys.
Where(key => key.Contains(function.ClassName + "." + function.FunctionName)).FirstOrDefault();

Expand Down Expand Up @@ -199,6 +201,10 @@ private static string GetMemberElement(
}
}

/// <summary>
/// Attempts to translate a DS type into a .NET type. Note that,
/// given these do not map 1 to 1, this is just a heuristic.
/// </summary>
private static string PrimitiveMap(string s)
{
switch (s)
Expand All @@ -211,12 +217,20 @@ private static string PrimitiveMap(string s)
return "System.Object";
case "double":
return "System.Double";
case "double[]":
return "System.Double[]";
case "int":
return "System.Int32";
case "int[]":
return "System.Int32[]";
case "bool":
return "System.Boolean";
case "bool[]":
return "System.Boolean[]";
case "string":
return "System.String";
case "string[]":
return "System.String[]";
default:
return s;
}
Expand Down
2 changes: 1 addition & 1 deletion src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public ObservableCollection<NodeCategoryViewModel> BrowserRootCategories
/// <returns></returns>
public NodeSearchElementViewModel FindViewModelForNode(string nodeName)
{
var result = dynamoViewModel.Model.SearchModel.SearchEntries.Where(e => {
var result = Model.SearchEntries.Where(e => {
if (e.CreationName.Equals(nodeName))
{
return true;
Expand Down
104 changes: 43 additions & 61 deletions test/DynamoCoreWpfTests/LibraryTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Dynamo;
Expand Down Expand Up @@ -32,7 +33,6 @@ public override void Setup()
libraryCore.ParsingMode = ParseMode.AllowNonAssignment;

var pathResolver = new TestPathResolver();
pathResolver.AddPreloadLibraryPath("DSCoreNodes.dll");

var pathManager = new PathManager(new PathManagerParams
{
Expand Down Expand Up @@ -84,30 +84,9 @@ public static void OnLibraryLoadFailed(object sender, EventArgs e)
public void DumpLibraryToXmlZeroTouchTest()
{
var searchViewModel = new SearchViewModel(new NodeSearchModel());

LibraryLoaded = false;

string libraryPath = "DSOffice.dll";

// All we need to do here is to ensure that the target has been loaded
// at some point, so if it's already here, don't try and reload it
if (!libraryServices.IsLibraryLoaded(libraryPath))
{
libraryServices.ImportLibrary(libraryPath);
Assert.IsTrue(LibraryLoaded);
}

var fgToCompare = libraryServices.GetFunctionGroups(libraryPath);
foreach (var funcGroup in fgToCompare)
{
foreach (var functionDescriptor in funcGroup.Functions)
{
if (functionDescriptor.IsVisibleInLibrary && !functionDescriptor.DisplayName.Contains("GetType"))
{
searchViewModel.Model.Add(new ZeroTouchSearchElement(functionDescriptor));
}
}
}
var fgToCompare = LoadLibraryIntoSearchViewModel(searchViewModel, libraryPath);

var document = searchViewModel.Model.ComposeXmlForLibrary(ExecutingDirectory);

Expand Down Expand Up @@ -157,30 +136,9 @@ public void DumpLibraryToXmlZeroTouchTest()
public void SearchHiddenInterfaceNodeTest()
{
var searchViewModel = new SearchViewModel(new NodeSearchModel());

LibraryLoaded = false;

string libraryPath = "FFITarget.dll";

// All we need to do here is to ensure that the target has been loaded
// at some point, so if it's already here, don't try and reload it
if (!libraryServices.IsLibraryLoaded(libraryPath))
{
libraryServices.ImportLibrary(libraryPath);
Assert.IsTrue(LibraryLoaded);
}

var fgToCompare = libraryServices.GetFunctionGroups(libraryPath);
foreach (var funcGroup in fgToCompare)
{
foreach (var functionDescriptor in funcGroup.Functions)
{
if (functionDescriptor.IsVisibleInLibrary && !functionDescriptor.DisplayName.Contains("GetType"))
{
searchViewModel.Model.Add(new ZeroTouchSearchElement(functionDescriptor));
}
}
}
LoadLibraryIntoSearchViewModel(searchViewModel, libraryPath);

var searchString = "InterfaceA";
var nodes = searchViewModel.Search(searchString);
Expand All @@ -207,10 +165,47 @@ public void SearchHiddenInterfaceNodeTest()
public void SearchHiddenEnumTest()
{
var searchViewModel = new SearchViewModel(new NodeSearchModel());
string libraryPath = "FFITarget.dll";

LibraryLoaded = false;
LoadLibraryIntoSearchViewModel(searchViewModel, libraryPath);

string libraryPath = "FFITarget.dll";
var searchString = "Days";
var nodes = searchViewModel.Search(searchString);
var foundNodes = nodes.Where(n => n.Class.Equals(searchString));
Assert.IsFalse(foundNodes.Any());

searchString = "Sunday";
nodes = searchViewModel.Search(searchString);
foundNodes = nodes.Where(n => n.Class.Equals(searchString));
Assert.IsFalse(foundNodes.Any());

searchString = "Tuesday";
nodes = searchViewModel.Search(searchString);
foundNodes = nodes.Where(n => n.Class.Equals(searchString));
Assert.IsFalse(foundNodes.Any());
}

/// <summary>
/// Tests that the XmlDocumentationExtension is able to translate a DS mangled function name that contains
/// array parameters back into the correct .NET type based mangled name.
/// </summary>
[Test]
public void CanResolveCorrectOverloadByRecognizingDoubleArrayParameter()
{
var searchViewModel = new SearchViewModel(new NodeSearchModel());
var libraryPath = "ProtoGeometry.dll";

LoadLibraryIntoSearchViewModel(searchViewModel, libraryPath);

var node = searchViewModel.FindViewModelForNode("Autodesk.DesignScript.Geometry.Curve.SplitByParameter@double[]");
Assert.IsNotNull(node);
// This is the description of SplitByParameter(System.Double[]).
Assert.AreEqual("Split a Curve into multiple pieces at the given parameters", node.Description);
}

private IEnumerable<Dynamo.Engine.FunctionGroup> LoadLibraryIntoSearchViewModel(SearchViewModel searchViewModel, string libraryPath)
{
LibraryLoaded = false;

// All we need to do here is to ensure that the target has been loaded
// at some point, so if it's already here, don't try and reload it
Expand All @@ -232,20 +227,7 @@ public void SearchHiddenEnumTest()
}
}

var searchString = "Days";
var nodes = searchViewModel.Search(searchString);
var foundNodes = nodes.Where(n => n.Class.Equals(searchString));
Assert.IsFalse(foundNodes.Any());

searchString = "Sunday";
nodes = searchViewModel.Search(searchString);
foundNodes = nodes.Where(n => n.Class.Equals(searchString));
Assert.IsFalse(foundNodes.Any());

searchString = "Tuesday";
nodes = searchViewModel.Search(searchString);
foundNodes = nodes.Where(n => n.Class.Equals(searchString));
Assert.IsFalse(foundNodes.Any());
return fgToCompare;
}
}
}

0 comments on commit c04ea0b

Please sign in to comment.