private bool TryRewriteTagHelper(Block tagBlock, RewritingContext context)
        {
            // TODO: Fully handle malformed tags: https://github.com/aspnet/Razor/issues/104

            // Get tag name of the current block (doesn't matter if it's an end or start tag)
            var tagName = GetTagName(tagBlock);

            // Could not determine tag name, it can't be a TagHelper, continue on and track the element.
            if (tagName == null)
            {
                return(false);
            }

            var descriptors = Enumerable.Empty <TagHelperDescriptor>();

            if (IsPotentialTagHelper(tagName, tagBlock))
            {
                descriptors = _provider.GetTagHelpers(tagName);
            }

            // If there aren't any TagHelperDescriptors registered then we aren't a TagHelper
            if (!descriptors.Any())
            {
                return(false);
            }

            if (!IsEndTag(tagBlock))
            {
                // We're in a begin tag helper block

                var validTagStructure = ValidTagStructure(tagName, tagBlock, context);

                var builder = TagHelperBlockRewriter.Rewrite(tagName,
                                                             validTagStructure,
                                                             tagBlock,
                                                             descriptors,
                                                             context.ErrorSink);

                // Found a new tag helper block
                TrackTagHelperBlock(builder);

                // If it's a self closing block then we don't have to worry about nested children
                // within the tag... complete it.
                if (IsSelfClosing(tagBlock))
                {
                    BuildCurrentlyTrackedTagHelperBlock();
                }
            }
            else
            {
                // We're in an end tag helper block.

                var tagNameScope = _tagStack.Count > 0 ? _tagStack.Peek().TagName : string.Empty;

                // Validate that our end tag helper matches the currently scoped tag helper, if not we
                // need to error.
                if (tagNameScope.Equals(tagName, StringComparison.OrdinalIgnoreCase))
                {
                    ValidTagStructure(tagName, tagBlock, context);

                    BuildCurrentlyTrackedTagHelperBlock();
                }
                else
                {
                    // Current tag helper scope does not match the end tag. Attempt to recover the tag
                    // helper by looking up the previous tag helper scopes for a matching tag. If we
                    // can't recover it means there was no corresponding tag helper begin tag.
                    if (TryRecoverTagHelper(tagName, context))
                    {
                        ValidTagStructure(tagName, tagBlock, context);

                        // Successfully recovered, move onto the next element.
                    }
                    else
                    {
                        // Could not recover, the end tag helper has no corresponding begin tag, create
                        // an error based on the current childBlock.
                        context.ErrorSink.OnError(
                            tagBlock.Start,
                            RazorResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(tagName));

                        return(false);
                    }
                }
            }

            return(true);
        }
        private bool TryRewriteTagHelper(Block tagBlock, RewritingContext context)
        {
            // Get tag name of the current block (doesn't matter if it's an end or start tag)
            var tagName = GetTagName(tagBlock);

            // Could not determine tag name, it can't be a TagHelper, continue on and track the element.
            if (tagName == null)
            {
                return(false);
            }

            var descriptors = Enumerable.Empty <TagHelperDescriptor>();

            if (!IsPotentialTagHelper(tagName, tagBlock))
            {
                return(false);
            }

            var tracker      = _currentTagHelperTracker;
            var tagNameScope = tracker?.Builder.TagName ?? string.Empty;

            if (!IsEndTag(tagBlock))
            {
                // We're now in a start tag block, we first need to see if the tag block is a tag helper.
                var providedAttributes = GetAttributeNames(tagBlock);

                descriptors = _provider.GetDescriptors(tagName, providedAttributes);


                // If there aren't any TagHelperDescriptors registered then we aren't a TagHelper
                if (!descriptors.Any())
                {
                    // If the current tag matches the current TagHelper scope it means the parent TagHelper matched
                    // all the required attributes but the current one did not; therefore, we need to increment the
                    // OpenMatchingTags counter for current the TagHelperBlock so we don't end it too early.
                    // ex: <myth req="..."><myth></myth></myth> We don't want the first myth to close on the inside
                    // tag.
                    if (string.Equals(tagNameScope, tagName, StringComparison.OrdinalIgnoreCase))
                    {
                        tracker.OpenMatchingTags++;
                    }

                    return(false);
                }

                ValidateParentTagHelperAllowsTagHelper(tagName, tagBlock, context.ErrorSink);
                ValidateDescriptors(descriptors, tagName, tagBlock, context.ErrorSink);

                // We're in a start TagHelper block.
                var validTagStructure = ValidateTagSyntax(tagName, tagBlock, context);

                var builder = TagHelperBlockRewriter.Rewrite(
                    tagName,
                    validTagStructure,
                    tagBlock,
                    descriptors,
                    context.ErrorSink);

                // Track the original start tag so the editor knows where each piece of the TagHelperBlock lies
                // for formatting.
                builder.SourceStartTag = tagBlock;

                // Found a new tag helper block
                TrackTagHelperBlock(builder);

                // If it's a non-content expecting block then we don't have to worry about nested children within the
                // tag. Complete it.
                if (builder.TagMode == TagMode.SelfClosing || builder.TagMode == TagMode.StartTagOnly)
                {
                    BuildCurrentlyTrackedTagHelperBlock(endTag: null);
                }
            }
            else
            {
                // Validate that our end tag matches the currently scoped tag, if not we may need to error.
                if (tagNameScope.Equals(tagName, StringComparison.OrdinalIgnoreCase))
                {
                    // If there are additional end tags required before we can build our block it means we're in a
                    // situation like this: <myth req="..."><myth></myth></myth> where we're at the inside </myth>.
                    if (tracker.OpenMatchingTags > 0)
                    {
                        tracker.OpenMatchingTags--;

                        return(false);
                    }

                    ValidateTagSyntax(tagName, tagBlock, context);

                    BuildCurrentlyTrackedTagHelperBlock(tagBlock);
                }
                else
                {
                    descriptors = _provider.GetDescriptors(tagName, attributeNames: Enumerable.Empty <string>());

                    // If there are not TagHelperDescriptors associated with the end tag block that also have no
                    // required attributes then it means we can't be a TagHelper, bail out.
                    if (!descriptors.Any())
                    {
                        return(false);
                    }

                    var invalidDescriptor = descriptors.FirstOrDefault(
                        descriptor => descriptor.TagStructure == TagStructure.WithoutEndTag);
                    if (invalidDescriptor != null)
                    {
                        // End tag TagHelper that states it shouldn't have an end tag.
                        context.ErrorSink.OnError(
                            tagBlock.Start,
                            RazorResources.FormatTagHelperParseTreeRewriter_EndTagTagHelperMustNotHaveAnEndTag(
                                tagName,
                                invalidDescriptor.TypeName,
                                invalidDescriptor.TagStructure),
                            tagBlock.Length);

                        return(false);
                    }

                    // Current tag helper scope does not match the end tag. Attempt to recover the tag
                    // helper by looking up the previous tag helper scopes for a matching tag. If we
                    // can't recover it means there was no corresponding tag helper start tag.
                    if (TryRecoverTagHelper(tagName, tagBlock, context))
                    {
                        ValidateParentTagHelperAllowsTagHelper(tagName, tagBlock, context.ErrorSink);
                        ValidateTagSyntax(tagName, tagBlock, context);

                        // Successfully recovered, move onto the next element.
                    }
                    else
                    {
                        // Could not recover, the end tag helper has no corresponding start tag, create
                        // an error based on the current childBlock.
                        context.ErrorSink.OnError(
                            tagBlock.Start,
                            RazorResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(tagName));

                        return(false);
                    }
                }
            }

            return(true);
        }