public static SyntaxNode ConvertToTriviaList(this SyntaxNode[] nodes)
        {
            var builder = new SyntaxListBuilder(nodes.Length);
            for (int i = 0; i < nodes.Length; i++)
            {
                var node = nodes[i];
                var nd = node.GetDiagnostics();
                foreach (var token in node.GetTokens())
                {
                    builder.Add(token.GetLeadingTrivia());
                    if (token.Width > 0)
                    {
                        var tk = token.WithLeadingTrivia(null).WithTrailingTrivia(null);
                        System.Diagnostics.Debug.Assert(tk.HasDiagnostics == token.HasDiagnostics);
                        if (nd != null && nd.Length > 0)
                        {
                            if (token != node)
                            {
                                tk = tk.WithAdditionalDiagnostics(nd);
                            }

                            nd = null;
                        }

                        builder.Add(Syntax.SkippedTokens(tk));
                    }

                    builder.Add(token.GetTrailingTrivia());
                }
            }

            return builder.ToListNode();
        }
        /// <summary>
        /// Look up a well known SyntaxToken for a given XML element tag or attribute.
        /// This is a performance optimization to avoid creating duplicate tokens for the same content.
        /// </summary>
        /// <param name="text">The text of the tag or attribute.</param>
        /// <param name="leading">The leading trivia of the token.</param>
        /// <returns>The SyntaxToken representing the well-known tag or attribute or null if it's not well-known.</returns>
        public static SyntaxToken LookupToken(string text, SyntaxListBuilder leading)
        {
            if (leading == null)
            {
                return LookupXmlElementTag(text);
            }

            if (IsSingleSpaceTrivia(leading))
            {
                return LookupXmlAttribute(text);
            }

            return null;
        }
示例#3
0
        public void GetEditedContent_SyntaxNode_ReturnsNewContent()
        {
            // Arrange
            var builder = SyntaxListBuilder <SyntaxToken> .Create();

            builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "Hello, "));
            builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "World"));

            var node = SyntaxFactory.MarkupTextLiteral(builder.ToList()).CreateRed();

            var change = new SourceChange(2, 2, "heyo");

            // Act
            var result = change.GetEditedContent(node);

            // Act
            Assert.Equal("Heheyoo, World", result);
        }
示例#4
0
        public void GetOrigninalText_SpanIsOwner_ReturnsContent_ZeroLengthSpan()
        {
            // Arrange
            var builder = SyntaxListBuilder <SyntaxToken> .Create();

            builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "Hello, "));
            builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "World"));

            var node = SyntaxFactory.MarkupTextLiteral(builder.ToList()).CreateRed(null, 13);

            var change = new SourceChange(15, 0, "heyo");

            // Act
            var result = change.GetOriginalText(node);

            // Act
            Assert.Equal(string.Empty, result);
        }
示例#5
0
        public void GetOffSet_SpanIsOwner_ReturnsOffset()
        {
            // Arrange
            var builder = SyntaxListBuilder <SyntaxToken> .Create();

            builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "Hello, "));
            builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "World"));

            var node = SyntaxFactory.MarkupTextLiteral(builder.ToList()).CreateRed(null, 13);

            var change = new SourceChange(15, 2, "heyo");

            // Act
            var result = change.GetOffset(node);

            // Act
            Assert.Equal(2, result);
        }
示例#6
0
        static void AddTokens(SyntaxNode current, SyntaxListBuilder <SyntaxToken> tokens)
        {
            if (current.SlotCount == 0 && current is SyntaxToken token)
            {
                // Token
                tokens.Add(token);
                return;
            }

            for (var i = 0; i < current.SlotCount; i++)
            {
                var child = current.GetNodeSlot(i);

                if (child != null)
                {
                    AddTokens(child, tokens);
                }
            }
        }
示例#7
0
    public void GetOffSet_SpanIsNotOwnerOfChange_ThrowsException()
    {
        // Arrange
        var builder = SyntaxListBuilder <SyntaxToken> .Create();

        builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "Hello, "));
        builder.Add(SyntaxFactory.Token(SyntaxKind.Marker, "World"));

        var node = SyntaxFactory.MarkupTextLiteral(builder.ToList()).CreateRed(null, 13);

        var change = new SourceChange(12, 2, "heyo");

        var expected = $"The node '{node}' is not the owner of change '{change}'.";

        // Act & Assert
        var exception = Assert.Throws <InvalidOperationException>(() => { change.GetOffset(node); });

        Assert.Equal(expected, exception.Message);
    }
示例#8
0
        private static SyntaxNode?CreateNode(IEnumerable <TNode>?nodes)
        {
            if (nodes == null)
            {
                return(null);
            }

            var collection = nodes as ICollection <TNode>;
            var builder    =
                (collection != null)
                    ? new SyntaxListBuilder <TNode>(collection.Count)
                    : SyntaxListBuilder <TNode> .Create();

            foreach (TNode node in nodes)
            {
                builder.Add(node);
            }

            return(builder.ToList().Node);
        }
        private HtmlNodeSyntax GetSyntaxNode(SyntaxKind syntaxKind)
        {
            if (syntaxKind == SyntaxKind.HtmlText)
            {
                var textTokens = new SyntaxListBuilder <SyntaxToken>(SyntaxListBuilder.Create());
                foreach (var token in Tokens)
                {
                    if (token.SyntaxKind == SyntaxKind.Unknown)
                    {
                        Debug.Assert(false, $"Unexpected html token {((HtmlToken)token).Type}");
                        continue;
                    }

                    textTokens.Add(token.SyntaxToken);
                }
                var textResult = textTokens.ToList();
                return(SyntaxFactory.HtmlText(new SyntaxList <SyntaxToken>(textResult.Node)));
            }

            return(null);
        }
示例#10
0
        private Syntax.GreenNode GetSyntaxNode(SyntaxKind syntaxKind)
        {
            if (syntaxKind == SyntaxKind.HtmlTextLiteral)
            {
                var textTokens = new SyntaxListBuilder <SyntaxToken>(SyntaxListBuilder.Create());
                foreach (var token in Tokens)
                {
                    if (token.Kind == SyntaxKind.Unknown)
                    {
                        Debug.Assert(false, $"Unexpected token {token.Kind}");
                        continue;
                    }

                    textTokens.Add(token);
                }
                var textResult = textTokens.ToList();
                return(SyntaxFactory.HtmlTextLiteral(new SyntaxList <SyntaxToken>(textResult.Node)));
            }

            return(null);
        }
