public void run(HtmlMatcherGraph htmlMatcherGraph) {
    if (!htmlMatcherGraph.getRootNode().isPresent()) {
      // Empty graph.
      return;
    }
    visit(htmlMatcherGraph.getRootNode().get());
    for (HtmlTagNode tag : annotationMap.keySet()) {
      if (tag instanceof HtmlOpenTagNode) {
        HtmlOpenTagNode openTag = (HtmlOpenTagNode) tag;
        if (annotationMap.containsEntry(openTag, INVALID_NODE)) {
          if (annotationMap.get(openTag).size() == 1) {
            errorReporter.report(
                openTag.getSourceLocation(), makeSoyErrorKind(UNEXPECTED_OPEN_TAG_ALWAYS));
          } else {
            errorReporter.report(
                openTag.getSourceLocation(), makeSoyErrorKind(UNEXPECTED_OPEN_TAG_SOMETIMES));
          }
        }
      }
    }
    // Do not annotate in inCondition because if there are errors, the nodes will be annotated
    // in the parent pass. The reason this happens is when the condition node is not balanced
    // internally but balanced globally.
    if (!errorReporter.getErrors().isEmpty() && inCondition) {
      return;
    }
    for (HtmlTagNode openTag : annotationMap.keySet()) {
      for (Optional<HtmlTagNode> closeTag : annotationMap.get(openTag)) {
        if (closeTag.isPresent()) {
          openTag.addTagPair(closeTag.get());
          closeTag.get().addTagPair(openTag);
        }
      }
    }
  }
public void run ( HtmlMatcherGraph htmlMatcherGraph ) { if ( ! htmlMatcherGraph . getRootNode ( ) . isPresent ( ) ) { return ; } visit ( htmlMatcherGraph . getRootNode ( ) . get ( ) ) ; for ( HtmlTagNode tag : annotationMap . keySet ( ) ) { if ( tag instanceof HtmlOpenTagNode ) { HtmlOpenTagNode openTag = ( HtmlOpenTagNode ) tag ; if ( annotationMap . containsEntry ( openTag , INVALID_NODE ) ) { if ( annotationMap . get ( openTag ) . size ( ) == 1 ) { errorReporter . report ( openTag . getSourceLocation ( ) , makeSoyErrorKind ( UNEXPECTED_OPEN_TAG_ALWAYS ) ) ; } else { errorReporter . report ( openTag . getSourceLocation ( ) , makeSoyErrorKind ( UNEXPECTED_OPEN_TAG_SOMETIMES ) ) ; } } } } if ( ! errorReporter . getErrors ( ) . isEmpty ( ) && inCondition ) { return ; } for ( HtmlTagNode openTag : annotationMap . keySet ( ) ) { for ( Optional < HtmlTagNode > closeTag : annotationMap . get ( openTag ) ) { if ( closeTag . isPresent ( ) ) { openTag . addTagPair ( closeTag . get ( ) ) ; closeTag . get ( ) . addTagPair ( openTag ) ; } } } }
Runs the HtmlTagMatchingPass.

<p>The pass does the following:

<ol>
<li>Traverse the HTML matcher graph and create a set of open -> close tag matches
<li>Rebalance the code paths, injecting synthetic close tags to balance optional open tags.
Optional open tags are defined here: <a
href="https://www.w3.org/TR/html5/syntax.html#optional-tags">https://www.w3.org/TR/html5/syntax.html#optional-tags</a>.
<p>&ndash; <em>Note:</em> Block nodes (such as {@code {msg} or {let}}) are discretely
rebalanced, annotated and error-checked. By definition, a block node must internally
balance HTML tags.
<li>Check for tag mismatch errors in the fully balanced code paths.
<p>&ndash; Afterwards, annotate the open with the list of possible close tags, and the
close tags with the list of possible open tags.
</ol>