Exemple #1
0
        public void GetBoundNodes(LanguageSyntaxNode node, out LanguageSyntaxNode bindableNode, out BoundNode lowestBoundNode, out BoundNode highestBoundNode, out BoundNode boundParent)
        {
            bindableNode = this.GetBindableSyntaxNode(node);

            LanguageSyntaxNode bindableParent = this.GetBindableParentNode(bindableNode);

            /* TODO:MetaDslx
             * // Special handling for the Color Color case.
             * //
             * // Suppose we have:
             * // public class Color {
             * //   public void M(int x) {}
             * //   public static void M(params int[] x) {}
             * // }
             * // public class C {
             * //   public void Test() {
             * //     Color Color = new Color();
             * //     System.Action<int> d = Color.M;
             * //   }
             * // }
             * //
             * // We actually don't know how to interpret the "Color" in "Color.M" until we
             * // perform overload resolution on the method group.  Now, if we were getting
             * // the semantic info for the method group, then bindableParent would be the
             * // variable declarator "d = Color.M" and so we would be able to pull the result
             * // of overload resolution out of the bound (method group) conversion.  However,
             * // if we are getting the semantic info for just the "Color" part, then
             * // bindableParent will be the member access, which doesn't have enough information
             * // to determine which "Color" to use (since no overload resolution has been
             * // performed).  We resolve this problem by detecting the case where we're looking
             * // up the LHS of a member access and calling GetBindableParentNode one more time.
             * // This gets us up to the level where the method group conversion occurs.
             * if (bindableParent != null && bindableParent.Kind() == SyntaxKind.SimpleMemberAccessExpression && ((MemberAccessExpressionSyntax)bindableParent).Expression == bindableNode)
             * {
             *  bindableParent = this.GetBindableParentNode(bindableParent);
             * }*/

            boundParent = bindableParent == null ? null : this.GetLowerBoundNode(bindableParent);

            lowestBoundNode  = this.GetLowerBoundNode(bindableNode);
            highestBoundNode = this.GetUpperBoundNode(bindableNode);
        }
Exemple #2
0
        /// <summary>
        /// Get all bounds nodes associated with a node, ordered from highest to lowest in the bound tree.
        /// Strictly speaking, the order is that of a pre-order traversal of the bound tree.
        /// </summary>
        public ImmutableArray <BoundNode> GetBoundNodes(LanguageSyntaxNode node)
        {
            // If this method is called with a null parameter, that implies that the Root should be
            // bound, but make sure that the Root is bindable.
            if (node == null)
            {
                node = GetBindableSyntaxNode(Root);
            }
            //Debug.Assert(node == GetBindableSyntaxNode(node));

            // We have one SemanticModel for each method.
            //
            // The SemanticModel contains a lazily-built immutable map from scope-introducing
            // syntactic statements (such as blocks) to binders, but not from lambdas to binders.
            //
            // The SemanticModel also contains a mutable map from syntax to bound nodes; that is
            // declared here. Since the map is not thread-safe we ensure that it is guarded with a
            // reader-writer lock.
            //
            // Have we already got the desired bound node in the mutable map? If so, return it.
            ImmutableArray <BoundNode> results = GetBoundNodesFromMap(node);

            if (!results.IsDefaultOrEmpty)
            {
                return(results);
            }

            // We might not actually have been given an expression or statement even though we were
            // allegedly given something that is "bindable".

            // If we didn't find in the cached bound nodes, find a binding root and bind it.
            // This will cache bound nodes under the binding root.
            LanguageSyntaxNode nodeToBind = GetBindingRoot(node);
            var nodeBinder = GetEnclosingBinder(GetAdjustedNodePosition(nodeToBind));

            BoundNode boundNode = nodeBinder.CreateBoundNodeForBoundTree(nodeToBind, this);

            results = AddBoundTreeAndGetBoundNodeFromMap(node, boundNode);

            if (!results.IsDefaultOrEmpty)
            {
                return(results);
            }

            // If we still didn't find it, its still possible we could bind it directly.
            // For example, types are usually not represented by bound nodes, and some error conditions and
            // not yet implemented features do not create bound nodes for everything underneath them.
            //
            // In this case, however, we only add the single bound node we found to the map, not any child bound nodes,
            // to avoid duplicates in the map if a parent of this node comes through this code path also.

            var binder = GetEnclosingBinder(GetAdjustedNodePosition(node));

            results = GetBoundNodesFromMap(node);

            if (!results.IsDefaultOrEmpty)
            {
                return(results);
            }

            /*else
             * {
             *  var directlyBoundNode = binder.CreateBoundNodeForBoundTree(node, this);
             *  AddBoundTreeForStandaloneSyntax(node, directlyBoundNode);
             *  results = GetBoundNodesFromMap(node);
             *
             *  if (!results.IsDefaultOrEmpty)
             *  {
             *      return results;
             *  }
             * }*/

            return(ImmutableArray <BoundNode> .Empty);
        }
Exemple #3
0
        private static void AddNode(OrderPreservingMultiDictionary <SyntaxNode, BoundNode> map, SyntaxNode thisSyntaxNodeOnly, BoundNode node)
        {
            if (node == null)
            {
                return;
            }

            // It is possible for there to be multiple bound nodes with the same syntax tree,
            // and that is by design. For example, in
            //
            // byte b = 3;
            //
            // there is a bound node for the implicit conversion to byte and a bound node for the
            // literal, an int. Sometimes we want the inner one (to state the type of the expression)
            // and sometimes we want the "parent's" view of things (for extract method, for instance.)
            //
            // We want to add all bound nodes associated with the same syntax node to the cache, so we first add the
            // bound node, then we dive deeper into the bound tree.
            if (ShouldAddNode(node, thisSyntaxNodeOnly))
            {
                map.Add(node.Syntax, node);
            }
        }
Exemple #4
0
        // Adds every syntax/bound pair in a tree rooted at the given bound node to the map, and the
        // performs a lookup of the given syntax node in the map.
        private ImmutableArray <BoundNode> AddBoundTreeAndGetBoundNodeFromMap(LanguageSyntaxNode syntax, BoundNode bound)
        {
            bool alreadyInTree = false;

            if (bound != null)
            {
                alreadyInTree = _map.ContainsKey(bound.Syntax);
            }

            // check if we already have node in the cache.
            // this may happen if we have races and in such case we are no longer interested in adding
            if (!alreadyInTree)
            {
                BoundNodeMapBuilder.AddToMap(bound, _map);
            }

            ImmutableArray <BoundNode> result;

            return(_map.TryGetValue(syntax, out result) ? result : default(ImmutableArray <BoundNode>));
        }
Exemple #5
0
        private static void CacheSubTree(OrderPreservingMultiDictionary <SyntaxNode, BoundNode> map, SyntaxNode thisSyntaxNodeOnly, BoundNode node)
        {
            if (node == null)
            {
                return;
            }
            Stack <BoundNode> nodeStack = new Stack <BoundNode>();

            nodeStack.Push(node);
            while (nodeStack.Count > 0)
            {
                BoundNode current = nodeStack.Pop();
                AddNode(map, thisSyntaxNodeOnly, current);
                var currentChildren = current.GetChildBoundNodes(thisSyntaxNodeOnly);
                for (int i = currentChildren.Length - 1; i >= 0; --i)
                {
                    nodeStack.Push(currentChildren[i]);
                }
            }
        }