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

com.google.testing.compile.Compilation Maven / Gradle / Ivy

There is a newer version: 0.21.0
Show newest version
/*
 * Copyright (C) 2013 Google, Inc.
 *
 * 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.testing.compile;

import static com.google.common.base.Preconditions.checkState;
import static com.google.testing.compile.JavaFileObjects.asByteSource;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static javax.tools.Diagnostic.Kind.ERROR;
import static javax.tools.Diagnostic.Kind.MANDATORY_WARNING;
import static javax.tools.Diagnostic.Kind.NOTE;
import static javax.tools.Diagnostic.Kind.WARNING;
import static javax.tools.JavaFileObject.Kind.CLASS;
import static javax.tools.StandardLocation.SOURCE_OUTPUT;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.util.Optional;
import java.util.stream.Collector;
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;

/** The results of {@linkplain Compiler#compile compiling} source files. */
public final class Compilation {

  private final Compiler compiler;
  private final ImmutableList sourceFiles;
  private final Status status;
  private final ImmutableList> diagnostics;
  private final ImmutableList generatedFiles;

  Compilation(
      Compiler compiler,
      Iterable sourceFiles,
      boolean successful,
      Iterable> diagnostics,
      Iterable generatedFiles) {
    this.compiler = compiler;
    this.sourceFiles = ImmutableList.copyOf(sourceFiles);
    this.status = successful ? Status.SUCCESS : Status.FAILURE;
    this.diagnostics = ImmutableList.copyOf(diagnostics);
    this.generatedFiles = ImmutableList.copyOf(generatedFiles);
  }

  /** The compiler. */
  public Compiler compiler() {
    return compiler;
  }

  /** The source files compiled. */
  public ImmutableList sourceFiles() {
    return sourceFiles;
  }

  /** The status of the compilation. */
  public Status status() {
    return status;
  }

  /**
   * All diagnostics reported during compilation. The order of the returned list is unspecified.
   *
   * @see #errors()
   * @see #warnings()
   * @see #notes()
   */
  public ImmutableList> diagnostics() {
    return diagnostics;
  }

  /** {@linkplain Diagnostic.Kind#ERROR Errors} reported during compilation. */
  public ImmutableList> errors() {
    return diagnosticsOfKind(ERROR);
  }

  /**
   * {@linkplain Diagnostic.Kind#WARNING Warnings} (including {@linkplain
   * Diagnostic.Kind#MANDATORY_WARNING mandatory warnings}) reported during compilation.
   */
  public ImmutableList> warnings() {
    return diagnosticsOfKind(WARNING, MANDATORY_WARNING);
  }

  /** {@linkplain Diagnostic.Kind#NOTE Notes} reported during compilation. */
  public ImmutableList> notes() {
    return diagnosticsOfKind(NOTE);
  }

  ImmutableList> diagnosticsOfKind(Kind kind, Kind... more) {
    ImmutableSet kinds = Sets.immutableEnumSet(kind, more);
    return diagnostics()
        .stream()
        .filter(diagnostic -> kinds.contains(diagnostic.getKind()))
        .collect(toImmutableList());
  }

  /**
   * Files generated during compilation.
   *
   * @throws IllegalStateException for {@linkplain #status() failed compilations}, since the state
   *     of the generated files is undefined in that case
   */
  public ImmutableList generatedFiles() {
    checkState(
        status.equals(Status.SUCCESS),
        "compilation failed, so generated files are unavailable. %s",
        describeFailureDiagnostics());
    return generatedFiles;
  }

  /**
   * Source files generated during compilation.
   *
   * @throws IllegalStateException for {@linkplain #status() failed compilations}, since the state
   *     of the generated files is undefined in that case
   */
  public ImmutableList generatedSourceFiles() {
    return generatedFiles()
        .stream()
        .filter(generatedFile -> generatedFile.getKind().equals(JavaFileObject.Kind.SOURCE))
        .collect(toImmutableList());
  }

