Merge pull request #601 from knocte/sock_improvements
[mono.git] / mcs / class / monodoc / Monodoc / providers / EcmaDoc.cs
index e6e7e618bac6c2c1fa9c4509f9b9e6f878cf4bd5..e3371d141d0e46ab9a591ae2b590cc9532fdf0b9 100644 (file)
@@ -212,7 +212,10 @@ namespace Monodoc.Providers
                        currentNode = result;
                        result = null;
                        searchNode.Caption = desc.ToCompleteTypeName ();
-                       index = currentNode.ChildNodes.BinarySearch (searchNode, EcmaTypeNodeComparer.Instance);
+                       if (!desc.GenericTypeArgumentsIsNumeric)
+                               index = currentNode.ChildNodes.BinarySearch (searchNode, EcmaTypeNodeComparer.Instance);
+                       else
+                               index = GenericTypeBacktickSearch (currentNode.ChildNodes, desc);
                        if (index >= 0)
                                result = currentNode.ChildNodes[index];
                        if ((desc.DescKind == EcmaDesc.Kind.Type && !desc.IsEtc) || index < 0)
@@ -249,6 +252,48 @@ namespace Monodoc.Providers
                        return result;
                }
 
+               static int GenericTypeBacktickSearch (IList<Node> childNodes, EcmaDesc desc)
+               {
+                       /* Our strategy is to search for the non-generic variant of the type
+                        * (which in most case should fail) and then use the closest index
+                        * to linearily search for the generic variant with the right generic arg number
+                        */
+                       var searchNode = new Node () { Caption = desc.TypeName };
+                       int index = childNodes.BinarySearch (searchNode, EcmaTypeNodeComparer.Instance);
+                       // Place the index in the right start position
+                       if (index < 0)
+                               index = ~index;
+
+                       for (int i = index; i < childNodes.Count; i++) {
+                               var currentNode = childNodes[i];
+                               // Find the index of the generic argument list
+                               int genericIndex = currentNode.Caption.IndexOf ('<');
+                               // If we are not on the same base type name anymore, there is no point
+                               int captionSlice = genericIndex != -1 ? genericIndex : currentNode.Caption.LastIndexOf (' ');
+                               if (string.Compare (searchNode.Caption, 0,
+                                                   currentNode.Caption, 0,
+                                                   Math.Max (captionSlice, searchNode.Caption.Length),
+                                                   StringComparison.Ordinal) != 0)
+                                       break;
+
+                               var numGenerics = CountTypeGenericArguments (currentNode.Caption, genericIndex);
+                               if (numGenerics == desc.GenericTypeArguments.Count) {
+                                       // Simple comparison if we are not looking for an inner type
+                                       if (desc.NestedType == null)
+                                               return i;
+                                       // If more complicated, we fallback to using EcmaUrlParser
+                                       var caption = currentNode.Caption;
+                                       caption = "T:" + caption.Substring (0, caption.LastIndexOf (' ')).Replace ('.', '+');
+                                       EcmaDesc otherDesc;
+                                       var parser = new EcmaUrlParser ();
+                                       if (parser.TryParse (caption, out otherDesc) && desc.NestedType.Equals (otherDesc.NestedType))
+                                               return i;
+                               }
+                       }
+
+                       return -1;
+               }
+
                // This comparer returns the answer straight from caption comparison
                class EcmaGenericNodeComparer : IComparer<Node>
                {
@@ -428,7 +473,7 @@ namespace Monodoc.Providers
                        }
                }
 
-               public static Node FindNodeForCaption (List<Node> nodes, string caption)
+               public static Node FindNodeForCaption (IList<Node> nodes, string caption)
                {
                        foreach (var node in nodes)
                                if (node.Caption.Equals (caption, StringComparison.OrdinalIgnoreCase))
@@ -436,6 +481,33 @@ namespace Monodoc.Providers
                        return null;
                }
 
+               public static int CountTypeGenericArguments (string typeDefinition, int startIndex = 0)
+               {
+                       int nestedLevel = 0;
+                       int count = 0;
+                       bool started = false;
+
+                       foreach (char c in typeDefinition.Skip (startIndex)) {
+                               switch (c) {
+                               case '<':
+                                       if (!started)
+                                               count = 1;
+                                       started = true;
+                                       nestedLevel++;
+                                       break;
+                               case ',':
+                                       if (started && nestedLevel == 1)
+                                               count++;
+                                       break;
+                               case '>':
+                                       nestedLevel--;
+                                       break;
+                               }
+                       }
+
+                       return count;
+               }
+
                internal static string MakeOperatorSignature (XElement member, out string memberSignature)
                {
                        string name = (string)member.Attribute ("MemberName");