示例#11
0
    internal SyntaxListBuilder Allocate()
    {
        SyntaxListBuilder item;

        if (_freeIndex > 0)
        {
            _freeIndex--;
            item = _freeList[_freeIndex].Value;
            _freeList[_freeIndex].Value = null;
        }
        else
        {
            item = new SyntaxListBuilder(10);
        }

#if DEBUG
        Debug.Assert(!_allocated.Contains(item));
        _allocated.Add(item);
#endif
        return(item);
    }
        public static SyntaxNode ConvertToTriviaList(this SyntaxNode[] nodes)
        {
            var builder = new SyntaxListBuilder(nodes.Length);

            for (int i = 0; i < nodes.Length; i++)
            {
                var node = nodes[i];
                var nd   = node.GetDiagnostics();
                foreach (var token in node.GetTokens())
                {
                    builder.Add(token.GetLeadingTrivia());
                    if (token.Width > 0)
                    {
                        var text = Syntax.SkippedText(token.GetText());
                        var d    = token.GetDiagnostics();
                        if (d.Length > 0)
                        {
                            text = text.WithDiagnostics(d);
                        }

                        if (nd != null && nd.Length > 0)
                        {
                            if (token != node)
                            {
                                text = text.WithAdditionalDiagnostics(nd);
                            }

                            nd = null;
                        }

                        builder.Add(text);
                    }

                    builder.Add(token.GetTrailingTrivia());
                }
            }

            return(builder.ToListNode());
        }
        public static SyntaxNode ConvertToTriviaList(this SyntaxNode[] nodes)
        {
            var builder = new SyntaxListBuilder(nodes.Length);
            for (int i = 0; i < nodes.Length; i++)
            {
                var node = nodes[i];
                var nd = node.GetDiagnostics();
                foreach (var token in node.GetTokens())
                {
                    builder.Add(token.GetLeadingTrivia());
                    if (token.Width > 0)
                    {
                        var text = Syntax.SkippedText(token.GetText());
                        var d = token.GetDiagnostics();
                        if (d.Length > 0)
                        {
                            text = text.WithDiagnostics(d);
                        }

                        if (nd != null && nd.Length > 0)
                        {
                            if (token != node)
                            {
                                text = text.WithAdditionalDiagnostics(nd);
                            }

                            nd = null;
                        }

                        builder.Add(text);
                    }

                    builder.Add(token.GetTrailingTrivia());
                }
            }

            return builder.ToListNode();
        }
示例#14
0
        private static SyntaxList <RazorSyntaxNode> GetRewrittenMarkupEndTagChildren(MarkupEndTagSyntax node)
        {
            // Rewrites the children of the end tag to look like the legacy syntax tree.
            if (node.IsMarkupTransition)
            {
                var tokens       = node.DescendantNodes().Where(n => n is SyntaxToken token && !token.IsMissing).Cast <SyntaxToken>().ToArray();
                var tokenBuilder = SyntaxListBuilder <SyntaxToken> .Create();

                tokenBuilder.AddRange(tokens, 0, tokens.Length);
                var markupTransition = SyntaxFactory.MarkupTransition(tokenBuilder.ToList()).Green.CreateRed(node, node.Position);
                var spanContext      = node.GetSpanContext();
                if (spanContext != null)
                {
                    markupTransition = markupTransition.WithSpanContext(spanContext);
                }

                var builder = new SyntaxListBuilder(1);
                builder.Add(markupTransition);
                return(new SyntaxList <RazorSyntaxNode>(builder.ToListNode().CreateRed(node, node.Position)));
            }

            return(node.Children);
        }
示例#15
0
        private static int GetFullWidth(SyntaxListBuilder builder)
        {
            int width = 0;

            if (builder != null)
            {
                for (int i = 0; i < builder.Count; i++)
                {
                    width += builder[i].FullWidth;
                }
            }

            return width;
        }