  /**
   * Returns the file at {@code path} if one was generated.
   *
   * 

For example: * *

   * {@code Optional} fooClassFile =
   *     compilation.generatedFile(CLASS_OUTPUT, "com/google/myapp/Foo.class");
   * 
* * @throws IllegalStateException for {@linkplain #status() failed compilations}, since the state * of the generated files is undefined in that case */ public Optional generatedFile(Location location, String path) { // We're relying on the implementation of location.getName() to be equivalent to the first // part of the path. String expectedFilename = String.format("%s/%s", location.getName(), path); return generatedFiles() .stream() .filter(generated -> generated.toUri().getPath().endsWith(expectedFilename)) .findFirst(); } /** * Returns the file with name {@code fileName} in package {@code packageName} if one was * generated. * *

For example: * *

   * {@code Optional} fooClassFile =
   *     compilation.generatedFile(CLASS_OUTPUT, "com.google.myapp", "Foo.class");
   * 
* * @throws IllegalStateException for {@linkplain #status() failed compilations}, since the state * of the generated files is undefined in that case */ public Optional generatedFile( Location location, String packageName, String fileName) { return generatedFile( location, packageName.isEmpty() ? fileName : packageName.replace('.', '/') + '/' + fileName); } /** * Returns the source file for the type with a given qualified name (no ".java" extension) if one * was generated. * *

For example: * *

   * {@code Optional} fooSourceFile =
   *     compilation.generatedSourceFile("com.google.myapp.Foo");
   * 
* * @throws IllegalStateException for {@linkplain #status() failed compilations}, since the state * of the generated files is undefined in that case */ public Optional generatedSourceFile(String qualifiedName) { int lastIndexOfDot = qualifiedName.lastIndexOf('.'); String packageName = lastIndexOfDot == -1 ? "" : qualifiedName.substring(0, lastIndexOfDot); String fileName = qualifiedName.substring(lastIndexOfDot + 1) + ".java"; return generatedFile(SOURCE_OUTPUT, packageName, fileName); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder .append("compilation of ") .append(sourceFiles.stream().map(JavaFileObject::getName).collect(toList())); if (!compiler.processors().isEmpty()) { builder.append(" using annotation processors ").append(compiler.processors()); } if (!compiler.options().isEmpty()) { builder.append(" passing options ").append(compiler.options()); } return builder.toString(); } /** Returns a description of the why the compilation failed. */ String describeFailureDiagnostics() { ImmutableList> errors = errors(); if (errors.isEmpty()) { return "Compilation produced no errors.\n"; } StringBuilder message = new StringBuilder("Compilation produced the following errors:\n"); errors.stream().forEach(error -> message.append(error).append('\n')); // If we compiled with -Werror we should output the warnings too if (compiler.options().contains("-Werror")) { warnings().stream().forEach(warning -> message.append(warning).append('\n')); } return message.toString(); } /** Returns a description of the source file generated by this compilation. */ String describeGeneratedSourceFiles() { ImmutableList generatedSourceFiles = generatedFiles .stream() .filter(generatedFile -> generatedFile.getKind().equals(JavaFileObject.Kind.SOURCE)) .collect(toImmutableList()); if (generatedSourceFiles.isEmpty()) { return "No files were generated.\n"; } else { StringBuilder message = new StringBuilder("Generated Source Files\n======================\n"); for (JavaFileObject generatedFile : generatedSourceFiles) { message.append(describeGeneratedFile(generatedFile)); } return message.toString(); } } /** Returns a description of the contents of a given generated file. */ private String describeGeneratedFile(JavaFileObject generatedFile) { try { StringBuilder entry = new StringBuilder("\n").append(generatedFile.getName()).append(":\n"); if (generatedFile.getKind().equals(CLASS)) { entry.append( String.format( " [generated class file (%d bytes)]", asByteSource(generatedFile).size())); } else { entry.append(generatedFile.getCharContent(true)); } return entry.append('\n').toString(); } catch (IOException e) { throw new IllegalStateException( "Couldn't read from JavaFileObject when it was already in memory.", e); } } // TODO(dpb): Use Guava's toImmutableList() once that's available. MOE:strip_line private static Collector> toImmutableList() { return collectingAndThen(toList(), ImmutableList::copyOf); } /** The status of a compilation. */ public enum Status { /** Compilation finished without errors. */ SUCCESS, /** Compilation finished with errors. */ FAILURE, } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy