private boolean run()

in java/com/google/javascript/jscomp/JsChecker.java [140:313]


  private boolean run() throws IOException {
    final JsCheckerState state = new JsCheckerState(label, legacy, testonly, roots, mysterySources);
    final Set<String> actuallySuppressed = new HashSet<>();

    // read provided files created by this program on deps
    for (String dep : deps) {
      state.provided.addAll(
          JsCheckerHelper.loadClosureJsLibraryInfo(Paths.get(dep))
              .getNamespaceList());
    }

    Map<String, String> labels = new HashMap<>();
    labels.put("", label);
    Set<String> modules = new LinkedHashSet<>();
    for (String source : sources) {
      for (String module : convertPathToModuleName(source, state.roots).asSet()) {
        modules.add(module);
        labels.put(module, label);
        state.provides.add(module);
      }
    }

    for (String source : mysterySources) {
      for (String module : convertPathToModuleName(source, state.roots).asSet()) {
        checkArgument(!module.startsWith("blaze-out/"),
            "oh no: %s", state.roots);
        modules.add(module);
        state.provided.add(module);
      }
    }

    // configure compiler
    Compiler compiler = new Compiler();
    CompilerOptions options = new CompilerOptions();
    options.setLanguage(LanguageMode.STABLE);
    options.setStrictModeInput(true);
    options.setIncrementalChecks(IncrementalCheckMode.GENERATE_IJS);
    options.setCodingConvention(convention.convention);
    options.setSkipTranspilationAndCrash(true);
    options.setContinueAfterErrors(true);
    options.setPrettyPrint(true);
    options.setPreserveTypeAnnotations(true);
    options.setPreserveDetailedSourceInfo(true);
    options.setEmitUseStrict(false);
    options.setParseJsDocDocumentation(Config.JsDocParsing.INCLUDE_DESCRIPTIONS_NO_WHITESPACE);
    JsCheckerErrorFormatter errorFormatter =
        new JsCheckerErrorFormatter(compiler, state.roots, labels);
    errorFormatter.setColorize(true);
    JsCheckerErrorManager errorManager = new JsCheckerErrorManager(errorFormatter);
    compiler.setErrorManager(errorManager);

    // configure which error messages appear
    if (!legacy) {
      for (String error
          : Iterables.concat(
              Diagnostics.JSCHECKER_ONLY_ERRORS,
              Diagnostics.JSCHECKER_EXTRA_ERRORS)) {
        options.setWarningLevel(Diagnostics.GROUPS.forName(error), CheckLevel.ERROR);
      }
    }
    final Set<DiagnosticType> suppressions = Sets.newHashSetWithExpectedSize(256);
    for (String code : suppress) {
      ImmutableSet<DiagnosticType> types = Diagnostics.getDiagnosticTypesForSuppressCode(code);
      if (types.isEmpty()) {
        System.err.println("ERROR: Bad --suppress value: " + code);
        return false;
      }
      suppressions.addAll(types);
    }

    options.addWarningsGuard(
        new WarningsGuard() {
          @Override
          public CheckLevel level(JSError error) {
            // TODO(jart): Figure out how to support this.
            if (error.getType().key
                    .equals("JSC_CONSTANT_WITHOUT_EXPLICIT_TYPE")) {
              return CheckLevel.OFF;
            }

            // Closure Rules will always ignore these checks no matter what.
            if (Diagnostics.IGNORE_ALWAYS.contains(error.getType())) {
              return CheckLevel.OFF;
            }

            // Disable warnings specific to conventions other than the one we're using.
            if (!convention.diagnostics.contains(error.getType())) {
              for (JsCheckerConvention conv : JsCheckerConvention.values()) {
                if (!conv.equals(convention)) {
                  if (conv.diagnostics.contains(error.getType())) {
                    suppressions.add(error.getType());
                    return CheckLevel.OFF;
                  }
                }
              }
            }
            // Disable warnings we've suppressed.
            Collection<String> groupNames = Diagnostics.DIAGNOSTIC_GROUPS.get(error.getType());
            if (suppressions.contains(error.getType())) {
              actuallySuppressed.add(error.getType().key);
              actuallySuppressed.addAll(groupNames);
              return CheckLevel.OFF;
            }
            // Ignore linter warnings on generated sources.
            if (groupNames.contains("lintChecks")
                && JsCheckerHelper.isGeneratedPath(error.getSourceName())) {
              return CheckLevel.OFF;
            }
            return null;
          }
        });

    // Run the compiler.
    compiler.setPassConfig(new JsCheckerPassConfig(state, options));
    compiler.disableThreads();
    compiler.compile(
        ImmutableList.<SourceFile>of(),
        getSourceFiles(Iterables.concat(sources, mysterySources)),
        options);

    // In order for suppress to be maintainable, we need to make sure the suppress codes relating to
    // linting were actually suppressed. However we can only offer this safety on the checks over
    // which JsChecker has sole dominion. Other suppress codes won't actually be suppressed until
    // they've been propagated up to the closure_js_binary rule.
    if (!suppress.contains("superfluousSuppress")) {
      Set<String> useless =
          Sets.intersection(
              Sets.difference(ImmutableSet.copyOf(suppress), actuallySuppressed),
              Diagnostics.JSCHECKER_ONLY_SUPPRESS_CODES);
      if (!useless.isEmpty()) {
        errorManager.report(CheckLevel.ERROR,
            JSError.make(Diagnostics.SUPERFLUOUS_SUPPRESS, label, Joiner.on(", ").join(useless)));
      }
    }

    // TODO: Make compiler.compile() package private so we don't have to do this.
    errorManager.stderr.clear();
    errorManager.generateReport();

    // write errors
    if (!expectFailure) {
      for (String line : errorManager.stderr) {
        System.err.println(line);
      }
    }
    if (!outputErrors.isEmpty()) {
      Files.write(Paths.get(outputErrors), errorManager.stderr, UTF_8);
    }

    // write .i.js type summary for this library
    if (!outputIjsFile.isEmpty()) {
      Files.write(Paths.get(outputIjsFile), compiler.toSource().getBytes(UTF_8));
    }

    // write file full of information about these sauces
    if (!output.isEmpty()) {
      ClosureJsLibrary.Builder info =
          ClosureJsLibrary.newBuilder()
              .setLabel(label)
              .setLegacy(legacy)
              .addAllNamespace(state.provides)
              .addAllModule(modules);
      if (!legacy) {
        for (DiagnosticType suppression : suppressions) {
          if (!Diagnostics.JSCHECKER_ONLY_SUPPRESS_CODES.contains(suppression.key)) {
            info.addSuppress(suppression.key);
          }
        }
      }
      Files.write(Paths.get(output), info.build().toString().getBytes(UTF_8));
    }

    return errorManager.getErrorCount() == 0;
  }