示例#16
0
        private SyntaxToken Create(ref TokenInfo info, SyntaxListBuilder leading, SyntaxListBuilder trailing, SyntaxDiagnosticInfo[] errors)
        {
            Debug.Assert(info.Kind != SyntaxKind.IdentifierToken || info.StringValue != null);

            var leadingNode = SyntaxList.List(leading);
            var trailingNode = SyntaxList.List(trailing);

            SyntaxToken token;
            if (info.RequiresTextForXmlEntity)
            {
                token = SyntaxFactory.Token(leadingNode, info.Kind, info.Text, info.StringValue, trailingNode);
            }
            else
            {
                switch (info.Kind)
                {
                    case SyntaxKind.IdentifierToken:
                        token = SyntaxFactory.Identifier(info.ContextualKind, leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.NumericLiteralToken:
                        switch (info.ValueKind)
                        {
                            case SpecialType.System_Int32:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.IntValue, trailingNode);
                                break;
                            case SpecialType.System_UInt32:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.UintValue, trailingNode);
                                break;
                            case SpecialType.System_Int64:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.LongValue, trailingNode);
                                break;
                            case SpecialType.System_UInt64:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.UlongValue, trailingNode);
                                break;
                            case SpecialType.System_Single:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.FloatValue, trailingNode);
                                break;
                            case SpecialType.System_Double:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.DoubleValue, trailingNode);
                                break;
                            case SpecialType.System_Decimal:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.DecimalValue, trailingNode);
                                break;
                            default:
                                throw ExceptionUtilities.UnexpectedValue(info.ValueKind);
                        }

                        break;
                    case SyntaxKind.InterpolatedStringToken:
                        // we do not record a separate "value" for an interpolated string token, as it must be rescanned during parsing.
                        token = SyntaxFactory.Literal(leadingNode, info.Text, info.Kind, info.Text, trailingNode);
                        break;
                    case SyntaxKind.StringLiteralToken:
                        token = SyntaxFactory.Literal(leadingNode, info.Text, info.Kind, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.CharacterLiteralToken:
                        token = SyntaxFactory.Literal(leadingNode, info.Text, info.CharValue, trailingNode);
                        break;
                    case SyntaxKind.XmlTextLiteralNewLineToken:
                        token = SyntaxFactory.XmlTextNewLine(leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.XmlTextLiteralToken:
                        token = SyntaxFactory.XmlTextLiteral(leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.XmlEntityLiteralToken:
                        token = SyntaxFactory.XmlEntity(leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.EndOfDocumentationCommentToken:
                    case SyntaxKind.EndOfFileToken:
                        token = SyntaxFactory.Token(leadingNode, info.Kind, trailingNode);
                        break;
                    case SyntaxKind.None:
                        token = SyntaxFactory.BadToken(leadingNode, info.Text, trailingNode);
                        break;

                    default:
                        Debug.Assert(SyntaxFacts.IsPunctuationOrKeyword(info.Kind));
                        token = SyntaxFactory.Token(leadingNode, info.Kind, trailingNode);
                        break;
                }
            }

            if (errors != null && (_options.DocumentationMode >= DocumentationMode.Diagnose || !InDocumentationComment))
            {
                token = token.WithDiagnosticsGreen(errors);
            }

            return token;
        }
示例#17
0
        private void LexExcludedDirectivesAndTrivia(bool endIsActive, ref SyntaxListBuilder triviaList)
        {
            while (true)
            {
                bool hasFollowingDirective;
                var text = this.LexDisabledText(out hasFollowingDirective);
                if (text != null)
                {
                    this.AddTrivia(text, ref triviaList);
                }

                if (!hasFollowingDirective)
                {
                    break;
                }

                var directive = this.LexSingleDirective(false, endIsActive, false, false, ref triviaList);
                var branching = directive as BranchingDirectiveTriviaSyntax;
                if (directive.Kind == SyntaxKind.EndIfDirectiveTrivia || (branching != null && branching.BranchTaken))
                {
                    break;
                }
                else if (directive.Kind == SyntaxKind.IfDirectiveTrivia)
                {
                    this.LexExcludedDirectivesAndTrivia(false, ref triviaList);
                }
            }
        }
示例#18
0
        private CSharpSyntaxNode LexSingleDirective(
            bool isActive,
            bool endIsActive,
            bool afterFirstToken,
            bool afterNonWhitespaceOnLine,
            ref SyntaxListBuilder triviaList)
        {
            if (SyntaxFacts.IsWhitespace(TextWindow.PeekChar()))
            {
                this.Start();
                this.AddTrivia(this.ScanWhitespace(), ref triviaList);
            }

            CSharpSyntaxNode directive;
            var saveMode = _mode;

            using (var dp = new DirectiveParser(this, _directives))
            {
                directive = dp.ParseDirective(isActive, endIsActive, afterFirstToken, afterNonWhitespaceOnLine);
            }

            this.AddTrivia(directive, ref triviaList);
            _directives = directive.ApplyDirectives(_directives);
            _mode = saveMode;
            return directive;
        }
 public XmlContext(SyntaxListPool pool, XmlElementStartTagSyntax start)
 {
     _pool = pool;
     _start = start;
     _content = _pool.Allocate<XmlNodeSyntax>();
 }
示例#20
0
        private void LexDirectiveAndExcludedTrivia(
            bool afterFirstToken,
            bool afterNonWhitespaceOnLine,
            ref SyntaxListBuilder triviaList)
        {
            var directive = this.LexSingleDirective(true, true, afterFirstToken, afterNonWhitespaceOnLine, ref triviaList);

            // also lex excluded stuff            
            var branching = directive as BranchingDirectiveTriviaSyntax;
            if (branching != null && !branching.BranchTaken)
            {
                this.LexExcludedDirectivesAndTrivia(true, ref triviaList);
            }
        }
示例#21
0
        /// <summary>
        /// Collects whitespace and new line trivia for XML doc comments. Does not see XML doc comment exterior trivia, and is a no op unless we are in the interior.
        /// </summary>
        /// <param name="trivia">List in which to collect the trivia</param>
        private void LexXmlWhitespaceAndNewLineTrivia(ref SyntaxListBuilder trivia)
        {
            this.Start();
            if (this.LocationIs(XmlDocCommentLocation.Interior))
            {
                char ch = TextWindow.PeekChar();
                switch (ch)
                {
                    case ' ':
                    case '\t':       // Horizontal tab
                    case '\v':       // Vertical Tab
                    case '\f':       // Form-feed
                        this.AddTrivia(this.ScanWhitespace(), ref trivia);
                        break;

                    case '\r':
                    case '\n':
                        this.AddTrivia(this.ScanEndOfLine(), ref trivia);
                        this.MutateLocation(XmlDocCommentLocation.Exterior);
                        return;

                    case '*':
                        if (this.StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
                        {
                            // we're at the end of the comment, but don't add as trivia here.
                            return;
                        }

                        goto default;

                    default:
                        if (SyntaxFacts.IsWhitespace(ch))
                        {
                            goto case ' ';
                        }

                        if (SyntaxFacts.IsNewLine(ch))
                        {
                            goto case '\n';
                        }

                        return;
                }
            }
        }
示例#22
0
        private static TryParseResult TryParseAttribute(
            string tagName,
            MarkupAttributeBlockSyntax attributeBlock,
            IEnumerable <TagHelperDescriptor> descriptors,
            ErrorSink errorSink,
            HashSet <string> processedBoundAttributeNames)
        {
            // Have a name now. Able to determine correct isBoundNonStringAttribute value.
            var result = CreateTryParseResult(attributeBlock.Name.GetContent(), descriptors, processedBoundAttributeNames);

            if (attributeBlock.ValuePrefix == null)
            {
                // We are purposefully not persisting NoQuotes even for unbound attributes because it is still possible to
                // rewrite the values that introduces a space like in UrlResolutionTagHelper.
                // The other case is it could be an expression, treat NoQuotes and DoubleQuotes equivalently. We purposefully do not persist NoQuotes
                // ValueStyles at code generation time to protect users from rendering dynamic content with spaces
                // that can break attributes.
                // Ex: <tag my-attribute=@value /> where @value results in the test "hello world".
                // This way, the above code would render <tag my-attribute="hello world" />.
                result.AttributeStructure = AttributeStructure.DoubleQuotes;
            }
            else
            {
                var lastToken = attributeBlock.ValuePrefix.GetLastToken();
                switch (lastToken.Kind)
                {
                case SyntaxKind.DoubleQuote:
                    result.AttributeStructure = AttributeStructure.DoubleQuotes;
                    break;

                case SyntaxKind.SingleQuote:
                    result.AttributeStructure = AttributeStructure.SingleQuotes;
                    break;

                default:
                    result.AttributeStructure = AttributeStructure.Minimized;
                    break;
                }
            }

            var attributeValue = attributeBlock.Value;

            if (attributeValue == null)
            {
                var builder = SyntaxListBuilder <RazorSyntaxNode> .Create();

                // Add a marker for attribute value when there are no quotes like, <p class= >
                builder.Add(SyntaxFactory.MarkupTextLiteral(new SyntaxList <SyntaxToken>()));

                attributeValue = SyntaxFactory.GenericBlock(builder.ToList());
            }
            var rewrittenValue = RewriteAttributeValue(result, attributeValue);

            var rewritten = SyntaxFactory.MarkupTagHelperAttribute(
                attributeBlock.NamePrefix,
                attributeBlock.Name,
                attributeBlock.NameSuffix,
                attributeBlock.EqualsToken,
                attributeBlock.ValuePrefix,
                rewrittenValue,
                attributeBlock.ValueSuffix);

            rewritten = rewritten.WithTagHelperAttributeInfo(
                new TagHelperAttributeInfo(result.AttributeName, result.AttributeStructure, result.IsBoundAttribute));

            result.RewrittenAttribute = rewritten;

            return(result);
        }
示例#23
0
    private static SyntaxNode CreateNode(IEnumerable <TNode> nodes)
    {
        if (nodes == null)
        {
            return(null);
        }

        var builder = (nodes is ICollection <TNode> collection) ? new SyntaxListBuilder <TNode>(collection.Count) : SyntaxListBuilder <TNode> .Create();

        foreach (var node in nodes)
        {
            builder.Add(node);
        }

        return(builder.ToList().Node);
    }
示例#24
0
        /// <summary>
        /// Collects XML doc comment exterior trivia, and therefore is a no op unless we are in the Start or Exterior of an XML doc comment.
        /// </summary>
        /// <param name="trivia">List in which to collect the trivia</param>
        private void LexXmlDocCommentLeadingTrivia(ref SyntaxListBuilder trivia)
        {
            var start = TextWindow.Position;
            this.Start();

            if (this.LocationIs(XmlDocCommentLocation.Start) && this.StyleIs(XmlDocCommentStyle.Delimited))
            {
                // Read the /** that begins an XML doc comment. Since these are recognized only
                // when the trailing character is not a '*', we wind up in the interior of the
                // doc comment at the end.

                if (TextWindow.PeekChar() == '/'
                    && TextWindow.PeekChar(1) == '*'
                    && TextWindow.PeekChar(2) == '*'
                    && TextWindow.PeekChar(3) != '*')
                {
                    TextWindow.AdvanceChar(3);
                    var text = TextWindow.GetText(true);
                    this.AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text), ref trivia);
                    this.MutateLocation(XmlDocCommentLocation.Interior);
                    return;
                }
            }
            else if (this.LocationIs(XmlDocCommentLocation.Start) || this.LocationIs(XmlDocCommentLocation.Exterior))
            {
                // We're in the exterior of an XML doc comment and need to eat the beginnings of
                // lines, for single line and delimited comments. We chew up white space until
                // a non-whitespace character, and then make the right decision depending on
                // what kind of comment we're in.

                while (true)
                {
                    char ch = TextWindow.PeekChar();
                    switch (ch)
                    {
                        case ' ':
                        case '\t':
                        case '\v':
                        case '\f':
                            TextWindow.AdvanceChar();
                            break;

                        case '/':
                            if (this.StyleIs(XmlDocCommentStyle.SingleLine) && TextWindow.PeekChar(1) == '/' && TextWindow.PeekChar(2) == '/' && TextWindow.PeekChar(3) != '/')
                            {
                                TextWindow.AdvanceChar(3);
                                var text = TextWindow.GetText(true);
                                this.AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text), ref trivia);
                                this.MutateLocation(XmlDocCommentLocation.Interior);
                                return;
                            }

                            goto default;

                        case '*':
                            if (this.StyleIs(XmlDocCommentStyle.Delimited))
                            {
                                while (TextWindow.PeekChar() == '*' && TextWindow.PeekChar(1) != '/')
                                {
                                    TextWindow.AdvanceChar();
                                }

                                var text = TextWindow.GetText(true);
                                if (!String.IsNullOrEmpty(text))
                                {
                                    this.AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text), ref trivia);
                                }

                                // This setup ensures that on the final line of a comment, if we have
                                // the string "  */", the "*/" part is separated from the whitespace
                                // and therefore recognizable as the end of the comment.

                                if (TextWindow.PeekChar() == '*' && TextWindow.PeekChar(1) == '/')
                                {
                                    TextWindow.AdvanceChar(2);
                                    this.AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia("*/"), ref trivia);
                                    this.MutateLocation(XmlDocCommentLocation.End);
                                }
                                else
                                {
                                    this.MutateLocation(XmlDocCommentLocation.Interior);
                                }

                                return;
                            }

                            goto default;

                        default:
                            if (SyntaxFacts.IsWhitespace(ch))
                            {
                                goto case ' ';
                            }

                            // so here we have something else. if this is a single-line xml
                            // doc comment, that means we're on a line that's no longer a doc
                            // comment, so we need to rewind. if we're in a delimited doc comment,
                            // then that means we hit pay dirt and we're back into xml text.

                            if (this.StyleIs(XmlDocCommentStyle.SingleLine))
                            {
                                TextWindow.Reset(start);
                                this.MutateLocation(XmlDocCommentLocation.End);
                            }
                            else // XmlDocCommentStyle.Delimited
                            {
                                Debug.Assert(this.StyleIs(XmlDocCommentStyle.Delimited));

                                var text = TextWindow.GetText(true);
                                if (!String.IsNullOrEmpty(text))
                                    this.AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text), ref trivia);
                                this.MutateLocation(XmlDocCommentLocation.Interior);
                            }

                            return;
                    }
                }
            }
            else if (!this.LocationIs(XmlDocCommentLocation.End) && this.StyleIs(XmlDocCommentStyle.Delimited))
            {
                if (TextWindow.PeekChar() == '*' && TextWindow.PeekChar(1) == '/')
                {
                    TextWindow.AdvanceChar(2);
                    var text = TextWindow.GetText(true);
                    this.AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text), ref trivia);
                    this.MutateLocation(XmlDocCommentLocation.End);
                }
            }
        }
示例#25
0
            public override SyntaxNode VisitMarkupElement(MarkupElementSyntax node)
            {
                if (IsPartOfStartTag(node))
                {
                    // If this element is inside a start tag, it is some sort of malformed case like
                    // <p @do { someattribute=\"btn\"></p>, where the end "p" tag is inside the start "p" tag.
                    // We don't want to do tag helper parsing for this tag.
                    return(base.VisitMarkupElement(node));
                }

                MarkupTagHelperStartTagSyntax tagHelperStart = null;
                MarkupTagHelperEndTagSyntax   tagHelperEnd   = null;
                TagHelperInfo tagHelperInfo = null;

                // Visit the start tag.
                var startTag = (MarkupStartTagSyntax)Visit(node.StartTag);

                if (startTag != null)
                {
                    var tagName = startTag.GetTagNameWithOptionalBang();
                    if (TryRewriteTagHelperStart(startTag, node.EndTag, out tagHelperStart, out tagHelperInfo))
                    {
                        // This is a tag helper.
                        if (tagHelperInfo.TagMode == TagMode.SelfClosing || tagHelperInfo.TagMode == TagMode.StartTagOnly)
                        {
                            var tagHelperElement   = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body: new SyntaxList <RazorSyntaxNode>(), endTag: null);
                            var rewrittenTagHelper = tagHelperElement.WithTagHelperInfo(tagHelperInfo);
                            if (node.Body.Count == 0 && node.EndTag == null)
                            {
                                return(rewrittenTagHelper);
                            }

                            // This tag contains a body and/or an end tag which needs to be moved to the parent.
                            var rewrittenNodes = SyntaxListBuilder <RazorSyntaxNode> .Create();

                            rewrittenNodes.Add(rewrittenTagHelper);
                            var rewrittenBody = VisitList(node.Body);
                            rewrittenNodes.AddRange(rewrittenBody);

                            return(SyntaxFactory.MarkupElement(startTag: null, body: rewrittenNodes.ToList(), endTag: node.EndTag));
                        }
                        else if (node.EndTag == null)
                        {
                            // Start tag helper with no corresponding end tag.
                            _errorSink.OnError(
                                RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper(
                                    new SourceSpan(SourceLocationTracker.Advance(startTag.GetSourceLocation(_source), "<"), tagName.Length),
                                    tagName));
                        }
                        else
                        {
                            // Tag helper start tag. Keep track.
                            var tracker = new TagHelperTracker(_tagHelperPrefix, tagHelperInfo);
                            _trackerStack.Push(tracker);
                        }
                    }
                    else
                    {
                        // Non-TagHelper tag.
                        ValidateParentAllowsPlainStartTag(startTag);

                        if (node.EndTag != null || (!startTag.IsSelfClosing() && !startTag.IsVoidElement()))
                        {
                            // Ideally we don't want to keep track of self-closing or void tags.
                            // But if a matching end tag exists, keep track of the start tag no matter what.
                            // We will just assume the parser had a good reason to do this.
                            var tracker = new TagTracker(tagName, isTagHelper: false);
                            _trackerStack.Push(tracker);
                        }
                    }
                }

                // Visit body between start and end tags.
                var body = VisitList(node.Body);

                // Visit end tag.
                var endTag = (MarkupEndTagSyntax)Visit(node.EndTag);

                if (endTag != null)
                {
                    var tagName = endTag.GetTagNameWithOptionalBang();
                    if (TryRewriteTagHelperEnd(startTag, endTag, out tagHelperEnd))
                    {
                        // This is a tag helper
                        if (startTag == null)
                        {
                            // The end tag helper has no corresponding start tag, create an error.
                            _errorSink.OnError(
                                RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper(
                                    new SourceSpan(SourceLocationTracker.Advance(endTag.GetSourceLocation(_source), "</"), tagName.Length), tagName));
                        }
                    }
                    else
                    {
                        // Non tag helper end tag.
                        if (startTag == null)
                        {
                            // Standalone end tag. We may need to error if it is not supposed to be here.
                            // If there was a corresponding start tag, we would have already added this error.
                            ValidateParentAllowsPlainEndTag(endTag);
                        }
                        else
                        {
                            // Since a start tag exists, we must already be tracking it.
                            // Pop the stack as we're done with the end tag.
                            _trackerStack.Pop();
                        }
                    }
                }

                if (tagHelperInfo != null)
                {
                    // If we get here it means this element was rewritten as a tag helper.
                    var tagHelperElement = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body, tagHelperEnd);
                    return(tagHelperElement.WithTagHelperInfo(tagHelperInfo));
                }

                // There was no matching tag helper for this element. Return.
                return(node.Update(startTag, body, endTag));
            }
 private static bool IsSingleSpaceTrivia(SyntaxListBuilder syntax)
 {
     return syntax.Count == 1 && SyntaxFactory.Space.IsEquivalentTo(syntax[0]);
 }
