Skip to content

Commit

Permalink
Model types of elements that are missing from the classpath as ERROR …
Browse files Browse the repository at this point in the history
…types

This fixes a bug where if a class file referenced an annotation that wasn't on
the classpath, turbine would model that annotation's type as a non-ERROR type,
and then report a fatal error trying to load the missing class file. This
changes causes it to model the missing type as an ERROR type, preventing it
from incorrectly trying to access additional information about the missing
class.

PiperOrigin-RevId: 586861763
  • Loading branch information
cushon authored and Javac Team committed Dec 1, 2023
1 parent cf3b973 commit 260f1bb
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 2 deletions.
4 changes: 2 additions & 2 deletions java/com/google/turbine/processing/TurbineElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,10 @@ public TypeMirror get() {
return factory.asTypeMirror(asGenericType(sym));
}

ClassTy asGenericType(ClassSymbol symbol) {
Type asGenericType(ClassSymbol symbol) {
TypeBoundClass info = info();
if (info == null) {
return ClassTy.asNonParametricClassTy(symbol);
return ErrorTy.create(getQualifiedName().toString());
}
Deque<Type.ClassTy.SimpleClassTy> simples = new ArrayDeque<>();
simples.addFirst(simple(symbol, info));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,29 @@
import com.google.turbine.binder.ClassPathBinder;
import com.google.turbine.binder.Processing;
import com.google.turbine.binder.Processing.ProcessorInfo;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.diag.TurbineDiagnostic;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineLog;
import com.google.turbine.lower.IntegrationTestSupport;
import com.google.turbine.parse.Parser;
import com.google.turbine.testing.TestClassPaths;
import com.google.turbine.tree.Tree;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
Expand All @@ -62,18 +69,23 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class ProcessingIntegrationTest {

@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();

@SupportedAnnotationTypes("*")
public static class CrashingProcessor extends AbstractProcessor {

Expand Down Expand Up @@ -864,4 +876,74 @@ public void uriProcessing() throws IOException {
.map(d -> d.message()))
.containsExactly("file:///foo/Bar - " + Paths.get(URI.create("file:///foo/Bar")));
}

@SupportedAnnotationTypes("*")
public static class MethodAnnotationTypeKindProcessor extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}

boolean first = true;

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!first) {
return false;
}
first = false;
TypeElement e = processingEnv.getElementUtils().getTypeElement("T");
for (AnnotationMirror a : e.getAnnotationMirrors()) {
DeclaredType t = a.getAnnotationType();
processingEnv
.getMessager()
.printMessage(Diagnostic.Kind.NOTE, t + "(" + t.getKind() + ")", e);
// this shouldn't crash
requireNonNull(a.getAnnotationType().asElement().getEnclosedElements());
}
return false;
}
}

@Test
public void missingAnnotationType() throws IOException {
Map<String, byte[]> library =
IntegrationTestSupport.runTurbine(
ImmutableMap.of(
"A.java", //
"@interface A {}",
"T.java",
"@A class T {}"),
ImmutableList.of());
Path libJar = temporaryFolder.newFile("lib.jar").toPath();
try (OutputStream os = Files.newOutputStream(libJar);
JarOutputStream jos = new JarOutputStream(os)) {
// deliberately exclude the definition of the annotation
jos.putNextEntry(new JarEntry("T.class"));
jos.write(requireNonNull(library.get("T")));
}

ImmutableList<Tree.CompUnit> units =
parseUnit(
"=== Y.java ===", //
"class Y {}");

TurbineLog log = new TurbineLog();
BindingResult bound =
Binder.bind(
log,
units,
ClassPathBinder.bindClasspath(ImmutableList.of(libJar)),
ProcessorInfo.create(
ImmutableList.of(new MethodAnnotationTypeKindProcessor()),
getClass().getClassLoader(),
ImmutableMap.of(),
SourceVersion.latestSupported()),
TestClassPaths.TURBINE_BOOTCLASSPATH,
Optional.empty());
assertThat(bound.units().keySet()).containsExactly(new ClassSymbol("Y"));
ImmutableList<String> messages =
log.diagnostics().stream().map(TurbineDiagnostic::message).collect(toImmutableList());
assertThat(messages).containsExactly("A(ERROR)");
}
}

0 comments on commit 260f1bb

Please sign in to comment.