Esempio n. 1
0
        internal EnvDTE.CodeAttribute AddAttribute(SyntaxNode containerNode, string name, string value, object position, string?target = null)
        {
            containerNode = CodeModelService.GetNodeWithAttributes(containerNode);
            var attributeNode  = CodeModelService.CreateAttributeNode(CodeModelService.GetUnescapedName(name), value, target);
            var insertionIndex = CodeModelService.PositionVariantToAttributeInsertionIndex(position, containerNode, fileCodeModel: this);

            var newNode = InsertAttribute(containerNode, attributeNode, insertionIndex);

            return((EnvDTE.CodeAttribute)CodeModelService.CreateInternalCodeElement(this.State, fileCodeModel: this, node: newNode));
        }
        private EnvDTE.CodeElement CreateInternalCodeMember(CodeModelState state, FileCodeModel fileCodeModel, SyntaxNode node)
        {
            var element = CodeModelService.CreateInternalCodeElement(state, fileCodeModel, node);

            if (IsBatchOpen)
            {
                var codeElement = ComAggregate.TryGetManagedObject <AbstractKeyedCodeElement>(element);
                if (codeElement != null)
                {
                    _batchElements.Add(codeElement);
                }
            }

            return(element);
        }
Esempio n. 3
0
        internal T CreateCodeElement <T>(SyntaxNode node)
        {
            var nodeKey = CodeModelService.TryGetNodeKey(node);

            if (!nodeKey.IsEmpty)
            {
                // Check if the node exists in the parse tree.
                // Note that in designer spew the nodes don't get created right away so we skip this check.
                if (!IsBatchOpen && CodeModelService.LookupNode(nodeKey, GetSyntaxTree()) == null)
                {
                    throw Exceptions.ThrowEFail();
                }

                // See if the element exists.
                var previousElement = _elementTable.TryGetValue(nodeKey);

                // Here's our element... possibly.  It must be valid -- if it isn't,
                // we need to remove it.
                if (previousElement != null)
                {
                    var previousElementImpl = ComAggregate.TryGetManagedObject <AbstractCodeElement>(previousElement);

                    if (previousElementImpl.IsValidNode())
                    {
                        if (previousElement is T)
                        {
                            return((T)previousElement);
                        }
                        else
                        {
                            Debug.Fail("Called asked for the wrong type!");
                            throw new InvalidOperationException();
                        }
                    }
                    else
                    {
                        // This guy is no longer valid, so yank it out.  No sense
                        // continuing to look for a match, either.
                        RemoveElement(nodeKey);
                    }
                }
            }

            return((T)CodeModelService.CreateInternalCodeElement(this.State, this, node));
        }
Esempio n. 4
0
        internal T GetOrCreateCodeElement <T>(SyntaxNode node)
        {
            var nodeKey = CodeModelService.TryGetNodeKey(node);

            if (!nodeKey.IsEmpty)
            {
                // Since the node already has a key, check to see if a code element already
                // exists for it. If so, return that element it it's still valid; otherwise,
                // remove it from the table.
                if (_codeElementTable.TryGetValue(nodeKey, out var codeElement))
                {
                    if (codeElement != null)
                    {
                        var element = ComAggregate.TryGetManagedObject <AbstractCodeElement>(
                            codeElement
                            );
                        if (element.IsValidNode())
                        {
                            if (codeElement is T tcodeElement)
                            {
                                return(tcodeElement);
                            }

                            throw new InvalidOperationException(
                                      $"Found a valid code element for {nodeKey}, but it is not of type, {typeof(T).ToString()}"
                                      );
                        }
                    }
                }

                // Go ahead and remove the nodeKey from the table. At this point, we'll be creating a new one.
                _codeElementTable.Remove(nodeKey);
            }

            return((T)CodeModelService.CreateInternalCodeElement(this.State, this, node));
        }
Esempio n. 5
0
        internal EnvDTE.CodeElement CodeElementFromPosition(int position, EnvDTE.vsCMElement scope)
        {
            var root       = GetSyntaxRoot();
            var leftToken  = SyntaxFactsService.FindTokenOnLeftOfPosition(root, position);
            var rightToken = SyntaxFactsService.FindTokenOnRightOfPosition(root, position);

            // We apply a set of heuristics to determine which member we pick to start searching.
            var token = leftToken;

            if (leftToken != rightToken)
            {
                if (leftToken.Span.End == position && rightToken.SpanStart == position)
                {
                    // If both tokens are touching, we prefer identifiers and keywords to
                    // separators. Note that the language doesn't allow both tokens to be a
                    // keyword or identifier.
                    if (SyntaxFactsService.IsKeyword(rightToken) ||
                        SyntaxFactsService.IsIdentifier(rightToken))
                    {
                        token = rightToken;
                    }
                }
                else if (leftToken.Span.End < position && rightToken.SpanStart <= position)
                {
                    // If only the right token is touching, we have to use it.
                    token = rightToken;
                }
            }

            // If we ended up using the left token but the position is after that token,
            // walk up to the first node who's last token is not the leftToken. By doing this, we
            // ensure that we don't find members when the position is actually between them.
            // In that case, we should find the enclosing type or namespace.
            var parent = token.Parent;

            if (token == leftToken && position > token.Span.End)
            {
                while (parent != null)
                {
                    if (parent.GetLastToken() == token)
                    {
                        parent = parent.Parent;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            var node = parent != null
                ? parent.AncestorsAndSelf().FirstOrDefault(n => CodeModelService.MatchesScope(n, scope))
                : null;

            if (node == null)
            {
                return(null);
            }

            if (scope == EnvDTE.vsCMElement.vsCMElementAttribute ||
                scope == EnvDTE.vsCMElement.vsCMElementImportStmt ||
                scope == EnvDTE.vsCMElement.vsCMElementParameter ||
                scope == EnvDTE.vsCMElement.vsCMElementOptionStmt ||
                scope == EnvDTE.vsCMElement.vsCMElementInheritsStmt ||
                scope == EnvDTE.vsCMElement.vsCMElementImplementsStmt ||
                (scope == EnvDTE.vsCMElement.vsCMElementFunction && CodeModelService.IsAccessorNode(node)))
            {
                // Attributes, imports, parameters, Option, Inherts and Implements
                // don't have node keys of their own and won't be included in our
                // collection of elements. Delegate to the service to create these.
                return(CodeModelService.CreateInternalCodeElement(State, this, node));
            }

            return(CreateCodeElement <EnvDTE.CodeElement>(node));
        }