From 844ab8abdb3d3b3a6fbea69c02a52decf20a53dc Mon Sep 17 00:00:00 2001 From: pinzart Date: Mon, 9 Nov 2020 08:44:28 -0500 Subject: [PATCH 01/13] handle hidden static methods from zero touch nodes --- .../CodeCompletion/CodeCompletionServices.cs | 6 ++- src/Engine/ProtoCore/Lang/CallSite.cs | 44 +++++++++++++------ src/Engine/ProtoCore/Lang/FunctionEndPoint.cs | 26 ++++++----- src/Engine/ProtoCore/Reflection/Mirror.cs | 33 ++++++++++++++ 4 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs index 52fece92201..c12157f02ff 100644 --- a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs +++ b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs @@ -69,7 +69,7 @@ internal IEnumerable GetCompletionsOnType(string code, string st } } - return members?.Select(x => CompletionData.ConvertMirrorToCompletionData(x)); + return members?.Distinct(new StaticMirrorSigComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } /// @@ -183,7 +183,9 @@ internal IEnumerable GetFunctionSignatures(string code, string f candidates = type.GetOverloadsOnInstance(functionName); } } - return candidates.Select(x => CompletionData.ConvertMirrorToCompletionData(x)); + + var hhh = candidates.Distinct(new StaticMirrorSigComparer()).ToList(); + return candidates.Distinct(new StaticMirrorSigComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } private void AddTypesToCompletionData(string stringToComplete, List completions, ElementResolver resolver) diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index d31ee5ae8df..5fafc8515ff 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1121,18 +1121,32 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor int typeID = svThisPtr.metaData.type; //Test for exact match - List exactFeps = new List(); + List exactFeps = null; - foreach (FunctionEndPoint fep in feps) - if (fep.ClassOwnerIndex == typeID) - exactFeps.Add(fep); + // Is static method call (i.e no this pointer) + if (svThisPtr.Pointer == Constants.kInvalidIndex) + { + // Here we will cover the specific case of static method hiding. + // We do not need to check actually if the method has the "IsHideBySig" (https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.ishidebysig) + // because static methods can only be hidden. + // In this case we simply select the function that belongs to the calling class. + // We also need to check that all function end points in "feps" have the exact same signature. + var sig = feps.First().Signature(false/*includeReturnType*/); + if (feps.All(x => x.Signature() == sig)) + { + exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope).ToList(); + } + } else + { + // If we have an instance of a class, then try to match with methods of that class. + exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID).ToList(); + } if (exactFeps.Count == 1) { return exactFeps[0]; } - - + //Walk the class tree structure to find the method while (runtimeCore.DSExecutable.classTable.ClassNodes[typeID].Base != Constants.kInvalidIndex) @@ -1155,9 +1169,9 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor { if (fep.FormalParams[i].rank == Constants.kArbitraryRank) noArbitraries++; - - numberOfArbitraryRanks.Add(noArbitraries); } + + numberOfArbitraryRanks.Add(noArbitraries); } int smallest = Int32.MaxValue; @@ -1448,7 +1462,9 @@ private StackValue DispatchNew( //If we got here then the function group got resolved log.AppendLine("Function group resolved: " + funcGroup); - // Filter function end point + // Filter function end point based on: + // 1. If the number of arguments match. + // 2. If procedures are not hidden (See details: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-modifier) List candidatesFeps = new List(); int argumentNumber = arguments.Count; foreach (var fep in funcGroup.FunctionEndPoints) @@ -1456,11 +1472,13 @@ private StackValue DispatchNew( int defaultParamNumber = fep.procedureNode.ArgumentInfos.Count(x => x.IsDefault); int parameterNumber = fep.procedureNode.ArgumentTypes.Count; - if (argumentNumber <= parameterNumber && parameterNumber - argumentNumber <= defaultParamNumber) - { - candidatesFeps.Add(fep); - } + bool argumentsCountMatch = argumentNumber <= parameterNumber && parameterNumber - argumentNumber <= defaultParamNumber; + if (!argumentsCountMatch) + continue; + + candidatesFeps.Add(fep); } + funcGroup = new FunctionGroup(candidatesFeps); #endregion diff --git a/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs b/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs index 9f5f8ea497b..175537f068d 100644 --- a/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs +++ b/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs @@ -288,13 +288,11 @@ public List CoerceParameters(List formalParameters, Runt return fixedUpVersions; } - - public override string ToString() + internal string Signature(bool includeReturnType = true) { string name = procedureNode.Name; - string returnType = procedureNode.ReturnType.ToString(); - - System.Text.StringBuilder sb = new StringBuilder(); + + StringBuilder sb = new StringBuilder(); sb.Append(name); sb.Append("("); @@ -309,15 +307,21 @@ public override string ToString() sb.Append(FormalParams[FormalParams.Length - 1]); } sb.Append(")"); - sb.Append("-> "); - sb.Append(returnType); + if (includeReturnType) + { + string returnType = procedureNode.ReturnType.ToString(); + + sb.Append("-> "); + sb.Append(returnType); + } return sb.ToString(); } - - } - - + public sealed override string ToString() + { + return Signature(); + } + } } diff --git a/src/Engine/ProtoCore/Reflection/Mirror.cs b/src/Engine/ProtoCore/Reflection/Mirror.cs index 8c125d03ca3..59b195044ae 100644 --- a/src/Engine/ProtoCore/Reflection/Mirror.cs +++ b/src/Engine/ProtoCore/Reflection/Mirror.cs @@ -213,6 +213,38 @@ public override string ToString() } } + internal class StaticMirrorSigComparer : IEqualityComparer + { + public bool Equals(StaticMirror x, StaticMirror y) + { + if (x is MethodMirror && y is MethodMirror) + { + var mmX = x as MethodMirror; + var mmY = y as MethodMirror; + return mmX.MethodName == mmY.MethodName && mmX.ArgumentList.Equals(mmY.ArgumentList); + } + return x.Name == y.ToString(); + } + + public int GetHashCode(StaticMirror obj) + { + if (obj is MethodMirror) + { + var mmObj = obj as MethodMirror; + + StringBuilder sb = new StringBuilder(); + + var methodName = mmObj.MethodName; + var argList = mmObj.ArgumentList.Select(x => x.Key + " : " + x.Value); + sb.AppendLine(methodName + " (" + + string.Join(", ", argList.Select(p => p.ToString())) + ')'); + + return sb.ToString().Trim().GetHashCode(); + } + return obj.ToString().GetHashCode(); + } + } + /// /// A ClassMirror object reflects upon the type of a single designscript variable /// The information here is populated during the code generation phase @@ -518,6 +550,7 @@ public IEnumerable GetInstanceMembers() members.AddRange(this.GetFunctions().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); members.AddRange(this.GetProperties().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + return members; } From 442ba90794f6d4165d96d71b45c0cf859096a4d7 Mon Sep 17 00:00:00 2001 From: pinzart Date: Mon, 9 Nov 2020 11:24:21 -0500 Subject: [PATCH 02/13] rever custom Signature logic --- .../CodeCompletion/CodeCompletionServices.cs | 1 - src/Engine/ProtoCore/Lang/CallSite.cs | 8 ++---- src/Engine/ProtoCore/Lang/FunctionEndPoint.cs | 26 ++++++++----------- src/Engine/ProtoCore/Reflection/Mirror.cs | 21 +-------------- 4 files changed, 14 insertions(+), 42 deletions(-) diff --git a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs index c12157f02ff..6802b86cb93 100644 --- a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs +++ b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs @@ -184,7 +184,6 @@ internal IEnumerable GetFunctionSignatures(string code, string f } } - var hhh = candidates.Distinct(new StaticMirrorSigComparer()).ToList(); return candidates.Distinct(new StaticMirrorSigComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index 5fafc8515ff..75c52d0fb1c 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1130,12 +1130,8 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor // We do not need to check actually if the method has the "IsHideBySig" (https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.ishidebysig) // because static methods can only be hidden. // In this case we simply select the function that belongs to the calling class. - // We also need to check that all function end points in "feps" have the exact same signature. - var sig = feps.First().Signature(false/*includeReturnType*/); - if (feps.All(x => x.Signature() == sig)) - { - exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope).ToList(); - } + // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. + exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope).ToList(); } else { // If we have an instance of a class, then try to match with methods of that class. diff --git a/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs b/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs index 175537f068d..9f5f8ea497b 100644 --- a/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs +++ b/src/Engine/ProtoCore/Lang/FunctionEndPoint.cs @@ -288,11 +288,13 @@ public List CoerceParameters(List formalParameters, Runt return fixedUpVersions; } - internal string Signature(bool includeReturnType = true) + + public override string ToString() { string name = procedureNode.Name; - - StringBuilder sb = new StringBuilder(); + string returnType = procedureNode.ReturnType.ToString(); + + System.Text.StringBuilder sb = new StringBuilder(); sb.Append(name); sb.Append("("); @@ -307,21 +309,15 @@ internal string Signature(bool includeReturnType = true) sb.Append(FormalParams[FormalParams.Length - 1]); } sb.Append(")"); + sb.Append("-> "); + sb.Append(returnType); - if (includeReturnType) - { - string returnType = procedureNode.ReturnType.ToString(); - - sb.Append("-> "); - sb.Append(returnType); - } return sb.ToString(); } - - public sealed override string ToString() - { - return Signature(); - } + } + + + } diff --git a/src/Engine/ProtoCore/Reflection/Mirror.cs b/src/Engine/ProtoCore/Reflection/Mirror.cs index 59b195044ae..46bbad61692 100644 --- a/src/Engine/ProtoCore/Reflection/Mirror.cs +++ b/src/Engine/ProtoCore/Reflection/Mirror.cs @@ -217,30 +217,11 @@ internal class StaticMirrorSigComparer : IEqualityComparer { public bool Equals(StaticMirror x, StaticMirror y) { - if (x is MethodMirror && y is MethodMirror) - { - var mmX = x as MethodMirror; - var mmY = y as MethodMirror; - return mmX.MethodName == mmY.MethodName && mmX.ArgumentList.Equals(mmY.ArgumentList); - } - return x.Name == y.ToString(); + return x.ToString() == y.ToString(); } public int GetHashCode(StaticMirror obj) { - if (obj is MethodMirror) - { - var mmObj = obj as MethodMirror; - - StringBuilder sb = new StringBuilder(); - - var methodName = mmObj.MethodName; - var argList = mmObj.ArgumentList.Select(x => x.Key + " : " + x.Value); - sb.AppendLine(methodName + " (" + - string.Join(", ", argList.Select(p => p.ToString())) + ')'); - - return sb.ToString().Trim().GetHashCode(); - } return obj.ToString().GetHashCode(); } } From e8065d062b86ac143c663dd6fd3de4da45c230d2 Mon Sep 17 00:00:00 2001 From: pinzart Date: Mon, 9 Nov 2020 11:59:49 -0500 Subject: [PATCH 03/13] Update CallSite.cs --- src/Engine/ProtoCore/Lang/CallSite.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index 75c52d0fb1c..d10ac2288c7 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1121,8 +1121,7 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor int typeID = svThisPtr.metaData.type; //Test for exact match - List exactFeps = null; - + IEnumerable exactFeps = null; // Is static method call (i.e no this pointer) if (svThisPtr.Pointer == Constants.kInvalidIndex) { @@ -1131,16 +1130,16 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor // because static methods can only be hidden. // In this case we simply select the function that belongs to the calling class. // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. - exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope).ToList(); + exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope); } else { // If we have an instance of a class, then try to match with methods of that class. - exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID).ToList(); + exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID); } - if (exactFeps.Count == 1) + if (exactFeps.Count() == 1) { - return exactFeps[0]; + return exactFeps.First(); } //Walk the class tree structure to find the method @@ -1159,15 +1158,15 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor foreach (FunctionEndPoint fep in feps) { - int noArbitraries = 0; + int numArbitraryRanks = 0; for (int i = 0; i < argumentsList.Count; i++) { if (fep.FormalParams[i].rank == Constants.kArbitraryRank) - noArbitraries++; + numArbitraryRanks++; } - numberOfArbitraryRanks.Add(noArbitraries); + numberOfArbitraryRanks.Add(numArbitraryRanks); } int smallest = Int32.MaxValue; From bfbbf99de6ce473908a3cc3595bb6aff01372f54 Mon Sep 17 00:00:00 2001 From: pinzart Date: Mon, 9 Nov 2020 19:54:55 -0500 Subject: [PATCH 04/13] update --- .../CodeCompletion/CodeCompletionServices.cs | 4 +- src/Engine/ProtoCore/Lang/CallSite.cs | 13 ++--- src/Engine/ProtoCore/Reflection/Mirror.cs | 54 +++++++++++++------ 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs index 6802b86cb93..8e5499ca754 100644 --- a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs +++ b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs @@ -69,7 +69,7 @@ internal IEnumerable GetCompletionsOnType(string code, string st } } - return members?.Distinct(new StaticMirrorSigComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); + return members?.Distinct(new StaticMirrorNameComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } /// @@ -184,7 +184,7 @@ internal IEnumerable GetFunctionSignatures(string code, string f } } - return candidates.Distinct(new StaticMirrorSigComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); + return candidates.Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } private void AddTypesToCompletionData(string stringToComplete, List completions, ElementResolver resolver) diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index d10ac2288c7..6b9145d6f0e 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1457,9 +1457,7 @@ private StackValue DispatchNew( //If we got here then the function group got resolved log.AppendLine("Function group resolved: " + funcGroup); - // Filter function end point based on: - // 1. If the number of arguments match. - // 2. If procedures are not hidden (See details: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-modifier) + // Filter function end point List candidatesFeps = new List(); int argumentNumber = arguments.Count; foreach (var fep in funcGroup.FunctionEndPoints) @@ -1467,11 +1465,10 @@ private StackValue DispatchNew( int defaultParamNumber = fep.procedureNode.ArgumentInfos.Count(x => x.IsDefault); int parameterNumber = fep.procedureNode.ArgumentTypes.Count; - bool argumentsCountMatch = argumentNumber <= parameterNumber && parameterNumber - argumentNumber <= defaultParamNumber; - if (!argumentsCountMatch) - continue; - - candidatesFeps.Add(fep); + if (argumentNumber <= parameterNumber && parameterNumber - argumentNumber <= defaultParamNumber) + { + candidatesFeps.Add(fep); + } } funcGroup = new FunctionGroup(candidatesFeps); diff --git a/src/Engine/ProtoCore/Reflection/Mirror.cs b/src/Engine/ProtoCore/Reflection/Mirror.cs index 46bbad61692..a3f7c6df8f9 100644 --- a/src/Engine/ProtoCore/Reflection/Mirror.cs +++ b/src/Engine/ProtoCore/Reflection/Mirror.cs @@ -213,16 +213,20 @@ public override string ToString() } } - internal class StaticMirrorSigComparer : IEqualityComparer + // + /// + /// Comparer class that defines methods to support the comparison of StaticMirror objects for equality. + /// + internal class StaticMirrorNameComparer : IEqualityComparer { public bool Equals(StaticMirror x, StaticMirror y) { - return x.ToString() == y.ToString(); + return x.Name == y.Name; } public int GetHashCode(StaticMirror obj) { - return obj.ToString().GetHashCode(); + return obj.Name.GetHashCode(); } } @@ -350,23 +354,27 @@ internal ClassMirror(StackValue svData, ProtoCore.Core core) /// /// Returns the constructors and static methods and properties /// belonging to the type and its base types + /// Excludes hidden methods and properties from base types. /// /// public IEnumerable GetMembers() { // TODO: Factor out reflection functionality for both LibraryServices and Mirrors List members = new List(); + members.AddRange(this.GetConstructors().GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(this.GetFunctions().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(this.GetProperties().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + + var derivedClassMembers = new HashSet(); + members.ForEach(x => derivedClassMembers.Add(x.ToString())); IEnumerable baseClasses = this.GetClassHierarchy(); foreach (var baseClass in baseClasses) { - members.AddRange(baseClass.GetFunctions().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(baseClass.GetProperties().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(baseClass.GetFunctions().Where(m => m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(baseClass.GetProperties().Where(m => m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); } - members.AddRange(this.GetConstructors().GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(this.GetFunctions().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(this.GetProperties().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); return members; } @@ -481,20 +489,25 @@ public IEnumerable GetOverloads(string methodName) /// /// Given a method name, return the matching list of /// constructors or static methods on this type and its base types + /// Excludes hidden methods form base types. /// /// /// public IEnumerable GetOverloadsOnType(string methodName) { List members = new List(); + members.AddRange(this.GetConstructors().Where(x => x.MethodName == methodName)); + members.AddRange(this.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName)); + + var derivedClassMembers = new HashSet(); + members.ForEach(x => derivedClassMembers.Add(x.ToString())); + IEnumerable baseClasses = this.GetClassHierarchy(); foreach (var baseClass in baseClasses) { - members.AddRange(baseClass.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName)); + members.AddRange(baseClass.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName && !derivedClassMembers.Contains(x.ToString()))); } - - members.AddRange(this.GetConstructors().Where(x => x.MethodName == methodName)); - members.AddRange(this.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName)); + return members; } @@ -517,21 +530,28 @@ public IEnumerable GetOverloadsOnInstance(string methodName) return members; } + /// + /// Returns the instance methods and properties + /// belonging to the type and its base types + /// Excludes hidden methods and properties from base types. + /// public IEnumerable GetInstanceMembers() { // TODO: Factor out reflection functionality for both LibraryServices and Mirrors List members = new List(); + members.AddRange(this.GetFunctions().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(this.GetProperties().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + + var derivedClassMembers = new HashSet(); + members.ForEach(x => derivedClassMembers.Add(x.ToString())); IEnumerable baseClasses = this.GetClassHierarchy(); foreach (var baseClass in baseClasses) { - members.AddRange(baseClass.GetFunctions().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(baseClass.GetProperties().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(baseClass.GetFunctions().Where(m => !m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(baseClass.GetProperties().Where(m => !m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); } - members.AddRange(this.GetFunctions().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(this.GetProperties().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - return members; } From c4a902854136c6a6cb8a921f5598095e7550a772 Mon Sep 17 00:00:00 2001 From: pinzart Date: Mon, 9 Nov 2020 20:16:00 -0500 Subject: [PATCH 05/13] Update Mirror.cs --- src/Engine/ProtoCore/Reflection/Mirror.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Engine/ProtoCore/Reflection/Mirror.cs b/src/Engine/ProtoCore/Reflection/Mirror.cs index a3f7c6df8f9..486fd185f5f 100644 --- a/src/Engine/ProtoCore/Reflection/Mirror.cs +++ b/src/Engine/ProtoCore/Reflection/Mirror.cs @@ -361,10 +361,13 @@ public IEnumerable GetMembers() { // TODO: Factor out reflection functionality for both LibraryServices and Mirrors List members = new List(); - members.AddRange(this.GetConstructors().GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(this.GetFunctions().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(this.GetProperties().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(GetConstructors().GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(GetFunctions().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(GetProperties().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + // Filter out hidden functions/properties: + // Create a set of unique function, property and constructor descriptions. + // In this case we use ToString() to get the uniques description of the members (func signature, propety names, constructor names). var derivedClassMembers = new HashSet(); members.ForEach(x => derivedClassMembers.Add(x.ToString())); @@ -499,6 +502,9 @@ public IEnumerable GetOverloadsOnType(string methodName) members.AddRange(this.GetConstructors().Where(x => x.MethodName == methodName)); members.AddRange(this.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName)); + // Filter out hidden functions/properties: + // Create a set of unique function and constructor descriptions. + // In this case we use ToString() to get the uniques description of the members (func signature, constructor names). var derivedClassMembers = new HashSet(); members.ForEach(x => derivedClassMembers.Add(x.ToString())); @@ -542,6 +548,9 @@ public IEnumerable GetInstanceMembers() members.AddRange(this.GetFunctions().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); members.AddRange(this.GetProperties().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + // Filter out hidden functions/properties: + // Create a set of unique function and property descriptions. + // In this case we use ToString() to get the uniques description of the members (func signature, propety names). var derivedClassMembers = new HashSet(); members.ForEach(x => derivedClassMembers.Add(x.ToString())); From be10e650f757f6e4464c22c8238cb70c3f973247 Mon Sep 17 00:00:00 2001 From: pinzart Date: Tue, 10 Nov 2020 08:28:46 -0500 Subject: [PATCH 06/13] Update CallSite.cs --- src/Engine/ProtoCore/Lang/CallSite.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index 6b9145d6f0e..31d066d8cf6 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1131,7 +1131,8 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor // In this case we simply select the function that belongs to the calling class. // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope); - } else + } + else { // If we have an instance of a class, then try to match with methods of that class. exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID); From 0c6f2ea5132fb461047f92d36b1b35572513afea Mon Sep 17 00:00:00 2001 From: pinzart Date: Tue, 10 Nov 2020 10:57:00 -0500 Subject: [PATCH 07/13] update --- src/Engine/ProtoCore/Lang/CallSite.cs | 31 +++++++++-------------- src/Engine/ProtoCore/Reflection/Mirror.cs | 6 ++--- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index 31d066d8cf6..a1162977097 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1118,33 +1118,26 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor Validity.Assert(svThisPtr.IsPointer, "this pointer wasn't a pointer. {89635B06-AD53-4170-ADA5-065EB2AE5858}"); - int typeID = svThisPtr.metaData.type; - //Test for exact match - IEnumerable exactFeps = null; - // Is static method call (i.e no this pointer) - if (svThisPtr.Pointer == Constants.kInvalidIndex) - { - // Here we will cover the specific case of static method hiding. - // We do not need to check actually if the method has the "IsHideBySig" (https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.ishidebysig) - // because static methods can only be hidden. - // In this case we simply select the function that belongs to the calling class. - // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. - exactFeps = feps.Where(x => x.ClassOwnerIndex == stackFrame.ClassScope); - } - else - { - // If we have an instance of a class, then try to match with methods of that class. - exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID); - } + // We have 2 possible cases here: + // 1. Static method call (i.e no this pointer) + // Here we will cover the specific case of static method hiding. + // We do not need to check actually if the method has the "IsHideBySig" (https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.ishidebysig) + // because static methods can only be hidden. + // In this case we simply select the function that belongs to the calling class. + // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. + // 2. Method call from an instance of a class. + // Try to match with methods of that class. + int typeID = svThisPtr.Pointer == Constants.kInvalidIndex ? stackFrame.ClassScope : svThisPtr.metaData.type; + //Test for exact match + IEnumerable exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID); if (exactFeps.Count() == 1) { return exactFeps.First(); } //Walk the class tree structure to find the method - while (runtimeCore.DSExecutable.classTable.ClassNodes[typeID].Base != Constants.kInvalidIndex) { typeID = runtimeCore.DSExecutable.classTable.ClassNodes[typeID].Base; diff --git a/src/Engine/ProtoCore/Reflection/Mirror.cs b/src/Engine/ProtoCore/Reflection/Mirror.cs index 486fd185f5f..5e9f25c7b7f 100644 --- a/src/Engine/ProtoCore/Reflection/Mirror.cs +++ b/src/Engine/ProtoCore/Reflection/Mirror.cs @@ -367,7 +367,7 @@ public IEnumerable GetMembers() // Filter out hidden functions/properties: // Create a set of unique function, property and constructor descriptions. - // In this case we use ToString() to get the uniques description of the members (func signature, propety names, constructor names). + // In this case we use ToString() to get the uniques description of the members (func signature, property names, constructor names). var derivedClassMembers = new HashSet(); members.ForEach(x => derivedClassMembers.Add(x.ToString())); @@ -492,7 +492,7 @@ public IEnumerable GetOverloads(string methodName) /// /// Given a method name, return the matching list of /// constructors or static methods on this type and its base types - /// Excludes hidden methods form base types. + /// Excludes hidden methods from base types. /// /// /// @@ -550,7 +550,7 @@ public IEnumerable GetInstanceMembers() // Filter out hidden functions/properties: // Create a set of unique function and property descriptions. - // In this case we use ToString() to get the uniques description of the members (func signature, propety names). + // In this case we use ToString() to get the uniques description of the members (func signature, property names). var derivedClassMembers = new HashSet(); members.ForEach(x => derivedClassMembers.Add(x.ToString())); From fc44db9961993c85ab8af5cec4a8a2fe22ffaadd Mon Sep 17 00:00:00 2001 From: pinzart Date: Tue, 10 Nov 2020 22:26:53 -0500 Subject: [PATCH 08/13] simplify and add test --- .../CodeCompletion/CodeCompletionServices.cs | 2 +- src/Engine/ProtoCore/Reflection/Mirror.cs | 78 ++++++------------- test/DynamoCoreTests/CodeBlockNodeTests.cs | 18 ++++- test/Engine/FFITarget/FFITarget.csproj | 1 + test/Engine/FFITarget/TestHiddenMethods.cs | 53 +++++++++++++ 5 files changed, 95 insertions(+), 57 deletions(-) create mode 100644 test/Engine/FFITarget/TestHiddenMethods.cs diff --git a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs index 8e5499ca754..57e1867125f 100644 --- a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs +++ b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs @@ -69,7 +69,7 @@ internal IEnumerable GetCompletionsOnType(string code, string st } } - return members?.Distinct(new StaticMirrorNameComparer()).Select(x => CompletionData.ConvertMirrorToCompletionData(x)); + return members?.Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } /// diff --git a/src/Engine/ProtoCore/Reflection/Mirror.cs b/src/Engine/ProtoCore/Reflection/Mirror.cs index 5e9f25c7b7f..d5eb1507a1e 100644 --- a/src/Engine/ProtoCore/Reflection/Mirror.cs +++ b/src/Engine/ProtoCore/Reflection/Mirror.cs @@ -213,23 +213,6 @@ public override string ToString() } } - // - /// - /// Comparer class that defines methods to support the comparison of StaticMirror objects for equality. - /// - internal class StaticMirrorNameComparer : IEqualityComparer - { - public bool Equals(StaticMirror x, StaticMirror y) - { - return x.Name == y.Name; - } - - public int GetHashCode(StaticMirror obj) - { - return obj.Name.GetHashCode(); - } - } - /// /// A ClassMirror object reflects upon the type of a single designscript variable /// The information here is populated during the code generation phase @@ -352,33 +335,27 @@ internal ClassMirror(StackValue svData, ProtoCore.Core core) } /// - /// Returns the constructors and static methods and properties - /// belonging to the type and its base types - /// Excludes hidden methods and properties from base types. + /// Returns a list of constructors and static methods and properties + /// belonging to the type and its base types. Filters out repeating names. /// /// public IEnumerable GetMembers() { // TODO: Factor out reflection functionality for both LibraryServices and Mirrors List members = new List(); - members.AddRange(GetConstructors().GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(GetFunctions().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(GetProperties().Where(m => m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(GetConstructors()); + members.AddRange(GetFunctions().Where(m => m.IsStatic)); + members.AddRange(GetProperties().Where(m => m.IsStatic)); - // Filter out hidden functions/properties: - // Create a set of unique function, property and constructor descriptions. - // In this case we use ToString() to get the uniques description of the members (func signature, property names, constructor names). - var derivedClassMembers = new HashSet(); - members.ForEach(x => derivedClassMembers.Add(x.ToString())); - - IEnumerable baseClasses = this.GetClassHierarchy(); + IEnumerable baseClasses = GetClassHierarchy(); foreach (var baseClass in baseClasses) { - members.AddRange(baseClass.GetFunctions().Where(m => m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(baseClass.GetProperties().Where(m => m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(baseClass.GetFunctions().Where(m => m.IsStatic)); + members.AddRange(baseClass.GetProperties().Where(m => m.IsStatic)); } - return members; + // Return a list of members with unique names. + return members.GroupBy(x => x.Name).Select(x => x.First()).ToList(); } /// @@ -499,16 +476,16 @@ public IEnumerable GetOverloads(string methodName) public IEnumerable GetOverloadsOnType(string methodName) { List members = new List(); - members.AddRange(this.GetConstructors().Where(x => x.MethodName == methodName)); - members.AddRange(this.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName)); + members.AddRange(GetConstructors().Where(x => x.MethodName == methodName)); + members.AddRange(GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName)); // Filter out hidden functions/properties: // Create a set of unique function and constructor descriptions. - // In this case we use ToString() to get the uniques description of the members (func signature, constructor names). + // In this case we use ToString() to get the unique description of the members (func signature, constructor names). var derivedClassMembers = new HashSet(); members.ForEach(x => derivedClassMembers.Add(x.ToString())); - IEnumerable baseClasses = this.GetClassHierarchy(); + IEnumerable baseClasses = GetClassHierarchy(); foreach (var baseClass in baseClasses) { members.AddRange(baseClass.GetFunctions().Where(x => x.IsStatic && x.MethodName == methodName && !derivedClassMembers.Contains(x.ToString()))); @@ -526,42 +503,37 @@ public IEnumerable GetOverloadsOnType(string methodName) public IEnumerable GetOverloadsOnInstance(string methodName) { List members = new List(); - IEnumerable baseClasses = this.GetClassHierarchy(); + IEnumerable baseClasses = GetClassHierarchy(); foreach (var baseClass in baseClasses) { members.AddRange(baseClass.GetFunctions().Where(x => !x.IsStatic && x.MethodName == methodName)); } - members.AddRange(this.GetFunctions().Where(x => !x.IsStatic && x.MethodName == methodName)); + members.AddRange(GetFunctions().Where(x => !x.IsStatic && x.MethodName == methodName)); return members; } /// /// Returns the instance methods and properties - /// belonging to the type and its base types - /// Excludes hidden methods and properties from base types. + /// belonging to the type and its base types. Filters out repeating names. /// public IEnumerable GetInstanceMembers() { // TODO: Factor out reflection functionality for both LibraryServices and Mirrors - List members = new List(); - members.AddRange(this.GetFunctions().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(this.GetProperties().Where(m => !m.IsStatic).GroupBy(x => x.Name).Select(y => y.First())); - // Filter out hidden functions/properties: - // Create a set of unique function and property descriptions. - // In this case we use ToString() to get the uniques description of the members (func signature, property names). - var derivedClassMembers = new HashSet(); - members.ForEach(x => derivedClassMembers.Add(x.ToString())); + List members = new List(); + members.AddRange(GetFunctions().Where(m => !m.IsStatic)); + members.AddRange(GetProperties().Where(m => !m.IsStatic)); - IEnumerable baseClasses = this.GetClassHierarchy(); + IEnumerable baseClasses = GetClassHierarchy(); foreach (var baseClass in baseClasses) { - members.AddRange(baseClass.GetFunctions().Where(m => !m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); - members.AddRange(baseClass.GetProperties().Where(m => !m.IsStatic && !derivedClassMembers.Contains(m.ToString())).GroupBy(x => x.Name).Select(y => y.First())); + members.AddRange(baseClass.GetFunctions().Where(m => !m.IsStatic)); + members.AddRange(baseClass.GetProperties().Where(m => !m.IsStatic)); } - return members; + // Return a list of members with unique names. + return members.GroupBy(x => x.Name).Select(y => y.First()).ToList(); } public ClassAttributes GetClassAttributes() diff --git a/test/DynamoCoreTests/CodeBlockNodeTests.cs b/test/DynamoCoreTests/CodeBlockNodeTests.cs index 0c1d3b2ee9b..440b951a909 100644 --- a/test/DynamoCoreTests/CodeBlockNodeTests.cs +++ b/test/DynamoCoreTests/CodeBlockNodeTests.cs @@ -2270,9 +2270,21 @@ public void TestCompletionOnDerivedTypeReturnsBaseType() var codeCompletionServices = new CodeCompletionServices(libraryServicesCore); var completions = codeCompletionServices.GetCompletionsOnType("", "DupTargetTest").ToList(); Assert.AreEqual(3, completions.Count); - Assert.AreEqual("Foo", completions[0].Text); - Assert.AreEqual("DupTargetTest", completions[1].Text); - Assert.AreEqual("Bar", completions[2].Text); + Assert.AreEqual("DupTargetTest", completions[0].Text); + Assert.AreEqual("Bar", completions[1].Text); + Assert.AreEqual("Foo", completions[2].Text); + } + + [Test] + [Category("UnitTests")] + public void TestCompletionOnDerivedTypeReturnsNonHiddenBaseMethods() + { + var codeCompletionServices = new CodeCompletionServices(libraryServicesCore); + var completions = codeCompletionServices.GetCompletionsOnType("", "FFITarget.DerivedTestHiddenMethods").ToList(); + Assert.AreEqual(3, completions.Count); + Assert.AreEqual("DerivedTestHiddenMethods", completions[0].Text); + Assert.AreEqual("SomeStaticMethod", completions[1].Text); + Assert.AreEqual("SomeMethod", completions[2].Text); } [Test] diff --git a/test/Engine/FFITarget/FFITarget.csproj b/test/Engine/FFITarget/FFITarget.csproj index 6c65b0386db..bc23e207edc 100644 --- a/test/Engine/FFITarget/FFITarget.csproj +++ b/test/Engine/FFITarget/FFITarget.csproj @@ -77,6 +77,7 @@ + diff --git a/test/Engine/FFITarget/TestHiddenMethods.cs b/test/Engine/FFITarget/TestHiddenMethods.cs new file mode 100644 index 00000000000..214972077b5 --- /dev/null +++ b/test/Engine/FFITarget/TestHiddenMethods.cs @@ -0,0 +1,53 @@ +using Autodesk.DesignScript.Runtime; + +namespace FFITarget +{ + public class BaseTestHiddenMethods + { + public static int SomeVariable = 100; + public BaseTestHiddenMethods() + { + } + + public static int SomeStaticMethod() + { + return 100; + } + public static int SomeStaticMethod(int[] x) + { + return 100; + } + public static int SomeStaticMethod(int[] x, int[] y) + { + return 100; + } + public static int SomeMethod() + { + return 100; + } + } + + public class DerivedTestHiddenMethods : BaseTestHiddenMethods + { + public static new int SomeVariable = 200; + public DerivedTestHiddenMethods() + { + } + public static new int SomeStaticMethod() + { + return 200; + } + public static new int SomeStaticMethod(int[] x) + { + return 200; + } + public static new int SomeStaticMethod(int[] x, int[] y) + { + return 200; + } + public static new int SomeMethod() + { + return 200; + } + } +} From 2307cf4a84373d83623ca81cfb1ee5bef033d6f0 Mon Sep 17 00:00:00 2001 From: pinzart Date: Tue, 10 Nov 2020 23:27:25 -0500 Subject: [PATCH 09/13] add more tests --- test/DynamoCoreTests/CodeBlockNodeTests.cs | 18 ++++++++++++ test/Engine/FFITarget/TestHiddenMethods.cs | 34 +++++++++++----------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/test/DynamoCoreTests/CodeBlockNodeTests.cs b/test/DynamoCoreTests/CodeBlockNodeTests.cs index 440b951a909..9d1e14382f5 100644 --- a/test/DynamoCoreTests/CodeBlockNodeTests.cs +++ b/test/DynamoCoreTests/CodeBlockNodeTests.cs @@ -1318,6 +1318,24 @@ public void IntegerOverflow() AssertPreviewValue(mathCeiling.AstIdentifierGuid, long.MinValue); } + [Test] + [Category("UnitTests")] + public void TestStaticHiddenFunctionCallResolution() + { + const string libraryPath = "FFITarget.dll"; + + CompilerUtils.TryLoadAssemblyIntoCore( + CurrentDynamoModel.LibraryServices.LibraryManagementCore, libraryPath); + + var codeBlockNodeDerived = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeDerived, "DerivedTestHiddenMethods.SomeStaticMethod();"); + AssertPreviewValue(codeBlockNodeDerived.GUID.ToString(), "Derived"); + + var codeBlockNodeBase = CreateCodeBlockNode(); + UpdateCodeBlockNodeContent(codeBlockNodeBase, "BaseTestHiddenMethods.SomeStaticMethod();"); + AssertPreviewValue(codeBlockNodeBase.GUID.ToString(), "Base"); + } + #region CodeBlockUtils Specific Tests [Test] [Category("UnitTests")] diff --git a/test/Engine/FFITarget/TestHiddenMethods.cs b/test/Engine/FFITarget/TestHiddenMethods.cs index 214972077b5..7e5c0401b6f 100644 --- a/test/Engine/FFITarget/TestHiddenMethods.cs +++ b/test/Engine/FFITarget/TestHiddenMethods.cs @@ -4,26 +4,26 @@ namespace FFITarget { public class BaseTestHiddenMethods { - public static int SomeVariable = 100; + public static int SomeVariable = 50; public BaseTestHiddenMethods() { } - public static int SomeStaticMethod() + public static string SomeStaticMethod() { - return 100; + return "Base"; } - public static int SomeStaticMethod(int[] x) + public static string SomeStaticMethod(int[] x) { - return 100; + return "Base"; } - public static int SomeStaticMethod(int[] x, int[] y) + public static string SomeStaticMethod(int[] x, int[] y) { - return 100; + return "Base"; } - public static int SomeMethod() + public static string SomeMethod() { - return 100; + return "Base"; } } @@ -33,21 +33,21 @@ public class DerivedTestHiddenMethods : BaseTestHiddenMethods public DerivedTestHiddenMethods() { } - public static new int SomeStaticMethod() + public static new string SomeStaticMethod() { - return 200; + return "Derived"; } - public static new int SomeStaticMethod(int[] x) + public static new string SomeStaticMethod(int[] x) { - return 200; + return "Derived"; } - public static new int SomeStaticMethod(int[] x, int[] y) + public static new string SomeStaticMethod(int[] x, int[] y) { - return 200; + return "Derived"; } - public static new int SomeMethod() + public static new string SomeMethod() { - return 200; + return "Derived"; } } } From d7a6eea3cbf0e82c44591080f5fee21c20c3ca51 Mon Sep 17 00:00:00 2001 From: pinzart Date: Wed, 11 Nov 2020 09:25:59 -0500 Subject: [PATCH 10/13] Update CallSite.cs --- src/Engine/ProtoCore/Lang/CallSite.cs | 30 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index a1162977097..eacf25efef6 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1119,18 +1119,28 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor "this pointer wasn't a pointer. {89635B06-AD53-4170-ADA5-065EB2AE5858}"); - // We have 2 possible cases here: - // 1. Static method call (i.e no this pointer) - // Here we will cover the specific case of static method hiding. + // We have multiple possible scopes for the function call: + // 1. Static method call - no this pointer + // ex: ClassA.Method(); + // Hidden static methods generate multiple feps. // We do not need to check actually if the method has the "IsHideBySig" (https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.ishidebysig) // because static methods can only be hidden. - // In this case we simply select the function that belongs to the calling class. - // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. - // 2. Method call from an instance of a class. - // Try to match with methods of that class. - int typeID = svThisPtr.Pointer == Constants.kInvalidIndex ? stackFrame.ClassScope : svThisPtr.metaData.type; - - //Test for exact match + // 2. Method call from an instance of a class - valid this pointer. + // ex: classAInstance.method(); + // 3. Function from the global scope - no this pointer and no class scope. + // In this case the svThisPtr.metaData.type will hold the global + // ex: SomeGlobalFunction(); + // + // All 3 cases will run through the same matching steps. + + // A static function call has an invalid this pointer and a valid class scope; + bool isValidStaticFuncCall = svThisPtr.Pointer == Constants.kInvalidIndex && stackFrame.ClassScope != Constants.kInvalidIndex; + + int typeID = isValidStaticFuncCall ? stackFrame.ClassScope : svThisPtr.metaData.type; + + // Try to match with feps belonging to the class scope (most derived class should have priority). + // In this case we simply select the function that belongs to the calling class. + // The assumption here is that all function end points in "feps" have already been checked that they have the same signature. IEnumerable exactFeps = feps.Where(x => x.ClassOwnerIndex == typeID); if (exactFeps.Count() == 1) { From 9944c0206544cb482f9e954752f6e9d43879a4df Mon Sep 17 00:00:00 2001 From: pinzart Date: Wed, 11 Nov 2020 11:13:41 -0500 Subject: [PATCH 11/13] remove duplicate test class and PR related touches --- .../CodeCompletion/CodeCompletionServices.cs | 1 - src/Engine/ProtoCore/Lang/CallSite.cs | 1 - test/DynamoCoreTests/CodeBlockNodeTests.cs | 19 +++---- test/Engine/FFITarget/FFITarget.csproj | 1 - test/Engine/FFITarget/TestHiddenMethods.cs | 53 ------------------- 5 files changed, 10 insertions(+), 65 deletions(-) delete mode 100644 test/Engine/FFITarget/TestHiddenMethods.cs diff --git a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs index 57e1867125f..52fece92201 100644 --- a/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs +++ b/src/DynamoCore/Engine/CodeCompletion/CodeCompletionServices.cs @@ -183,7 +183,6 @@ internal IEnumerable GetFunctionSignatures(string code, string f candidates = type.GetOverloadsOnInstance(functionName); } } - return candidates.Select(x => CompletionData.ConvertMirrorToCompletionData(x)); } diff --git a/src/Engine/ProtoCore/Lang/CallSite.cs b/src/Engine/ProtoCore/Lang/CallSite.cs index eacf25efef6..1b948b72ec2 100644 --- a/src/Engine/ProtoCore/Lang/CallSite.cs +++ b/src/Engine/ProtoCore/Lang/CallSite.cs @@ -1128,7 +1128,6 @@ private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCor // 2. Method call from an instance of a class - valid this pointer. // ex: classAInstance.method(); // 3. Function from the global scope - no this pointer and no class scope. - // In this case the svThisPtr.metaData.type will hold the global // ex: SomeGlobalFunction(); // // All 3 cases will run through the same matching steps. diff --git a/test/DynamoCoreTests/CodeBlockNodeTests.cs b/test/DynamoCoreTests/CodeBlockNodeTests.cs index 9d1e14382f5..7f248ec18ae 100644 --- a/test/DynamoCoreTests/CodeBlockNodeTests.cs +++ b/test/DynamoCoreTests/CodeBlockNodeTests.cs @@ -1328,12 +1328,12 @@ public void TestStaticHiddenFunctionCallResolution() CurrentDynamoModel.LibraryServices.LibraryManagementCore, libraryPath); var codeBlockNodeDerived = CreateCodeBlockNode(); - UpdateCodeBlockNodeContent(codeBlockNodeDerived, "DerivedTestHiddenMethods.SomeStaticMethod();"); - AssertPreviewValue(codeBlockNodeDerived.GUID.ToString(), "Derived"); + UpdateCodeBlockNodeContent(codeBlockNodeDerived, "HidesMethodFromClassA.Baz();"); + AssertPreviewValue(codeBlockNodeDerived.GUID.ToString(), 23); var codeBlockNodeBase = CreateCodeBlockNode(); - UpdateCodeBlockNodeContent(codeBlockNodeBase, "BaseTestHiddenMethods.SomeStaticMethod();"); - AssertPreviewValue(codeBlockNodeBase.GUID.ToString(), "Base"); + UpdateCodeBlockNodeContent(codeBlockNodeBase, "ClassA.Baz();"); + AssertPreviewValue(codeBlockNodeBase.GUID.ToString(), 234); } #region CodeBlockUtils Specific Tests @@ -2298,11 +2298,12 @@ public void TestCompletionOnDerivedTypeReturnsBaseType() public void TestCompletionOnDerivedTypeReturnsNonHiddenBaseMethods() { var codeCompletionServices = new CodeCompletionServices(libraryServicesCore); - var completions = codeCompletionServices.GetCompletionsOnType("", "FFITarget.DerivedTestHiddenMethods").ToList(); - Assert.AreEqual(3, completions.Count); - Assert.AreEqual("DerivedTestHiddenMethods", completions[0].Text); - Assert.AreEqual("SomeStaticMethod", completions[1].Text); - Assert.AreEqual("SomeMethod", completions[2].Text); + var completions = codeCompletionServices.GetCompletionsOnType("", "FFITarget.HidesMethodFromClassA").ToList(); + Assert.AreEqual(4, completions.Count); + Assert.AreEqual("HidesMethodFromClassA", completions[0].Text); + Assert.AreEqual("Baz", completions[1].Text); + Assert.AreEqual("Bar", completions[2].Text); + Assert.AreEqual("Foo", completions[3].Text); } [Test] diff --git a/test/Engine/FFITarget/FFITarget.csproj b/test/Engine/FFITarget/FFITarget.csproj index bc23e207edc..6c65b0386db 100644 --- a/test/Engine/FFITarget/FFITarget.csproj +++ b/test/Engine/FFITarget/FFITarget.csproj @@ -77,7 +77,6 @@ - diff --git a/test/Engine/FFITarget/TestHiddenMethods.cs b/test/Engine/FFITarget/TestHiddenMethods.cs deleted file mode 100644 index 7e5c0401b6f..00000000000 --- a/test/Engine/FFITarget/TestHiddenMethods.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Autodesk.DesignScript.Runtime; - -namespace FFITarget -{ - public class BaseTestHiddenMethods - { - public static int SomeVariable = 50; - public BaseTestHiddenMethods() - { - } - - public static string SomeStaticMethod() - { - return "Base"; - } - public static string SomeStaticMethod(int[] x) - { - return "Base"; - } - public static string SomeStaticMethod(int[] x, int[] y) - { - return "Base"; - } - public static string SomeMethod() - { - return "Base"; - } - } - - public class DerivedTestHiddenMethods : BaseTestHiddenMethods - { - public static new int SomeVariable = 200; - public DerivedTestHiddenMethods() - { - } - public static new string SomeStaticMethod() - { - return "Derived"; - } - public static new string SomeStaticMethod(int[] x) - { - return "Derived"; - } - public static new string SomeStaticMethod(int[] x, int[] y) - { - return "Derived"; - } - public static new string SomeMethod() - { - return "Derived"; - } - } -} From 2f55cd04a705e7d6586973bac972d5469a99a696 Mon Sep 17 00:00:00 2001 From: pinzart Date: Thu, 12 Nov 2020 13:03:03 -0500 Subject: [PATCH 12/13] move test --- test/DynamoCoreTests/CodeBlockNodeTests.cs | 18 ---------------- test/Engine/ProtoTest/FFITests/CSFFITest.cs | 23 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/test/DynamoCoreTests/CodeBlockNodeTests.cs b/test/DynamoCoreTests/CodeBlockNodeTests.cs index 7f248ec18ae..9b86ca2d319 100644 --- a/test/DynamoCoreTests/CodeBlockNodeTests.cs +++ b/test/DynamoCoreTests/CodeBlockNodeTests.cs @@ -1318,24 +1318,6 @@ public void IntegerOverflow() AssertPreviewValue(mathCeiling.AstIdentifierGuid, long.MinValue); } - [Test] - [Category("UnitTests")] - public void TestStaticHiddenFunctionCallResolution() - { - const string libraryPath = "FFITarget.dll"; - - CompilerUtils.TryLoadAssemblyIntoCore( - CurrentDynamoModel.LibraryServices.LibraryManagementCore, libraryPath); - - var codeBlockNodeDerived = CreateCodeBlockNode(); - UpdateCodeBlockNodeContent(codeBlockNodeDerived, "HidesMethodFromClassA.Baz();"); - AssertPreviewValue(codeBlockNodeDerived.GUID.ToString(), 23); - - var codeBlockNodeBase = CreateCodeBlockNode(); - UpdateCodeBlockNodeContent(codeBlockNodeBase, "ClassA.Baz();"); - AssertPreviewValue(codeBlockNodeBase.GUID.ToString(), 234); - } - #region CodeBlockUtils Specific Tests [Test] [Category("UnitTests")] diff --git a/test/Engine/ProtoTest/FFITests/CSFFITest.cs b/test/Engine/ProtoTest/FFITests/CSFFITest.cs index 1d7369e20f7..f484b5cc6d5 100644 --- a/test/Engine/ProtoTest/FFITests/CSFFITest.cs +++ b/test/Engine/ProtoTest/FFITests/CSFFITest.cs @@ -501,6 +501,29 @@ public void TestInheritanceCtorsVirtualMethods() ExecuteAndVerify(code, data); } + [Test] + public void TestStaticHiddenFunctionCallResolution() + { + string code = @" + b = HidesMethodFromClassA.Baz(); + "; + + Type dummy = typeof(FFITarget.HidesMethodFromClassA); + code = string.Format("import(\"{0}\");\r\n{1}", dummy.AssemblyQualifiedName, code); + Console.WriteLine(code); + ValidationData[] data = { new ValidationData { ValueName = "b", ExpectedValue = 23, BlockIndex = 0 } }; + ExecuteAndVerify(code, data); + + code = @" + b = ClassA.Baz(); + "; + dummy = typeof(FFITarget.ClassA); + code = string.Format("import(\"{0}\");\r\n{1}", dummy.AssemblyQualifiedName, code); + Console.WriteLine(code); + ValidationData[] data1 = { new ValidationData { ValueName = "b", ExpectedValue = 234, BlockIndex = 0 } }; + ExecuteAndVerify(code, data1); + } + [Test] public void TestInheritanceCtorsVirtualMethods2() { From 5ccafffc0ef521ce7c9b837ce14667309f89ea62 Mon Sep 17 00:00:00 2001 From: pinzart Date: Thu, 12 Nov 2020 13:08:19 -0500 Subject: [PATCH 13/13] Update CSFFITest.cs --- test/Engine/ProtoTest/FFITests/CSFFITest.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/test/Engine/ProtoTest/FFITests/CSFFITest.cs b/test/Engine/ProtoTest/FFITests/CSFFITest.cs index f484b5cc6d5..ca8cdfca217 100644 --- a/test/Engine/ProtoTest/FFITests/CSFFITest.cs +++ b/test/Engine/ProtoTest/FFITests/CSFFITest.cs @@ -505,23 +505,17 @@ public void TestInheritanceCtorsVirtualMethods() public void TestStaticHiddenFunctionCallResolution() { string code = @" - b = HidesMethodFromClassA.Baz(); + d = HidesMethodFromClassA.Baz(); + b = ClassA.Baz(); "; Type dummy = typeof(FFITarget.HidesMethodFromClassA); code = string.Format("import(\"{0}\");\r\n{1}", dummy.AssemblyQualifiedName, code); Console.WriteLine(code); - ValidationData[] data = { new ValidationData { ValueName = "b", ExpectedValue = 23, BlockIndex = 0 } }; + ValidationData[] data = { new ValidationData { ValueName = "d", ExpectedValue = 23, BlockIndex = 0 }, + new ValidationData { ValueName = "b", ExpectedValue = 234, BlockIndex = 0 } + }; ExecuteAndVerify(code, data); - - code = @" - b = ClassA.Baz(); - "; - dummy = typeof(FFITarget.ClassA); - code = string.Format("import(\"{0}\");\r\n{1}", dummy.AssemblyQualifiedName, code); - Console.WriteLine(code); - ValidationData[] data1 = { new ValidationData { ValueName = "b", ExpectedValue = 234, BlockIndex = 0 } }; - ExecuteAndVerify(code, data1); } [Test]