示例#27
0
 private static bool IsSingleSpaceTrivia(SyntaxListBuilder syntax)
 {
     return(syntax.Count == 1 && SyntaxFactory.Space.IsEquivalentTo(syntax[0]));
 }
        internal static CSharpSyntaxNode List(SyntaxListBuilder builder)
        {
            if (builder != null)
            {
                return builder.ToListNode();
            }

            return null;
        }
示例#29
0
    private SyntaxList <RazorSyntaxNode> GetLegacyChildren()
    {
        // This method returns the children of this start tag in legacy format.
        // This is needed to generate the same classified spans as the legacy syntax tree.
        var builder = new SyntaxListBuilder(5);
        var tokens  = SyntaxListBuilder <SyntaxToken> .Create();

        var context = this.GetSpanContext();

        // We want to know if this tag contains non-whitespace attribute content to set the appropriate AcceptedCharacters.
        // The prefix of a start tag(E.g '|<foo| attr>') will have 'Any' accepted characters if non-whitespace attribute content exists.
        var acceptsAnyContext = new SpanContext(context.ChunkGenerator, SpanEditHandler.CreateDefault());

        acceptsAnyContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
        var containsAttributesContent = false;

        foreach (var attribute in Attributes)
        {
            if (!string.IsNullOrWhiteSpace(attribute.GetContent()))
            {
                containsAttributesContent = true;
                break;
            }
        }

        if (!OpenAngle.IsMissing)
        {
            tokens.Add(OpenAngle);
        }
        if (Bang != null)
        {
            builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(acceptsAnyContext));

            tokens.Add(Bang);
            var acceptsNoneContext = new SpanContext(context.ChunkGenerator, SpanEditHandler.CreateDefault());
            acceptsNoneContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
            builder.Add(SyntaxFactory.RazorMetaCode(tokens.Consume()).WithSpanContext(acceptsNoneContext));
        }
        if (!Name.IsMissing)
        {
            tokens.Add(Name);
        }

        builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(containsAttributesContent ? acceptsAnyContext : context));

        builder.AddRange(Attributes);

        if (ForwardSlash != null)
        {
            tokens.Add(ForwardSlash);
        }
        if (!CloseAngle.IsMissing)
        {
            tokens.Add(CloseAngle);
        }

        if (tokens.Count > 0)
        {
            builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(context));
        }

        return(new SyntaxList <RazorSyntaxNode>(builder.ToListNode().CreateRed(this, Position)));
    }
示例#30
0
        private void LexXmlDocCommentLeadingTriviaWithWhitespace(ref SyntaxListBuilder trivia)
        {
            while (true)
            {
                this.LexXmlDocCommentLeadingTrivia(ref trivia);

                char ch = TextWindow.PeekChar();
                if (this.LocationIs(XmlDocCommentLocation.Interior)
                    && (SyntaxFacts.IsWhitespace(ch) || SyntaxFacts.IsNewLine(ch)))
                {
                    this.LexXmlWhitespaceAndNewLineTrivia(ref trivia);
                }
                else
                {
                    break;
                }
            }
        }
示例#31
0
        private void LexSyntaxTrivia(bool afterFirstToken, bool isTrailing, ref SyntaxListBuilder triviaList)
        {
            bool onlyWhitespaceOnLine = !isTrailing;

            while (true)
            {
                this.Start();
                char ch = TextWindow.PeekChar();
                if (ch == ' ')
                {
                    this.AddTrivia(this.ScanWhitespace(), ref triviaList);
                    continue;
                }
                else if (ch > 127)
                {
                    if (SyntaxFacts.IsWhitespace(ch))
                    {
                        ch = ' ';
                    }
                    else if (SyntaxFacts.IsNewLine(ch))
                    {
                        ch = '\n';
                    }
                }

                switch (ch)
                {
                    case ' ':
                    case '\t':       // Horizontal tab
                    case '\v':       // Vertical Tab
                    case '\f':       // Form-feed
                    case '\u001A':
                        this.AddTrivia(this.ScanWhitespace(), ref triviaList);
                        break;
                    case '/':
                        if ((ch = TextWindow.PeekChar(1)) == '/')
                        {
                            if (!this.SuppressDocumentationCommentParse && TextWindow.PeekChar(2) == '/' && TextWindow.PeekChar(3) != '/')
                            {
                                // Doc comments should never be in trailing trivia.
                                // Stop processing so that it will be leading trivia on the next token.
                                if (isTrailing)
                                {
                                    return;
                                }

                                this.AddTrivia(this.LexXmlDocComment(XmlDocCommentStyle.SingleLine), ref triviaList);
                                break;
                            }

                            // normal single line comment
                            this.ScanToEndOfLine();
                            var text = TextWindow.GetText(false);
                            this.AddTrivia(SyntaxFactory.Comment(text), ref triviaList);
                            onlyWhitespaceOnLine = false;
                            break;
                        }
                        else if (ch == '*')
                        {
                            if (!this.SuppressDocumentationCommentParse && TextWindow.PeekChar(2) == '*' &&
                                TextWindow.PeekChar(3) != '*' && TextWindow.PeekChar(3) != '/')
                            {
                                // Doc comments should never be in trailing trivia.
                                // Stop processing so that it will be leading trivia on the next token.
                                if (isTrailing)
                                {
                                    return;
                                }

                                this.AddTrivia(this.LexXmlDocComment(XmlDocCommentStyle.Delimited), ref triviaList);
                                break;
                            }

                            bool isTerminated;
                            this.ScanMultiLineComment(out isTerminated);
                            if (!isTerminated)
                            {
                                // The comment didn't end.  Report an error at the start point.
                                this.AddError(ErrorCode.ERR_OpenEndedComment);
                            }

                            var text = TextWindow.GetText(false);
                            this.AddTrivia(SyntaxFactory.Comment(text), ref triviaList);
                            onlyWhitespaceOnLine = false;
                            break;
                        }

                        // not trivia
                        return;
                    case '\r':
                    case '\n':
                        this.AddTrivia(this.ScanEndOfLine(), ref triviaList);
                        if (isTrailing)
                        {
                            return;
                        }

                        onlyWhitespaceOnLine = true;
                        break;
                    case '#':
                        if (_allowPreprocessorDirectives)
                        {
                            this.LexDirectiveAndExcludedTrivia(afterFirstToken, isTrailing || !onlyWhitespaceOnLine, ref triviaList);
                            break;
                        }
                        else
                        {
                            return;
                        }
                    default:
                        return;
                }
            }
        }
        /*  <summary>
         ''' Add all the tokens in this node and children to the build token list builder. While doing this, add any
         ''' diagnostics not on tokens to the given diagnostic info list.
         ''' </summary>
        */
        internal virtual void CollectConstituentTokensAndDiagnostics(SyntaxListBuilder<SyntaxToken> tokenListBuilder, IList<DiagnosticInfo> nonTokenDiagnostics)
        {
            DiagnosticInfo[] diagnostics = this.GetDiagnostics();
            if (diagnostics != null && diagnostics.Length > 0)
            {
                foreach (var diag in diagnostics)
                {
                    nonTokenDiagnostics.Add(diag);
                }
            }

            // Recurse to subtrees.
            for (var i = 0; i < SlotCount; i++)
            {
                var green = GetSlot(i);
                if (green != null)
                {
                    ((SyntaxNode)green).CollectConstituentTokensAndDiagnostics(tokenListBuilder, nonTokenDiagnostics);
                }
            }
        }
示例#33
0
        private void AddTrivia(CSharpSyntaxNode trivia, ref SyntaxListBuilder list)
        {
            if (this.HasErrors)
            {
                trivia = trivia.WithDiagnosticsGreen(this.GetErrors(leadingTriviaWidth: 0));
            }

            if (list == null)
            {
                list = new SyntaxListBuilder(TriviaListInitialCapacity);
            }

            list.Add(trivia);
        }
示例#34
0
        private static SyntaxList <RazorSyntaxNode> GetRewrittenChildren(
            string tagName,
            bool validStructure,
            MarkupTagBlockSyntax tagBlock,
            TagHelperBinding bindingResult,
            RazorParserFeatureFlags featureFlags,
            ErrorSink errorSink,
            RazorSourceDocument source)
        {
            var tagHelperBuilder = SyntaxListBuilder <RazorSyntaxNode> .Create();

            var processedBoundAttributeNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            if (tagBlock.Children.Count == 1)
            {
                // Tag with no attributes. We have nothing to rewrite here.
                return(tagBlock.Children);
            }

            // Add the tag start
            tagHelperBuilder.Add(tagBlock.Children.First());

            // We skip the first child "<tagname" and take everything up to the ending portion of the tag ">" or "/>".
            // If the tag does not have a valid structure then there's no close angle to ignore.
            var tokenOffset = validStructure ? 1 : 0;

            for (var i = 1; i < tagBlock.Children.Count - tokenOffset; i++)
            {
                var            isMinimized           = false;
                var            attributeNameLocation = SourceLocation.Undefined;
                var            child = tagBlock.Children[i];
                TryParseResult result;
                if (child is MarkupAttributeBlockSyntax attributeBlock)
                {
                    attributeNameLocation = attributeBlock.Name.GetSourceLocation(source);
                    result = TryParseAttribute(
                        tagName,
                        attributeBlock,
                        bindingResult.Descriptors,
                        errorSink,
                        processedBoundAttributeNames);
                    tagHelperBuilder.Add(result.RewrittenAttribute);
                }
                else if (child is MarkupMinimizedAttributeBlockSyntax minimizedAttributeBlock)
                {
                    isMinimized           = true;
                    attributeNameLocation = minimizedAttributeBlock.Name.GetSourceLocation(source);
                    result = TryParseMinimizedAttribute(
                        tagName,
                        minimizedAttributeBlock,
                        bindingResult.Descriptors,
                        errorSink,
                        processedBoundAttributeNames);
                    tagHelperBuilder.Add(result.RewrittenAttribute);
                }
                else if (child is CSharpCodeBlockSyntax)
                {
                    // TODO: Accept more than just Markup attributes: https://github.com/aspnet/Razor/issues/96.
                    // Something like:
                    // <input @checked />
                    var location   = new SourceSpan(child.GetSourceLocation(source), child.FullWidth);
                    var diagnostic = RazorDiagnosticFactory.CreateParsing_TagHelpersCannotHaveCSharpInTagDeclaration(location, tagName);
                    errorSink.OnError(diagnostic);

                    result = null;
                }
                else if (child is MarkupTextLiteralSyntax)
                {
                    // If the original span content was whitespace it ultimately means the tag
                    // that owns this "attribute" is malformed and is expecting a user to type a new attribute.
                    // ex: <myTH class="btn"| |
                    var literalContent = child.GetContent();
                    if (!string.IsNullOrWhiteSpace(literalContent))
                    {
                        var location   = child.GetSourceSpan(source);
                        var diagnostic = RazorDiagnosticFactory.CreateParsing_TagHelperAttributeListMustBeWellFormed(location);
                        errorSink.OnError(diagnostic);
                    }
                    result = null;
                }
                else
                {
                    result = null;
                }

                // Only want to track the attribute if we succeeded in parsing its corresponding Block/Span.
                if (result == null)
                {
                    // Error occurred while parsing the attribute. Don't try parsing the rest to avoid misleading errors.
                    for (var j = i; j < tagBlock.Children.Count; j++)
                    {
                        tagHelperBuilder.Add(tagBlock.Children[j]);
                    }

                    return(tagHelperBuilder.ToList());
                }

                // Check if it's a non-boolean bound attribute that is minimized or if it's a bound
                // non-string attribute that has null or whitespace content.
                var isValidMinimizedAttribute = featureFlags.AllowMinimizedBooleanTagHelperAttributes && result.IsBoundBooleanAttribute;
                if ((isMinimized &&
                     result.IsBoundAttribute &&
                     !isValidMinimizedAttribute) ||
                    (!isMinimized &&
                     result.IsBoundNonStringAttribute &&
                     string.IsNullOrWhiteSpace(GetAttributeValueContent(result.RewrittenAttribute))))
                {
                    var errorLocation    = new SourceSpan(attributeNameLocation, result.AttributeName.Length);
                    var propertyTypeName = GetPropertyType(result.AttributeName, bindingResult.Descriptors);
                    var diagnostic       = RazorDiagnosticFactory.CreateTagHelper_EmptyBoundAttribute(errorLocation, result.AttributeName, tagName, propertyTypeName);
                    errorSink.OnError(diagnostic);
                }

                // Check if the attribute was a prefix match for a tag helper dictionary property but the
                // dictionary key would be the empty string.
                if (result.IsMissingDictionaryKey)
                {
                    var errorLocation = new SourceSpan(attributeNameLocation, result.AttributeName.Length);
                    var diagnostic    = RazorDiagnosticFactory.CreateParsing_TagHelperIndexerAttributeNameMustIncludeKey(errorLocation, result.AttributeName, tagName);
                    errorSink.OnError(diagnostic);
                }
            }

            if (validStructure)
            {
                // Add the tag end.
                tagHelperBuilder.Add(tagBlock.Children[tagBlock.Children.Count - 1]);
            }

            return(tagHelperBuilder.ToList());
        }
示例#35
0
    internal PooledResult <TNode> Allocate <TNode>() where TNode : GreenNode
    {
        var builder = new SyntaxListBuilder <TNode>(this.Allocate());

        return(new PooledResult <TNode>(this, builder));
    }
示例#36
0
        public static MarkupTagHelperStartTagSyntax Rewrite(
            string tagName,
            RazorParserFeatureFlags featureFlags,
            MarkupStartTagSyntax startTag,
            TagHelperBinding bindingResult,
            ErrorSink errorSink,
            RazorSourceDocument source)
        {
            var processedBoundAttributeNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            var attributes       = startTag.Attributes;
            var attributeBuilder = SyntaxListBuilder <RazorSyntaxNode> .Create();

            for (var i = 0; i < startTag.Attributes.Count; i++)
            {
                var            isMinimized           = false;
                var            attributeNameLocation = SourceLocation.Undefined;
                var            child = startTag.Attributes[i];
                TryParseResult result;
                if (child is MarkupAttributeBlockSyntax attributeBlock)
                {
                    attributeNameLocation = attributeBlock.Name.GetSourceLocation(source);
                    result = TryParseAttribute(
                        tagName,
                        attributeBlock,
                        bindingResult.Descriptors,
                        errorSink,
                        processedBoundAttributeNames);
                    attributeBuilder.Add(result.RewrittenAttribute);
                }
                else if (child is MarkupMinimizedAttributeBlockSyntax minimizedAttributeBlock)
                {
                    isMinimized           = true;
                    attributeNameLocation = minimizedAttributeBlock.Name.GetSourceLocation(source);
                    result = TryParseMinimizedAttribute(
                        tagName,
                        minimizedAttributeBlock,
                        bindingResult.Descriptors,
                        errorSink,
                        processedBoundAttributeNames);
                    attributeBuilder.Add(result.RewrittenAttribute);
                }
                else if (child is MarkupMiscAttributeContentSyntax miscContent)
                {
                    foreach (var contentChild in miscContent.Children)
                    {
                        if (contentChild is CSharpCodeBlockSyntax codeBlock)
                        {
                            // TODO: Accept more than just Markup attributes: https://github.com/aspnet/Razor/issues/96.
                            // Something like:
                            // <input @checked />
                            var location   = new SourceSpan(codeBlock.GetSourceLocation(source), codeBlock.FullWidth);
                            var diagnostic = RazorDiagnosticFactory.CreateParsing_TagHelpersCannotHaveCSharpInTagDeclaration(location, tagName);
                            errorSink.OnError(diagnostic);
                            break;
                        }
                        else
                        {
                            // If the original span content was whitespace it ultimately means the tag
                            // that owns this "attribute" is malformed and is expecting a user to type a new attribute.
                            // ex: <myTH class="btn"| |
                            var literalContent = contentChild.GetContent();
                            if (!string.IsNullOrWhiteSpace(literalContent))
                            {
                                var location   = contentChild.GetSourceSpan(source);
                                var diagnostic = RazorDiagnosticFactory.CreateParsing_TagHelperAttributeListMustBeWellFormed(location);
                                errorSink.OnError(diagnostic);
                                break;
                            }
                        }
                    }

                    result = null;
                }
                else
                {
                    result = null;
                }

                // Only want to track the attribute if we succeeded in parsing its corresponding Block/Span.
                if (result == null)
                {
                    // Error occurred while parsing the attribute. Don't try parsing the rest to avoid misleading errors.
                    for (var j = i; j < startTag.Attributes.Count; j++)
                    {
                        attributeBuilder.Add(startTag.Attributes[j]);
                    }

                    break;
                }

                // Check if it's a non-boolean bound attribute that is minimized or if it's a bound
                // non-string attribute that has null or whitespace content.
                var isValidMinimizedAttribute = featureFlags.AllowMinimizedBooleanTagHelperAttributes && result.IsBoundBooleanAttribute;
                if ((isMinimized &&
                     result.IsBoundAttribute &&
                     !isValidMinimizedAttribute) ||
                    (!isMinimized &&
                     result.IsBoundNonStringAttribute &&
                     string.IsNullOrWhiteSpace(GetAttributeValueContent(result.RewrittenAttribute))))
                {
                    var errorLocation    = new SourceSpan(attributeNameLocation, result.AttributeName.Length);
                    var propertyTypeName = GetPropertyType(result.AttributeName, bindingResult.Descriptors);
                    var diagnostic       = RazorDiagnosticFactory.CreateTagHelper_EmptyBoundAttribute(errorLocation, result.AttributeName, tagName, propertyTypeName);
                    errorSink.OnError(diagnostic);
                }

                // Check if the attribute was a prefix match for a tag helper dictionary property but the
                // dictionary key would be the empty string.
                if (result.IsMissingDictionaryKey)
                {
                    var errorLocation = new SourceSpan(attributeNameLocation, result.AttributeName.Length);
                    var diagnostic    = RazorDiagnosticFactory.CreateParsing_TagHelperIndexerAttributeNameMustIncludeKey(errorLocation, result.AttributeName, tagName);
                    errorSink.OnError(diagnostic);
                }
            }

            if (attributeBuilder.Count > 0)
            {
                // This means we rewrote something. Use the new set of attributes.
                attributes = attributeBuilder.ToList();
            }

            var tagHelperStartTag = SyntaxFactory.MarkupTagHelperStartTag(
                startTag.OpenAngle, startTag.Bang, startTag.Name, attributes, startTag.ForwardSlash, startTag.CloseAngle);

            return(tagHelperStartTag.WithSpanContext(startTag.GetSpanContext()));
        }
 public static SyntaxList <GreenNode> ToList(this SyntaxListBuilder builder)
 {
     return(ToList <GreenNode>(builder));
 }
示例#38
0
 internal SyntaxListBuilder(SyntaxListBuilder builder)
 {
     _builder = builder;
 }
示例#39
0
        private static SyntaxList <RazorSyntaxNode> GetRewrittenMarkupStartTagChildren(MarkupStartTagSyntax node)
        {
            // Rewrites the children of the start tag to look like the legacy syntax tree.
            if (node.IsMarkupTransition)
            {
                var tokens       = node.DescendantNodes().Where(n => n is SyntaxToken token && !token.IsMissing).Cast <SyntaxToken>().ToArray();
                var tokenBuilder = SyntaxListBuilder <SyntaxToken> .Create();

                tokenBuilder.AddRange(tokens, 0, tokens.Length);
                var markupTransition = SyntaxFactory.MarkupTransition(tokenBuilder.ToList()).Green.CreateRed(node, node.Position);
                var spanContext      = node.GetSpanContext();
                if (spanContext != null)
                {
                    markupTransition = markupTransition.WithSpanContext(spanContext);
                }

                var builder = new SyntaxListBuilder(1);
                builder.Add(markupTransition);
                return(new SyntaxList <RazorSyntaxNode>(builder.ToListNode().CreateRed(node, node.Position)));
            }

            SpanContext latestSpanContext = null;
            var         children          = node.Children;
            var         newChildren       = new SyntaxListBuilder(children.Count);
            var         literals          = new List <MarkupTextLiteralSyntax>();

            foreach (var child in children)
            {
                if (child is MarkupTextLiteralSyntax literal)
                {
                    literals.Add(literal);
                    latestSpanContext = literal.GetSpanContext() ?? latestSpanContext;
                }
                else if (child is MarkupMiscAttributeContentSyntax miscContent)
                {
                    foreach (var contentChild in miscContent.Children)
                    {
                        if (contentChild is MarkupTextLiteralSyntax contentLiteral)
                        {
                            literals.Add(contentLiteral);
                            latestSpanContext = contentLiteral.GetSpanContext() ?? latestSpanContext;
                        }
                        else
                        {
                            // Pop stack
                            AddLiteralIfExists();
                            newChildren.Add(contentChild);
                        }
                    }
                }
                else
                {
                    AddLiteralIfExists();
                    newChildren.Add(child);
                }
            }

            AddLiteralIfExists();

            return(new SyntaxList <RazorSyntaxNode>(newChildren.ToListNode().CreateRed(node, node.Position)));

            void AddLiteralIfExists()
            {
                if (literals.Count > 0)
                {
                    var mergedLiteral = SyntaxUtilities.MergeTextLiterals(literals.ToArray());
                    mergedLiteral = mergedLiteral.WithSpanContext(latestSpanContext);
                    literals.Clear();
                    latestSpanContext = null;
                    newChildren.Add(mergedLiteral);
                }
            }
        }
示例#40
0
        private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = false, bool afterLineNumber = false, bool afterReference = false)
        {
            var skippedTokens = new SyntaxListBuilder<SyntaxToken>();

            // Consume all extranous tokens as leading SkippedTokens trivia.
            if (this.CurrentToken.Kind != SyntaxKind.EndOfDirectiveToken &&
                this.CurrentToken.Kind != SyntaxKind.EndOfFileToken)
            {
                skippedTokens = new SyntaxListBuilder<SyntaxToken>(10);

                if (!ignoreErrors)
                {
                    ErrorCode errorCode = ErrorCode.ERR_EndOfPPLineExpected;
                    if (afterPragma)
                    {
                        errorCode = ErrorCode.WRN_EndOfPPLineExpected;
                    }
                    else if (afterLineNumber)
                    {
                        errorCode = ErrorCode.ERR_MissingPPFile;
                    }
                    else if (afterReference)
                    {
                        errorCode = ErrorCode.ERR_ExpectedPPFile;
                    }

                    skippedTokens.Add(this.AddError(this.EatToken().WithoutDiagnosticsGreen(), errorCode));
                }

                while (this.CurrentToken.Kind != SyntaxKind.EndOfDirectiveToken &&
                       this.CurrentToken.Kind != SyntaxKind.EndOfFileToken)
                {
                    skippedTokens.Add(this.EatToken().WithoutDiagnosticsGreen());
                }
            }

            // attach text from extraneous tokens as trivia to EndOfDirective token
            SyntaxToken endOfDirective = this.CurrentToken.Kind == SyntaxKind.EndOfDirectiveToken
                                         ? this.EatToken()
                                         : SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken);

            if (!skippedTokens.IsNull)
            {
                endOfDirective = endOfDirective.WithLeadingTrivia(SyntaxFactory.SkippedTokensTrivia(skippedTokens.ToList()));
            }

            return endOfDirective;
        }
示例#41
0
            private void VisitAttributeValue(SyntaxNode node)
            {
                if (node == null)
                {
                    return;
                }

                IReadOnlyList <SyntaxNode> children = node.ChildNodes();
                var position = node.Position;

                if (children.First() is MarkupBlockSyntax markupBlock &&
                    markupBlock.Children.Count == 2 &&
                    markupBlock.Children[0] is MarkupTextLiteralSyntax &&
                    markupBlock.Children[1] is MarkupEphemeralTextLiteralSyntax)
                {
                    // This is a special case when we have an attribute like attr="@@foo".
                    // In this case, we want the foo to be written out as HtmlContent and not HtmlAttributeValue.
                    Visit(markupBlock);
                    children = children.Skip(1).ToList();
                    position = children.Count > 0 ? children[0].Position : position;
                }

                if (children.All(c => c is MarkupLiteralAttributeValueSyntax))
                {
                    var literalAttributeValueNodes = children.Cast <MarkupLiteralAttributeValueSyntax>().ToArray();
                    var valueTokens = SyntaxListBuilder <SyntaxToken> .Create();

                    for (var i = 0; i < literalAttributeValueNodes.Length; i++)
                    {
                        var mergedValue = MergeAttributeValue(literalAttributeValueNodes[i]);
                        valueTokens.AddRange(mergedValue.LiteralTokens);
                    }
                    var rewritten = SyntaxFactory.MarkupTextLiteral(valueTokens.ToList()).Green.CreateRed(node.Parent, position);
                    Visit(rewritten);
                }
                else if (children.All(c => c is MarkupTextLiteralSyntax))
                {
                    var builder = SyntaxListBuilder <SyntaxToken> .Create();

                    var markupLiteralArray = children.Cast <MarkupTextLiteralSyntax>();
                    foreach (var literal in markupLiteralArray)
                    {
                        builder.AddRange(literal.LiteralTokens);
                    }
                    var rewritten = SyntaxFactory.MarkupTextLiteral(builder.ToList()).Green.CreateRed(node.Parent, position);
                    Visit(rewritten);
                }
                else if (children.All(c => c is CSharpExpressionLiteralSyntax))
                {
                    var builder = SyntaxListBuilder <SyntaxToken> .Create();

                    var         expressionLiteralArray = children.Cast <CSharpExpressionLiteralSyntax>();
                    SpanContext context = null;
                    foreach (var literal in expressionLiteralArray)
                    {
                        context = literal.GetSpanContext();
                        builder.AddRange(literal.LiteralTokens);
                    }
                    var rewritten = SyntaxFactory.CSharpExpressionLiteral(builder.ToList()).Green.CreateRed(node.Parent, position);
                    rewritten = context != null?rewritten.WithSpanContext(context) : rewritten;

                    Visit(rewritten);
                }
                else
                {
                    Visit(node);
                }
            }