From a937933705044602bb51dd34ef6d8299d2b869db Mon Sep 17 00:00:00 2001 From: aparajit-pratap Date: Wed, 14 Nov 2018 13:02:27 -0500 Subject: [PATCH] Fix broken behavior of IsVisibleInDynamoLibrary attribute with interfaces and Enums (#9242) * fix broken behavior of IsVisibleInDynamoLibrary attribute with interfaces * revert extraneous changes * fixes * added test * revert file * fix regression in IsVisibleInDynamoLibrary attribute applied to enum * add test for enum attribute fix --- src/Engine/ProtoCore/FFI/CLRDLLModule.cs | 73 ++++++++++----- src/Libraries/CoreNodes/DateTime.cs | 8 +- test/DynamoCoreWpfTests/LibraryTests.cs | 96 ++++++++++++++++++++ test/Engine/FFITarget/CodeCompletionClass.cs | 25 +++++ 4 files changed, 171 insertions(+), 31 deletions(-) diff --git a/src/Engine/ProtoCore/FFI/CLRDLLModule.cs b/src/Engine/ProtoCore/FFI/CLRDLLModule.cs index 80668b281a2..849c5b1711b 100644 --- a/src/Engine/ProtoCore/FFI/CLRDLLModule.cs +++ b/src/Engine/ProtoCore/FFI/CLRDLLModule.cs @@ -47,8 +47,8 @@ static CLRModuleType() /// given type is not found, it creates a new one. If CLRDLLModule is /// passed as null, it creates empty CLRModuleType. /// - /// CLRDLLModule which imports this type /// System.Type to be imported in DesignScript + /// CLRDLLModule which imports this type /// Alias name, if any. For now its not supported. public static CLRModuleType GetInstance(Type type, CLRDLLModule module, string alias) { @@ -359,10 +359,10 @@ private ClassDeclNode ParseSystemType(Type type, string alias) // marked as sealed and abstract. classnode.IsStatic = type.IsAbstract && type.IsSealed; + // If all methods are static, it doesn't make sense to expose + // constructor. if (!classnode.IsStatic) { - // If all methods are static, it doesn't make sense to expose - // constructor. ConstructorInfo[] ctors = type.GetConstructors(); foreach (var c in ctors) { @@ -663,23 +663,24 @@ private ProtoCore.AST.AssociativeAST.VarDeclNode ParseFieldDeclaration(FieldInfo return varDeclNode; } - private ProtoCore.AST.AssociativeAST.FunctionDefinitionNode ParseFieldAccessor(FieldInfo f) + private FunctionDefinitionNode ParseFieldAccessor(FieldInfo f) { if (null == f || SupressesImport(f)) return null; - ProtoCore.AST.AssociativeAST.FunctionDefinitionNode func = new ProtoCore.AST.AssociativeAST.FunctionDefinitionNode(); - func.Name = string.Format("{0}{1}", Constants.kGetterPrefix, f.Name); - func.Signature = new ProtoCore.AST.AssociativeAST.ArgumentSignatureNode(); - func.ReturnType = CLRModuleType.GetProtoCoreType(f.FieldType, Module); - func.FunctionBody = null; - func.Access = ProtoCore.CompilerDefinitions.AccessModifier.Public; - func.IsExternLib = true; - func.ExternLibName = Module.Name; - func.IsStatic = f.IsStatic; - //Set the method attribute for Enum properties. - func.MethodAttributes = new FFIMethodAttributes(f); - + var func = new FunctionDefinitionNode + { + Name = string.Format("{0}{1}", Constants.kGetterPrefix, f.Name), + Signature = new ArgumentSignatureNode(), + ReturnType = CLRModuleType.GetProtoCoreType(f.FieldType, Module), + FunctionBody = null, + Access = ProtoCore.CompilerDefinitions.AccessModifier.Public, + IsExternLib = true, + ExternLibName = Module.Name, + IsStatic = f.IsStatic, + MethodAttributes = new FFIMethodAttributes(f), + }; + return func; } @@ -1225,6 +1226,9 @@ public FFIClassAttributes(Type type) if (type == null) throw new ArgumentNullException("type"); + // Hide all interfaces from library and search + if (type.IsInterface) HiddenInLibrary = true; + attributes = type.GetCustomAttributes(false).Cast().ToArray(); foreach (var attr in attributes) { @@ -1268,24 +1272,45 @@ public FFIMethodAttributes(FieldInfo f) { var atts = f.GetCustomAttributes(false).Cast(); + var parentAtts = f.DeclaringType.GetCustomAttributes(false).Cast(); + var isObsolete = false; + var hidden = false; + var message = ""; + foreach(var attr in parentAtts) + { + if(attr is ObsoleteAttribute) + { + isObsolete = true; + message = (attr as ObsoleteAttribute).Message; + if (string.IsNullOrEmpty(message)) + message = "Obsolete"; + } + + if (attr is IsVisibleInDynamoLibraryAttribute) + { + hidden = !((IsVisibleInDynamoLibraryAttribute)attr).Visible; + } + } + foreach (var attr in atts) { //Set the obsolete message for enum fields. - if (attr is IsObsoleteAttribute) + if (attr is ObsoleteAttribute) { HiddenInLibrary = true; - ObsoleteMessage = (attr as IsObsoleteAttribute).Message; + ObsoleteMessage = (attr as ObsoleteAttribute).Message; if (string.IsNullOrEmpty(ObsoleteMessage)) ObsoleteMessage = "Obsolete"; } - else if (attr is ObsoleteAttribute) + else if(attr is IsVisibleInDynamoLibraryAttribute) { - HiddenInLibrary = true; - ObsoleteMessage = (attr as ObsoleteAttribute).Message; - if (string.IsNullOrEmpty(ObsoleteMessage)) - ObsoleteMessage = "Obsolete"; + HiddenInLibrary = !((IsVisibleInDynamoLibraryAttribute)attr).Visible; } - + } + if (isObsolete || hidden) + { + HiddenInLibrary = true; + if (isObsolete) ObsoleteMessage = message; } } diff --git a/src/Libraries/CoreNodes/DateTime.cs b/src/Libraries/CoreNodes/DateTime.cs index f0b658622e2..5713fbf6a6d 100644 --- a/src/Libraries/CoreNodes/DateTime.cs +++ b/src/Libraries/CoreNodes/DateTime.cs @@ -233,21 +233,15 @@ public static System.TimeSpan TimeOfDay(System.DateTime dateTime) /// Days of the Week /// [IsVisibleInDynamoLibrary(false)] + [Obsolete("This node is deprecated")] public enum DayOfWeek { - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekSunday", typeof(Properties.Resources))]Sunday, - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekMonday", typeof(Properties.Resources))]Monday, - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekTuesday", typeof(Properties.Resources))]Tuesday, - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekWednesday", typeof(Properties.Resources))]Wednesday, - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekThursday", typeof(Properties.Resources))]Thursday, - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekFriday", typeof(Properties.Resources))]Friday, - [Obsolete("This node is deprecated")] [EnumDescription("EnumDateOfWeekSaturday", typeof(Properties.Resources))]Saturday } diff --git a/test/DynamoCoreWpfTests/LibraryTests.cs b/test/DynamoCoreWpfTests/LibraryTests.cs index 59c370da2fd..2a1ee441174 100644 --- a/test/DynamoCoreWpfTests/LibraryTests.cs +++ b/test/DynamoCoreWpfTests/LibraryTests.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using ProtoCore; using System; +using System.Linq; using System.Xml; using TestServices; @@ -151,5 +152,100 @@ public void DumpLibraryToXmlZeroTouchTest() } } } + + [Test] + 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)); + } + } + } + + var searchString = "InterfaceA"; + var nodes = searchViewModel.Search(searchString); + var foundNodes = nodes.Where(n => n.Class.Equals(searchString)); + Assert.IsFalse(foundNodes.Any()); + + searchString = "DerivedFromInterfaceA"; + nodes = searchViewModel.Search(searchString); + foundNodes = nodes.Where(n => n.Class.Equals(searchString)); + Assert.AreEqual(2, foundNodes.Count()); + + searchString = "TraceableId"; + nodes = searchViewModel.Search(searchString); + foundNodes = nodes.Where(n => n.Class.Equals(searchString)); + Assert.IsFalse(foundNodes.Any()); + + searchString = "ISerializable"; + nodes = searchViewModel.Search(searchString); + foundNodes = nodes.Where(n => n.Class.Equals(searchString)); + Assert.IsFalse(foundNodes.Any()); + } + + [Test] + public void SearchHiddenEnumTest() + { + 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)); + } + } + } + + 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()); + } } } diff --git a/test/Engine/FFITarget/CodeCompletionClass.cs b/test/Engine/FFITarget/CodeCompletionClass.cs index e4fce3224e5..9bc134cb08e 100644 --- a/test/Engine/FFITarget/CodeCompletionClass.cs +++ b/test/Engine/FFITarget/CodeCompletionClass.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; namespace FFITarget @@ -125,4 +126,28 @@ public class AnotherClassWithNameConflict public static string PropertyF { get; set; } } } + + [IsVisibleInDynamoLibrary(false)] + [Serializable] + public class TraceableId : ISerializable + { + public int IntID { get; set; } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("intID", IntID, typeof(int)); + } + } + + [IsVisibleInDynamoLibrary(false)] + public enum Days + { + Sunday, + Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday + } }