All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.SortingErrorManager Maven / Gradle / Ivy

/*
 * Copyright 2018 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.javascript.jscomp;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;

/**
 * A customizable error manager that sorts all errors and warnings reported to it, and has
 * customizable output through the {@link ErrorReportGenerator} interface.
 */
public class SortingErrorManager implements ErrorManager {

  private final TreeSet messages = new TreeSet<>(new LeveledJSErrorComparator());
  private int originalErrorCount = 0;
  private int promotedErrorCount = 0;
  private int warningCount = 0;
  private double typedPercent = 0.0;

  /** Responsible for generating the report of the errors at the end of compilation */
  ImmutableSet errorReportGenerators;

  public SortingErrorManager(Set errorReportGenerators) {
    this.errorReportGenerators = ImmutableSet.copyOf(errorReportGenerators);
  }

  @Override
  public void report(CheckLevel level, JSError error) {
    ErrorWithLevel e = new ErrorWithLevel(error, level);
    if (messages.add(e)) {
      if (level == CheckLevel.ERROR) {
        if (error.getType().level == CheckLevel.ERROR) {
          originalErrorCount++;
        } else {
          promotedErrorCount++;
        }
      } else if (level == CheckLevel.WARNING) {
        warningCount++;
      }
    }
  }

  @Override
  public boolean hasHaltingErrors() {
    return originalErrorCount != 0;
  }

  @Override
  public int getErrorCount() {
    return originalErrorCount + promotedErrorCount;
  }

  @Override
  public int getWarningCount() {
    return warningCount;
  }

  @Override
  public ImmutableList getErrors() {
    return filterToListOf(CheckLevel.ERROR);
  }

  @Override
  public ImmutableList getWarnings() {
    return filterToListOf(CheckLevel.WARNING);
  }

  Iterable getSortedDiagnostics() {
    // TODO(b/114762232): It should be possible to remove the copying here and switch to an
    // unmodifiable collection once we get rid of usages that add warnings during generateReport.
    return ImmutableList.copyOf(messages);
  }

  @Override
  public void setTypedPercent(double typedPercent) {
    this.typedPercent = typedPercent;
  }

  @Override
  public double getTypedPercent() {
    return typedPercent;
  }

  private ImmutableList filterToListOf(CheckLevel level) {
    return messages.stream()
        .filter((e) -> e.level == level)
        .map((e) -> e.error)
        .collect(toImmutableList());
  }

  // TODO(b/114762232): It should be invalid to report errors during the execution of this method;
  // doing so will become impossible once all subclases have migrated to an ErrorReportGenerator.
  @Override
  public void generateReport() {
    for (ErrorReportGenerator generator : this.errorReportGenerators) {
      generator.generateReport(this);
    }
  }

  /** Strategy for customizing the output format of the error report */
  public interface ErrorReportGenerator {
    void generateReport(SortingErrorManager manager);
  }

  /**
   * Comparator of {@link JSError} with an associated {@link CheckLevel}. The ordering is the
   * standard lexical ordering on the quintuple (file name, line number, {@link CheckLevel},
   * character number, description).
   *
   * 

Note: this comparator imposes orderings that are inconsistent with {@link * JSError#equals(Object)}. */ static final class LeveledJSErrorComparator implements Comparator { private static final int P1_LT_P2 = -1; private static final int P1_GT_P2 = 1; @Override public int compare(ErrorWithLevel p1, ErrorWithLevel p2) { // null is the smallest value if (p2 == null) { if (p1 == null) { return 0; } else { return P1_GT_P2; } } // check level if (p1.level != p2.level) { return p2.level.compareTo(p1.level); } // sourceName comparison String source1 = p1.error.getSourceName(); String source2 = p2.error.getSourceName(); if (source1 != null && source2 != null) { int sourceCompare = source1.compareTo(source2); if (sourceCompare != 0) { return sourceCompare; } } else if (source1 == null && source2 != null) { return P1_LT_P2; } else if (source1 != null && source2 == null) { return P1_GT_P2; } // lineno comparison int lineno1 = p1.error.getLineNumber(); int lineno2 = p2.error.getLineNumber(); if (lineno1 != lineno2) { return lineno1 - lineno2; } else if (lineno1 < 0 && 0 <= lineno2) { return P1_LT_P2; } else if (0 <= lineno1 && lineno2 < 0) { return P1_GT_P2; } // charno comparison int charno1 = p1.error.getCharno(); int charno2 = p2.error.getCharno(); if (charno1 != charno2) { return charno1 - charno2; } else if (charno1 < 0 && 0 <= charno2) { return P1_LT_P2; } else if (0 <= charno1 && charno2 < 0) { return P1_GT_P2; } // description return p1.error.getDescription().compareTo(p2.error.getDescription()); } } static class ErrorWithLevel { final JSError error; final CheckLevel level; ErrorWithLevel(JSError error, CheckLevel level) { this.error = error; this.level = level; } @Override public int hashCode() { return Objects.hash( level, error.getDescription(), error.getSourceName(), error.getLineNumber(), error.getCharno()); } @Override public boolean equals(Object obj) { if (!(obj instanceof ErrorWithLevel)) { return false; } ErrorWithLevel e = (ErrorWithLevel) obj; return Objects.equals(level, e.level) && Objects.equals(error.getDescription(), e.error.getDescription()) && Objects.equals(error.getSourceName(), e.error.getSourceName()) && error.getLineNumber() == e.error.getLineNumber() && error.getCharno() == e.error.getCharno(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy