aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:08:29 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:08:29 +0000
commita38c0ca68ed611ba8b993fd3bab59f9c2ce4c892 (patch)
tree0baa92251e9c2c2d2522d953021138893ae84133
parent9cce82a73df960c5e76ec07b785eb23e2a43b6dc (diff)
parentd4be1f10b831f4c3774091c74e4b904ec6450c9a (diff)
downloadturbine-aml_sta_341615000.tar.gz
Change-Id: Id86cee821f19e3a725aefc406e5eaa4dc641624c
-rw-r--r--.github/workflows/ci.yml8
-rw-r--r--Android.bp6
-rw-r--r--METADATA12
-rw-r--r--java/com/google/turbine/binder/FileManagerClassBinder.java5
-rw-r--r--java/com/google/turbine/bytecode/ByteReader.java2
-rw-r--r--java/com/google/turbine/bytecode/ClassReader.java20
-rw-r--r--java/com/google/turbine/main/Main.java10
-rw-r--r--java/com/google/turbine/options/LanguageVersion.java2
-rw-r--r--java/com/google/turbine/parse/ConstExpressionParser.java6
-rw-r--r--java/com/google/turbine/parse/Parser.java8
-rw-r--r--java/com/google/turbine/parse/StreamLexer.java162
-rw-r--r--java/com/google/turbine/processing/TurbineElements.java2
-rw-r--r--java/com/google/turbine/processing/TurbineFiler.java7
-rw-r--r--java/com/google/turbine/processing/TurbineTypes.java59
-rw-r--r--java/com/google/turbine/type/Type.java21
-rw-r--r--java/com/google/turbine/zip/Zip.java41
-rw-r--r--javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java3
-rw-r--r--javatests/com/google/turbine/deps/TransitiveTest.java3
-rw-r--r--javatests/com/google/turbine/lower/LongStringIntegrationTest.java4
-rw-r--r--javatests/com/google/turbine/lower/LowerIntegrationTest.java8
-rw-r--r--javatests/com/google/turbine/lower/LowerTest.java2
-rw-r--r--javatests/com/google/turbine/lower/testdata/sealed_nested.test7
-rw-r--r--javatests/com/google/turbine/lower/testdata/textblock.test30
-rw-r--r--javatests/com/google/turbine/main/MainTest.java3
-rw-r--r--javatests/com/google/turbine/options/LanguageVersionTest.java4
-rw-r--r--javatests/com/google/turbine/parse/CommentParserTest.java15
-rw-r--r--javatests/com/google/turbine/parse/LexerTest.java27
-rw-r--r--javatests/com/google/turbine/parse/ParseErrorTest.java26
-rw-r--r--javatests/com/google/turbine/processing/AbstractTurbineTypesBiFunctionTest.java47
-rw-r--r--javatests/com/google/turbine/processing/AbstractTurbineTypesBiPredicateTest.java20
-rw-r--r--javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java32
-rw-r--r--javatests/com/google/turbine/processing/ProcessingIntegrationTest.java60
-rw-r--r--javatests/com/google/turbine/processing/TurbineFilerTest.java9
-rw-r--r--javatests/com/google/turbine/processing/TurbineTypesAsMemberOfTest.java76
-rw-r--r--javatests/com/google/turbine/testing/TestResources.java3
-rw-r--r--javatests/com/google/turbine/zip/ZipTest.java168
-rw-r--r--pom.xml44
37 files changed, 802 insertions, 160 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e12698c..54db52c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,19 +29,19 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
- java: [ 17, 11 ]
+ java: [ 19, 17, 11.0.16 ]
experimental: [ false ]
include:
# Only test on macos and windows with a single recent JDK to avoid a
# combinatorial explosion of test configurations.
- os: macos-latest
- java: 17
+ java: 19
experimental: false
- os: windows-latest
- java: 17
+ java: 19
experimental: false
- os: ubuntu-latest
- java: 18-ea
+ java: 20-ea
experimental: true
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
diff --git a/Android.bp b/Android.bp
index f5880c2..2236365 100644
--- a/Android.bp
+++ b/Android.bp
@@ -55,4 +55,10 @@ java_library_host {
proto: {
type: "full",
},
+
+ errorprone: {
+ javacflags: [
+ "-Xep:NoCanIgnoreReturnValueOnClasses:WARN",
+ ],
+ },
}
diff --git a/METADATA b/METADATA
index e166a49..ad28c65 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,5 @@
name: "turbine"
-description:
- "Turbine is a header compiler for Java."
-
+description: "Turbine is a header compiler for Java."
third_party {
url {
type: HOMEPAGE
@@ -11,7 +9,11 @@ third_party {
type: GIT
value: "https://github.com/google/turbine"
}
- version: "a963d859dc98108c37a701c1f76c4494fc480198"
- last_upgrade_date { year: 2020 month: 3 day: 27 }
+ version: "f42d03f5b18a61a3cdaf2f903e54618771c8797a"
license_type: NOTICE
+ last_upgrade_date {
+ year: 2022
+ month: 6
+ day: 1
+ }
}
diff --git a/java/com/google/turbine/binder/FileManagerClassBinder.java b/java/com/google/turbine/binder/FileManagerClassBinder.java
index d36d2d8..a807dd7 100644
--- a/java/com/google/turbine/binder/FileManagerClassBinder.java
+++ b/java/com/google/turbine/binder/FileManagerClassBinder.java
@@ -19,7 +19,6 @@ package com.google.turbine.binder;
import com.google.common.base.Joiner;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
-import com.google.common.io.ByteStreams;
import com.google.turbine.binder.bound.ModuleInfo;
import com.google.turbine.binder.bytecode.BytecodeBoundClass;
import com.google.turbine.binder.env.Env;
@@ -113,7 +112,7 @@ public final class FileManagerClassBinder {
@Override
public byte[] get() {
try {
- return ByteStreams.toByteArray(jfo.openInputStream());
+ return jfo.openInputStream().readAllBytes();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -162,7 +161,7 @@ public final class FileManagerClassBinder {
@Override
public byte[] get() {
try {
- return ByteStreams.toByteArray(fileObject.openInputStream());
+ return fileObject.openInputStream().readAllBytes();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/java/com/google/turbine/bytecode/ByteReader.java b/java/com/google/turbine/bytecode/ByteReader.java
index a9deff2..5458b49 100644
--- a/java/com/google/turbine/bytecode/ByteReader.java
+++ b/java/com/google/turbine/bytecode/ByteReader.java
@@ -20,11 +20,9 @@ import static com.google.common.base.Verify.verify;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.ByteArrayInputStream;
/** A {@link ByteArrayDataInput} wrapper that tracks the current byte array index. */
-@CanIgnoreReturnValue
public class ByteReader {
private final byte[] bytes;
diff --git a/java/com/google/turbine/bytecode/ClassReader.java b/java/com/google/turbine/bytecode/ClassReader.java
index 740026a..da35196 100644
--- a/java/com/google/turbine/bytecode/ClassReader.java
+++ b/java/com/google/turbine/bytecode/ClassReader.java
@@ -159,7 +159,7 @@ public class ClassReader {
/** Reads a JVMS 4.7.9 Signature attribute. */
private String readSignature(ConstantPoolReader constantPool) {
String signature;
- reader.u4(); // length
+ int unusedLength = reader.u4();
signature = constantPool.utf8(reader.u2());
return signature;
}
@@ -167,7 +167,7 @@ public class ClassReader {
/** Reads JVMS 4.7.6 InnerClasses attributes. */
private List<ClassFile.InnerClass> readInnerClasses(
ConstantPoolReader constantPool, String thisClass) {
- reader.u4(); // length
+ int unusedLength = reader.u4();
int numberOfClasses = reader.u2();
List<ClassFile.InnerClass> innerclasses = new ArrayList<>();
for (int i = 0; i < numberOfClasses; i++) {
@@ -197,7 +197,7 @@ public class ClassReader {
private void readAnnotations(
ImmutableList.Builder<ClassFile.AnnotationInfo> annotations,
ConstantPoolReader constantPool) {
- reader.u4(); // length
+ int unusedLength = reader.u4();
int numAnnotations = reader.u2();
for (int n = 0; n < numAnnotations; n++) {
annotations.add(readAnnotation(constantPool));
@@ -207,7 +207,7 @@ public class ClassReader {
/** Processes a JVMS 4.7.18 RuntimeVisibleParameterAnnotations attribute */
public void readParameterAnnotations(
List<ImmutableList.Builder<AnnotationInfo>> annotations, ConstantPoolReader constantPool) {
- reader.u4(); // length
+ int unusedLength = reader.u4();
int numParameters = reader.u1();
while (annotations.size() < numParameters) {
annotations.add(ImmutableList.builder());
@@ -223,7 +223,7 @@ public class ClassReader {
/** Processes a JVMS 4.7.24 MethodParameters attribute. */
private void readMethodParameters(
ImmutableList.Builder<ParameterInfo> parameters, ConstantPoolReader constantPool) {
- reader.u4(); // length
+ int unusedLength = reader.u4();
int numParameters = reader.u1();
for (int i = 0; i < numParameters; i++) {
String name = constantPool.utf8(reader.u2());
@@ -239,7 +239,7 @@ public class ClassReader {
/** Processes a JVMS 4.7.25 Module attribute. */
private ModuleInfo readModule(ConstantPoolReader constantPool) {
- reader.u4(); // length
+ int unusedLength = reader.u4();
String name = constantPool.moduleInfo(reader.u2());
int flags = reader.u2();
int versionIndex = reader.u2();
@@ -423,7 +423,7 @@ public class ClassReader {
signature = readSignature(constantPool);
break;
case "AnnotationDefault":
- reader.u4(); // length
+ int unusedLength = reader.u4();
defaultValue = readElementValue(constantPool);
break;
case "RuntimeInvisibleAnnotations":
@@ -470,7 +470,7 @@ public class ClassReader {
/** Reads an Exceptions attribute. */
private ImmutableList<String> readExceptions(ConstantPoolReader constantPool) {
ImmutableList.Builder<String> exceptions = ImmutableList.builder();
- reader.u4(); // length
+ int unusedLength = reader.u4();
int numberOfExceptions = reader.u2();
for (int exceptionIndex = 0; exceptionIndex < numberOfExceptions; exceptionIndex++) {
exceptions.add(constantPool.classInfo(reader.u2()));
@@ -496,7 +496,7 @@ public class ClassReader {
String attributeName = constantPool.utf8(reader.u2());
switch (attributeName) {
case "ConstantValue":
- reader.u4(); // length
+ int unusedLength = reader.u4();
value = constantPool.constant(reader.u2());
break;
case "RuntimeInvisibleAnnotations":
@@ -525,7 +525,7 @@ public class ClassReader {
}
private String readTurbineTransitiveJar(ConstantPoolReader constantPool) {
- reader.u4(); // length
+ int unusedLength = reader.u4();
return constantPool.utf8(reader.u2());
}
}
diff --git a/java/com/google/turbine/main/Main.java b/java/com/google/turbine/main/Main.java
index da97bcd..34984a8 100644
--- a/java/com/google/turbine/main/Main.java
+++ b/java/com/google/turbine/main/Main.java
@@ -58,7 +58,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
-import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
@@ -433,16 +432,11 @@ public final class Main {
}
/** Normalize timestamps. */
- static final long DEFAULT_TIMESTAMP =
- LocalDateTime.of(2010, 1, 1, 0, 0, 0)
- .atZone(ZoneId.systemDefault())
- .toInstant()
- .toEpochMilli();
+ static final LocalDateTime DEFAULT_TIMESTAMP = LocalDateTime.of(2010, 1, 1, 0, 0, 0);
private static void addEntry(JarOutputStream jos, String name, byte[] bytes) throws IOException {
JarEntry je = new JarEntry(name);
- // TODO(cushon): switch to setLocalTime after we migrate to JDK 9
- je.setTime(DEFAULT_TIMESTAMP);
+ je.setTimeLocal(DEFAULT_TIMESTAMP);
je.setMethod(ZipEntry.STORED);
je.setSize(bytes.length);
je.setCrc(Hashing.crc32().hashBytes(bytes).padToLong());
diff --git a/java/com/google/turbine/options/LanguageVersion.java b/java/com/google/turbine/options/LanguageVersion.java
index e2b0ea7..d8641b4 100644
--- a/java/com/google/turbine/options/LanguageVersion.java
+++ b/java/com/google/turbine/options/LanguageVersion.java
@@ -53,7 +53,7 @@ public abstract class LanguageVersion {
try {
return SourceVersion.valueOf("RELEASE_" + source());
} catch (IllegalArgumentException unused) {
- throw new IllegalArgumentException("invalid -source version: " + source());
+ return SourceVersion.latestSupported();
}
}
diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java
index 8b7466f..e4aad6b 100644
--- a/java/com/google/turbine/parse/ConstExpressionParser.java
+++ b/java/com/google/turbine/parse/ConstExpressionParser.java
@@ -588,11 +588,11 @@ public class ConstExpressionParser {
}
eat();
int pos = position;
- Tree.ConstVarName constVarName = (Tree.ConstVarName) qualIdent();
- if (constVarName == null) {
+ Expression constVarName = qualIdent();
+ if (!(constVarName instanceof Tree.ConstVarName)) {
return null;
}
- ImmutableList<Ident> name = constVarName.name();
+ ImmutableList<Ident> name = ((Tree.ConstVarName) constVarName).name();
ImmutableList.Builder<Tree.Expression> args = ImmutableList.builder();
if (token == Token.LPAREN) {
eat();
diff --git a/java/com/google/turbine/parse/Parser.java b/java/com/google/turbine/parse/Parser.java
index c370ad8..acf84d7 100644
--- a/java/com/google/turbine/parse/Parser.java
+++ b/java/com/google/turbine/parse/Parser.java
@@ -547,6 +547,7 @@ public class Parser {
switch (token) {
case IDENT:
{
+ String javadoc = lexer.javadoc();
Ident name = eatIdent();
if (token == Token.LPAREN) {
dropParens();
@@ -569,7 +570,7 @@ public class Parser {
ImmutableList.of()),
name,
Optional.<Expression>empty(),
- null));
+ javadoc));
annos = ImmutableList.builder();
break;
}
@@ -719,6 +720,11 @@ public class Parser {
case IDENT:
Ident ident = ident();
+ if (ident.value().equals("sealed")) {
+ next();
+ access.add(TurbineModifier.SEALED);
+ break;
+ }
if (ident.value().equals("non")) {
int pos = position;
next();
diff --git a/java/com/google/turbine/parse/StreamLexer.java b/java/com/google/turbine/parse/StreamLexer.java
index 2348385..3d46b90 100644
--- a/java/com/google/turbine/parse/StreamLexer.java
+++ b/java/com/google/turbine/parse/StreamLexer.java
@@ -17,8 +17,11 @@
package com.google.turbine.parse;
import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.turbine.parse.UnicodeEscapePreprocessor.ASCII_SUB;
+import static java.lang.Math.min;
+import com.google.common.collect.ImmutableList;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
@@ -399,6 +402,15 @@ public class StreamLexer implements Lexer {
case '"':
{
eat();
+ if (ch == '"') {
+ eat();
+ if (ch != '"') {
+ saveValue("");
+ return Token.STRING_LITERAL;
+ }
+ eat();
+ return textBlock();
+ }
readFrom();
StringBuilder sb = new StringBuilder();
STRING:
@@ -436,6 +448,156 @@ public class StreamLexer implements Lexer {
}
}
+ private Token textBlock() {
+ OUTER:
+ while (true) {
+ switch (ch) {
+ case ' ':
+ case '\r':
+ case '\t':
+ eat();
+ break;
+ default:
+ break OUTER;
+ }
+ }
+ switch (ch) {
+ case '\r':
+ eat();
+ if (ch == '\n') {
+ eat();
+ }
+ break;
+ case '\n':
+ eat();
+ break;
+ default:
+ throw inputError();
+ }
+ readFrom();
+ StringBuilder sb = new StringBuilder();
+ while (true) {
+ switch (ch) {
+ case '"':
+ eat();
+ if (ch != '"') {
+ sb.append("\"");
+ continue;
+ }
+ eat();
+ if (ch != '"') {
+ sb.append("\"\"");
+ continue;
+ }
+ eat();
+ String value = sb.toString();
+ value = stripIndent(value);
+ value = translateEscapes(value);
+ saveValue(value);
+ return Token.STRING_LITERAL;
+ case ASCII_SUB:
+ if (reader.done()) {
+ return Token.EOF;
+ }
+ // falls through
+ default:
+ sb.appendCodePoint(ch);
+ eat();
+ continue;
+ }
+ }
+ }
+
+ static String stripIndent(String value) {
+ if (value.isEmpty()) {
+ return value;
+ }
+ ImmutableList<String> lines = value.lines().collect(toImmutableList());
+ // the amount of whitespace to strip from the beginning of every line
+ int strip = Integer.MAX_VALUE;
+ char last = value.charAt(value.length() - 1);
+ boolean trailingNewline = last == '\n' || last == '\r';
+ if (trailingNewline) {
+ // If the input contains a trailing newline, we have something like:
+ //
+ // |String s = """
+ // | foo
+ // |""";
+ //
+ // Because the final """ is unindented, nothing should be stripped.
+ strip = 0;
+ } else {
+ // find the longest common prefix of whitespace across all non-blank lines
+ for (int i = 0; i < lines.size(); i++) {
+ String line = lines.get(i);
+ int nonWhitespaceStart = nonWhitespaceStart(line);
+ if (nonWhitespaceStart == line.length()) {
+ continue;
+ }
+ strip = min(strip, nonWhitespaceStart);
+ }
+ }
+ StringBuilder result = new StringBuilder();
+ boolean first = true;
+ for (String line : lines) {
+ if (!first) {
+ result.append('\n');
+ }
+ int end = trailingWhitespaceStart(line);
+ if (strip <= end) {
+ result.append(line, strip, end);
+ }
+ first = false;
+ }
+ if (trailingNewline) {
+ result.append('\n');
+ }
+ return result.toString();
+ }
+
+ private static int nonWhitespaceStart(String value) {
+ int i = 0;
+ while (i < value.length() && Character.isWhitespace(value.charAt(i))) {
+ i++;
+ }
+ return i;
+ }
+
+ private static int trailingWhitespaceStart(String value) {
+ int i = value.length() - 1;
+ while (i >= 0 && Character.isWhitespace(value.charAt(i))) {
+ i--;
+ }
+ return i + 1;
+ }
+
+ private static String translateEscapes(String value) {
+ StreamLexer lexer =
+ new StreamLexer(new UnicodeEscapePreprocessor(new SourceFile(null, value + ASCII_SUB)));
+ return lexer.translateEscapes();
+ }
+
+ private String translateEscapes() {
+ readFrom();
+ StringBuilder sb = new StringBuilder();
+ OUTER:
+ while (true) {
+ switch (ch) {
+ case '\\':
+ eat();
+ sb.append(escape());
+ continue;
+ case ASCII_SUB:
+ break OUTER;
+ default:
+ sb.appendCodePoint(ch);
+ eat();
+ continue;
+ }
+ }
+ return sb.toString();
+ }
+
private char escape() {
boolean zeroToThree = false;
switch (ch) {
diff --git a/java/com/google/turbine/processing/TurbineElements.java b/java/com/google/turbine/processing/TurbineElements.java
index b5fd7f4..9b3ea26 100644
--- a/java/com/google/turbine/processing/TurbineElements.java
+++ b/java/com/google/turbine/processing/TurbineElements.java
@@ -384,7 +384,7 @@ public class TurbineElements implements Elements {
return false;
}
TypeMirror a = overrider.asType();
- TypeMirror b = types.asMemberOf((DeclaredType) type.asType(), overridden);
+ TypeMirror b = types.asMemberOfInternal((DeclaredType) type.asType(), overridden);
if (b == null) {
return false;
}
diff --git a/java/com/google/turbine/processing/TurbineFiler.java b/java/com/google/turbine/processing/TurbineFiler.java
index 45cdc22..8c522ba 100644
--- a/java/com/google/turbine/processing/TurbineFiler.java
+++ b/java/com/google/turbine/processing/TurbineFiler.java
@@ -24,7 +24,6 @@ import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
-import com.google.common.io.ByteStreams;
import com.google.turbine.diag.SourceFile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -232,7 +231,7 @@ public class TurbineFiler implements Filer {
@Override
public URI toUri() {
- return URI.create("file://" + path);
+ return URI.create("file:///" + path);
}
@Override
@@ -309,7 +308,7 @@ public class TurbineFiler implements Filer {
@Override
public URI toUri() {
- return URI.create("file://" + name + kind.extension);
+ return URI.create("file:///" + name + kind.extension);
}
@Override
@@ -380,7 +379,7 @@ public class TurbineFiler implements Filer {
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
- return new String(ByteStreams.toByteArray(openInputStream()), UTF_8);
+ return new String(openInputStream().readAllBytes(), UTF_8);
}
}
diff --git a/java/com/google/turbine/processing/TurbineTypes.java b/java/com/google/turbine/processing/TurbineTypes.java
index d2068dd..467059c 100644
--- a/java/com/google/turbine/processing/TurbineTypes.java
+++ b/java/com/google/turbine/processing/TurbineTypes.java
@@ -26,18 +26,11 @@ import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.sym.ClassSymbol;
-import com.google.turbine.binder.sym.FieldSymbol;
-import com.google.turbine.binder.sym.MethodSymbol;
-import com.google.turbine.binder.sym.ParamSymbol;
-import com.google.turbine.binder.sym.RecordComponentSymbol;
import com.google.turbine.binder.sym.Symbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineTyKind;
-import com.google.turbine.processing.TurbineElement.TurbineExecutableElement;
-import com.google.turbine.processing.TurbineElement.TurbineFieldElement;
import com.google.turbine.processing.TurbineElement.TurbineTypeElement;
-import com.google.turbine.processing.TurbineElement.TurbineTypeParameterElement;
import com.google.turbine.processing.TurbineTypeMirror.TurbineDeclaredType;
import com.google.turbine.processing.TurbineTypeMirror.TurbineErrorType;
import com.google.turbine.processing.TurbineTypeMirror.TurbineTypeVariable;
@@ -1127,41 +1120,6 @@ public class TurbineTypes implements Types {
.build()));
}
- private static ClassSymbol enclosingClass(Symbol symbol) {
- switch (symbol.symKind()) {
- case CLASS:
- return (ClassSymbol) symbol;
- case TY_PARAM:
- return enclosingClass(((TyVarSymbol) symbol).owner());
- case METHOD:
- return ((MethodSymbol) symbol).owner();
- case FIELD:
- return ((FieldSymbol) symbol).owner();
- case PARAMETER:
- return ((ParamSymbol) symbol).owner().owner();
- case RECORD_COMPONENT:
- return ((RecordComponentSymbol) symbol).owner();
- case MODULE:
- case PACKAGE:
- throw new IllegalArgumentException(symbol.symKind().toString());
- }
- throw new AssertionError(symbol.symKind());
- }
-
- private static Type type(Element element) {
- switch (element.getKind()) {
- case TYPE_PARAMETER:
- return TyVar.create(((TurbineTypeParameterElement) element).sym(), ImmutableList.of());
- case FIELD:
- return ((TurbineFieldElement) element).info().type();
- case METHOD:
- case CONSTRUCTOR:
- return ((TurbineExecutableElement) element).info().asType();
- default:
- throw new UnsupportedOperationException(element.toString());
- }
- }
-
/**
* Returns the {@link TypeMirror} of the given {@code element} as a member of {@code containing},
* or else {@code null} if it is not a member.
@@ -1171,13 +1129,24 @@ public class TurbineTypes implements Types {
*/
@Override
public TypeMirror asMemberOf(DeclaredType containing, Element element) {
+ TypeMirror result = asMemberOfInternal(containing, element);
+ if (result == null) {
+ throw new IllegalArgumentException(String.format("asMemberOf(%s, %s)", containing, element));
+ }
+ return result;
+ }
+
+ public @Nullable TypeMirror asMemberOfInternal(DeclaredType containing, Element element) {
ClassTy c = ((TurbineDeclaredType) containing).asTurbineType();
- ClassSymbol symbol = enclosingClass(((TurbineElement) element).sym());
- ImmutableList<ClassTy> path = factory.cha().search(c, enclosingClass(symbol));
+ Symbol enclosing = ((TurbineElement) element.getEnclosingElement()).sym();
+ if (!enclosing.symKind().equals(Symbol.Kind.CLASS)) {
+ return null;
+ }
+ ImmutableList<ClassTy> path = factory.cha().search(c, (ClassSymbol) enclosing);
if (path.isEmpty()) {
return null;
}
- Type type = type(element);
+ Type type = asTurbineType(element.asType());
for (ClassTy ty : path) {
ImmutableMap<TyVarSymbol, Type> mapping = getMapping(ty);
if (mapping == null) {
diff --git a/java/com/google/turbine/type/Type.java b/java/com/google/turbine/type/Type.java
index 085346a..5fbf1b1 100644
--- a/java/com/google/turbine/type/Type.java
+++ b/java/com/google/turbine/type/Type.java
@@ -17,6 +17,7 @@
package com.google.turbine.type;
import static com.google.common.collect.Iterables.getLast;
+import static java.lang.Math.max;
import static java.util.Objects.requireNonNull;
import com.google.auto.value.AutoValue;
@@ -144,15 +145,23 @@ public interface Type {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (SimpleClassTy c : classes()) {
- for (AnnoInfo anno : c.annos()) {
- sb.append(anno);
- sb.append(' ');
- }
+ String binaryName = c.sym().binaryName();
if (!first) {
+ for (AnnoInfo anno : c.annos()) {
+ sb.append(anno);
+ sb.append(' ');
+ }
sb.append('.');
- sb.append(c.sym().binaryName().substring(c.sym().binaryName().lastIndexOf('$') + 1));
+ sb.append(binaryName, binaryName.lastIndexOf('$') + 1, binaryName.length());
} else {
- sb.append(c.sym().binaryName().replace('/', '.').replace('$', '.'));
+ int idx = max(binaryName.lastIndexOf('/'), binaryName.lastIndexOf('$')) + 1;
+ String name = binaryName.replace('/', '.').replace('$', '.');
+ sb.append(name, 0, idx);
+ for (AnnoInfo anno : c.annos()) {
+ sb.append(anno);
+ sb.append(' ');
+ }
+ sb.append(name, idx, name.length());
}
if (!c.targs().isEmpty()) {
sb.append('<');
diff --git a/java/com/google/turbine/zip/Zip.java b/java/com/google/turbine/zip/Zip.java
index fa0f0e0..c08999b 100644
--- a/java/com/google/turbine/zip/Zip.java
+++ b/java/com/google/turbine/zip/Zip.java
@@ -18,7 +18,6 @@ package com.google.turbine.zip;
import static java.nio.charset.StandardCharsets.UTF_8;
-import com.google.common.io.ByteStreams;
import com.google.common.primitives.UnsignedInts;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
@@ -65,7 +64,6 @@ import java.util.zip.ZipException;
* supported.
* <li>UTF-8 is the only supported encoding.
* <li>STORED and DEFLATE are the only supported compression methods.
- * <li>zip64 extensible data sectors are not supported.
* <li>Zip files larger than Integer.MAX_VALUE bytes are not supported.
* <li>The only supported ZIP64 field is ENDTOT. This implementation assumes that the ZIP64 end
* header is present only if ENDTOT in EOCD header is 0xFFFF.
@@ -74,6 +72,7 @@ import java.util.zip.ZipException;
public final class Zip {
static final int ZIP64_ENDSIG = 0x06064b50;
+ static final int ZIP64_LOCSIG = 0x07064b50;
static final int LOCHDR = 30; // LOC header size
static final int CENHDR = 46; // CEN header size
@@ -196,20 +195,44 @@ public final class Zip {
if (totalEntries == ZIP64_MAGICCOUNT) {
// Assume the zip64 EOCD has the usual size; we don't support zip64 extensible data sectors.
long zip64eocdOffset = size - ENDHDR - ZIP64_LOCHDR - ZIP64_ENDHDR;
- MappedByteBuffer zip64eocd = chan.map(MapMode.READ_ONLY, zip64eocdOffset, ZIP64_ENDHDR);
- zip64eocd.order(ByteOrder.LITTLE_ENDIAN);
// Note that zip reading is necessarily best-effort, since an archive could contain 0xFFFF
// entries and the last entry's data could contain a ZIP64_ENDSIG. Some implementations
// read the full EOCD records and compare them.
- if (zip64eocd.getInt(0) == ZIP64_ENDSIG) {
- cdsize = zip64eocd.getLong(ZIP64_ENDSIZ);
+ long zip64cdsize = zip64cdsize(chan, zip64eocdOffset);
+ if (zip64cdsize != -1) {
eocdOffset = zip64eocdOffset;
+ cdsize = zip64cdsize;
+ } else {
+ // If we couldn't find a zip64 EOCD at a fixed offset, either it doesn't exist
+ // or there was a zip64 extensible data sector, so try going through the
+ // locator. This approach doesn't work if data was prepended to the archive
+ // without updating the offset in the locator.
+ MappedByteBuffer zip64loc =
+ chan.map(MapMode.READ_ONLY, size - ENDHDR - ZIP64_LOCHDR, ZIP64_LOCHDR);
+ zip64loc.order(ByteOrder.LITTLE_ENDIAN);
+ if (zip64loc.getInt(0) == ZIP64_LOCSIG) {
+ zip64eocdOffset = zip64loc.getLong(8);
+ zip64cdsize = zip64cdsize(chan, zip64eocdOffset);
+ if (zip64cdsize != -1) {
+ eocdOffset = zip64eocdOffset;
+ cdsize = zip64cdsize;
+ }
+ }
}
}
this.cd = chan.map(MapMode.READ_ONLY, eocdOffset - cdsize, cdsize);
cd.order(ByteOrder.LITTLE_ENDIAN);
}
+ static long zip64cdsize(FileChannel chan, long eocdOffset) throws IOException {
+ MappedByteBuffer zip64eocd = chan.map(MapMode.READ_ONLY, eocdOffset, ZIP64_ENDHDR);
+ zip64eocd.order(ByteOrder.LITTLE_ENDIAN);
+ if (zip64eocd.getInt(0) == ZIP64_ENDSIG) {
+ return zip64eocd.getLong(ZIP64_ENDSIZ);
+ }
+ return -1;
+ }
+
@Override
public Iterator<Entry> iterator() {
return new ZipIterator(path, chan, cd);
@@ -308,9 +331,9 @@ public final class Zip {
fc.get(bytes);
if (deflate) {
bytes =
- ByteStreams.toByteArray(
- new InflaterInputStream(
- new ByteArrayInputStream(bytes), new Inflater(/*nowrap=*/ true)));
+ new InflaterInputStream(
+ new ByteArrayInputStream(bytes), new Inflater(/*nowrap=*/ true))
+ .readAllBytes();
}
return bytes;
} catch (IOException e) {
diff --git a/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java b/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java
index 65d973d..e2d54bd 100644
--- a/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java
+++ b/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java
@@ -24,7 +24,6 @@ import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.Iterables;
-import com.google.common.io.ByteStreams;
import com.google.turbine.binder.bound.TurbineClassValue;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
@@ -195,7 +194,7 @@ public class BytecodeBoundClassTest {
private static byte[] toByteArrayOrDie(InputStream is) {
try {
- return ByteStreams.toByteArray(is);
+ return is.readAllBytes();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/javatests/com/google/turbine/deps/TransitiveTest.java b/javatests/com/google/turbine/deps/TransitiveTest.java
index f08e899..3829ddd 100644
--- a/javatests/com/google/turbine/deps/TransitiveTest.java
+++ b/javatests/com/google/turbine/deps/TransitiveTest.java
@@ -26,7 +26,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
-import com.google.common.io.ByteStreams;
import com.google.protobuf.ExtensionRegistry;
import com.google.turbine.bytecode.ClassFile;
import com.google.turbine.bytecode.ClassFile.InnerClass;
@@ -87,7 +86,7 @@ public class TransitiveTest {
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
- jarEntries.put(je.getName(), ByteStreams.toByteArray(jf.getInputStream(je)));
+ jarEntries.put(je.getName(), jf.getInputStream(je).readAllBytes());
}
}
return jarEntries;
diff --git a/javatests/com/google/turbine/lower/LongStringIntegrationTest.java b/javatests/com/google/turbine/lower/LongStringIntegrationTest.java
index a462b69..7bb61e5 100644
--- a/javatests/com/google/turbine/lower/LongStringIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LongStringIntegrationTest.java
@@ -44,7 +44,7 @@ public class LongStringIntegrationTest {
public void test() throws Exception {
Map<String, byte[]> output =
runTurbineWithStack(
- /* stackSize= */ 1,
+ /* stackSize= */ 100_000,
/* input= */ ImmutableMap.of("Test.java", source()),
/* classpath= */ ImmutableList.of());
@@ -70,7 +70,7 @@ public class LongStringIntegrationTest {
},
/* name= */ "turbine",
stackSize);
- t.run();
+ t.start();
t.join();
return output;
}
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index 97170ca..94f1d07 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -44,7 +44,12 @@ import org.junit.runners.Parameterized.Parameters;
public class LowerIntegrationTest {
private static final ImmutableMap<String, Integer> SOURCE_VERSION =
- ImmutableMap.of("record.test", 16, "record2.test", 16, "sealed.test", 17);
+ ImmutableMap.of(
+ "record.test", 16, //
+ "record2.test", 16,
+ "sealed.test", 17,
+ "sealed_nested.test", 17,
+ "textblock.test", 15);
@Parameters(name = "{index}: {0}")
public static Iterable<Object[]> parameters() {
@@ -285,6 +290,7 @@ public class LowerIntegrationTest {
"superabstract.test",
"supplierfunction.test",
"tbound.test",
+ "textblock.test",
"tyanno_inner.test",
"tyanno_varargs.test",
"typaram.test",
diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java
index 6d3a6df..a6410db 100644
--- a/javatests/com/google/turbine/lower/LowerTest.java
+++ b/javatests/com/google/turbine/lower/LowerTest.java
@@ -312,7 +312,7 @@ public class LowerTest {
String attributeName = pool.utf8(reader.u2());
switch (attributeName) {
case "Signature":
- reader.u4(); // length
+ int unusedLength = reader.u4();
signature = pool.utf8(reader.u2());
break;
default:
diff --git a/javatests/com/google/turbine/lower/testdata/sealed_nested.test b/javatests/com/google/turbine/lower/testdata/sealed_nested.test
new file mode 100644
index 0000000..6c4304e
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/sealed_nested.test
@@ -0,0 +1,7 @@
+=== T.java ===
+
+class T {
+ static sealed class Sealed permits Sealed.Foo {
+ static final class Foo extends Sealed {}
+ }
+}
diff --git a/javatests/com/google/turbine/lower/testdata/textblock.test b/javatests/com/google/turbine/lower/testdata/textblock.test
new file mode 100644
index 0000000..9683296
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/textblock.test
@@ -0,0 +1,30 @@
+=== TextBlock.java ===
+class TextBlock {
+ public static final String hello = """
+ hello
+ world
+ """;
+ public static final String escape = """
+ hello\nworld\"
+ \r\t\b
+ \0123
+ \'
+ \\
+ \"
+ """;
+ public static final String quotes = """
+ " "" ""\" """;
+ public static final String newline = """
+ hello
+ world""";
+ public static final String blank = """
+ hello
+
+
+ world
+ """;
+ public static final String allBlank = """
+
+
+ """;
+}
diff --git a/javatests/com/google/turbine/main/MainTest.java b/javatests/com/google/turbine/main/MainTest.java
index 3504891..c894d9d 100644
--- a/javatests/com/google/turbine/main/MainTest.java
+++ b/javatests/com/google/turbine/main/MainTest.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.io.ByteStreams;
import com.google.common.io.MoreFiles;
import com.google.protobuf.ExtensionRegistry;
import com.google.turbine.diag.TurbineError;
@@ -148,7 +147,7 @@ public class MainTest {
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
- data.put(je.getName(), ByteStreams.toByteArray(jf.getInputStream(je)));
+ data.put(je.getName(), jf.getInputStream(je).readAllBytes());
}
}
return data;
diff --git a/javatests/com/google/turbine/options/LanguageVersionTest.java b/javatests/com/google/turbine/options/LanguageVersionTest.java
index 601652c..a5b303d 100644
--- a/javatests/com/google/turbine/options/LanguageVersionTest.java
+++ b/javatests/com/google/turbine/options/LanguageVersionTest.java
@@ -140,8 +140,6 @@ public class LanguageVersionTest {
public void unsupportedSourceVersion() {
LanguageVersion languageVersion =
LanguageVersion.fromJavacopts(ImmutableList.of("-source", "9999"));
- IllegalArgumentException expected =
- assertThrows(IllegalArgumentException.class, languageVersion::sourceVersion);
- assertThat(expected).hasMessageThat().contains("invalid -source version:");
+ assertThat(languageVersion.sourceVersion()).isEqualTo(SourceVersion.latestSupported());
}
}
diff --git a/javatests/com/google/turbine/parse/CommentParserTest.java b/javatests/com/google/turbine/parse/CommentParserTest.java
index a2f84d5..d10d34d 100644
--- a/javatests/com/google/turbine/parse/CommentParserTest.java
+++ b/javatests/com/google/turbine/parse/CommentParserTest.java
@@ -58,6 +58,13 @@ public class CommentParserTest {
" * class C",
" */",
" class C {}",
+ " /** This is an enum. */",
+ " enum E {",
+ " /** This is H. */",
+ " H,",
+ " /** This is I. */",
+ " I",
+ " }",
"}\n"));
TyDecl decl = getOnlyElement(unit.decls());
assertThat(decl.javadoc()).isEqualTo(" hello world ");
@@ -68,11 +75,17 @@ public class CommentParserTest {
.collect(toImmutableMap(c -> c.name().value(), c -> c.javadoc())))
.containsExactly(
"A", "\n * This is\n * class A\n ",
- "C", "\n * This is\n * class C\n ");
+ "C", "\n * This is\n * class C\n ",
+ "E", " This is an enum. ");
TyDecl a = (TyDecl) decl.members().get(0);
MethDecl f = (MethDecl) a.members().get(0);
assertThat(f.javadoc()).isEqualTo(" This is a method ");
VarDecl g = (VarDecl) a.members().get(1);
assertThat(g.javadoc()).isEqualTo(" This is a field ");
+ TyDecl e = (TyDecl) decl.members().get(3);
+ VarDecl h = (VarDecl) e.members().get(0);
+ assertThat(h.javadoc()).isEqualTo(" This is H. ");
+ VarDecl i = (VarDecl) e.members().get(1);
+ assertThat(i.javadoc()).isEqualTo(" This is I. ");
}
}
diff --git a/javatests/com/google/turbine/parse/LexerTest.java b/javatests/com/google/turbine/parse/LexerTest.java
index c3d7804..bf0b374 100644
--- a/javatests/com/google/turbine/parse/LexerTest.java
+++ b/javatests/com/google/turbine/parse/LexerTest.java
@@ -17,11 +17,15 @@
package com.google.turbine.parse;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
import com.google.common.escape.SourceCodeEscapers;
+import com.google.common.truth.Expect;
import com.google.turbine.diag.SourceFile;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -29,6 +33,8 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class LexerTest {
+ @Rule public final Expect expect = Expect.create();
+
@Test
public void testSimple() {
assertThat(lex("\nasd dsa\n")).containsExactly("IDENT(asd)", "IDENT(dsa)", "EOF");
@@ -367,4 +373,25 @@ public class LexerTest {
} while (token != Token.EOF);
return tokens;
}
+
+ @Test
+ public void stripIndent() throws Exception {
+ assumeTrue(Runtime.version().feature() >= 13);
+ String[] inputs = {
+ "",
+ "hello",
+ "hello\n",
+ "\nhello",
+ "\n hello\n world",
+ "\n hello\n world\n ",
+ "\n hello\n world\n",
+ "\n hello\n world\n ",
+ "\n hello\nworld",
+ "\n hello\n \nworld\n ",
+ };
+ Method stripIndent = String.class.getMethod("stripIndent");
+ for (String input : inputs) {
+ expect.that(StreamLexer.stripIndent(input)).isEqualTo(stripIndent.invoke(input));
+ }
+ }
}
diff --git a/javatests/com/google/turbine/parse/ParseErrorTest.java b/javatests/com/google/turbine/parse/ParseErrorTest.java
index 2c48b81..4a92648 100644
--- a/javatests/com/google/turbine/parse/ParseErrorTest.java
+++ b/javatests/com/google/turbine/parse/ParseErrorTest.java
@@ -307,6 +307,32 @@ public class ParseErrorTest {
" ^"));
}
+ @Test
+ public void singleLineTextBlockRejected() {
+ String input = "class T { String s = \"\"\" \"\"\"; }";
+ TurbineError e = assertThrows(TurbineError.class, () -> Parser.parse(input));
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo(
+ lines(
+ "<>:1: error: unexpected input: \"",
+ "class T { String s = \"\"\" \"\"\"; }",
+ " ^"));
+ }
+
+ @Test
+ public void annotationClassLiteral() {
+ String input = "@interface A { A value() default @Integer.class; }";
+ TurbineError e = assertThrows(TurbineError.class, () -> Parser.parse(input));
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo(
+ lines(
+ "<>:1: error: unexpected token: ;",
+ "@interface A { A value() default @Integer.class; }",
+ " ^"));
+ }
+
private static String lines(String... lines) {
return Joiner.on(System.lineSeparator()).join(lines);
}
diff --git a/javatests/com/google/turbine/processing/AbstractTurbineTypesBiFunctionTest.java b/javatests/com/google/turbine/processing/AbstractTurbineTypesBiFunctionTest.java
new file mode 100644
index 0000000..e00673d
--- /dev/null
+++ b/javatests/com/google/turbine/processing/AbstractTurbineTypesBiFunctionTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 Google Inc. All Rights Reserved.
+ *
+ * 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.turbine.processing;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.util.Types;
+
+/**
+ * A combo test for {@link TurbineTypes} that compares the behaviour of bifunctions like {@link
+ * Types#asMemberOf(DeclaredType, Element)} with javac's implementation.
+ */
+abstract class AbstractTurbineTypesBiFunctionTest<T> extends AbstractTurbineTypesTest {
+
+ final String testDescription;
+ final TypesBiFunctionInput javacInput;
+ final TypesBiFunctionInput turbineInput;
+
+ public AbstractTurbineTypesBiFunctionTest(
+ String testDescription, TypesBiFunctionInput javacInput, TypesBiFunctionInput turbineInput) {
+ this.testDescription = testDescription;
+ this.javacInput = javacInput;
+ this.turbineInput = turbineInput;
+ }
+
+ protected void test(String symbol, TypeBiFunction<T> predicate) {
+ assertWithMessage("%s = %s", javacInput.format(symbol), turbineInput.format(symbol))
+ .that(turbineInput.apply(predicate))
+ .isEqualTo(javacInput.apply(predicate));
+ }
+}
diff --git a/javatests/com/google/turbine/processing/AbstractTurbineTypesBiPredicateTest.java b/javatests/com/google/turbine/processing/AbstractTurbineTypesBiPredicateTest.java
index 6ea6e72..08891eb 100644
--- a/javatests/com/google/turbine/processing/AbstractTurbineTypesBiPredicateTest.java
+++ b/javatests/com/google/turbine/processing/AbstractTurbineTypesBiPredicateTest.java
@@ -16,8 +16,6 @@
package com.google.turbine.processing;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
@@ -25,22 +23,10 @@ import javax.lang.model.util.Types;
* A combo test for {@link TurbineTypes} that compares the behaviour of bipredicates like {@link
* Types#isSubtype(TypeMirror, TypeMirror)} with javac's implementation.
*/
-abstract class AbstractTurbineTypesBiPredicateTest extends AbstractTurbineTypesTest {
-
- final String testDescription;
- final TypesBiFunctionInput javacInput;
- final TypesBiFunctionInput turbineInput;
-
+abstract class AbstractTurbineTypesBiPredicateTest
+ extends AbstractTurbineTypesBiFunctionTest<Boolean> {
public AbstractTurbineTypesBiPredicateTest(
String testDescription, TypesBiFunctionInput javacInput, TypesBiFunctionInput turbineInput) {
- this.testDescription = testDescription;
- this.javacInput = javacInput;
- this.turbineInput = turbineInput;
- }
-
- protected void test(String symbol, TypeBiPredicate predicate) {
- assertWithMessage("%s = %s", javacInput.format(symbol), turbineInput.format(symbol))
- .that(turbineInput.apply(predicate))
- .isEqualTo(javacInput.apply(predicate));
+ super(testDescription, javacInput, turbineInput);
}
}
diff --git a/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java b/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java
index 7d8d479..02df1ec 100644
--- a/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java
+++ b/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java
@@ -31,6 +31,7 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
+import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Streams;
import com.google.turbine.binder.Binder;
import com.google.turbine.binder.Binder.BindingResult;
@@ -93,8 +94,8 @@ class AbstractTurbineTypesTest {
}
}
- protected interface TypeBiPredicate {
- boolean apply(Types types, TypeMirror a, TypeMirror b);
+ protected interface TypeBiFunction<T> {
+ T apply(Types types, TypeMirror a, TypeMirror b);
}
static class TypesBiFunctionInput {
@@ -108,8 +109,8 @@ class AbstractTurbineTypesTest {
this.rhs = rhs;
}
- boolean apply(TypeBiPredicate predicate) {
- return predicate.apply(types, lhs, rhs);
+ <T> T apply(TypeBiFunction<T> function) {
+ return function.apply(types, lhs, rhs);
}
String format(String symbol) {
@@ -232,18 +233,23 @@ class AbstractTurbineTypesTest {
"Float",
"Double",
},
- // type annotations
- {
- "@A List<@B Integer>",
- "@A List",
- "@A int @B []",
- "@A List<@A int @B []>",
- "Map.@A Entry<@B Integer, @C Number>",
- },
};
+
+ // type annotations
+ List<String> annotatedTypes = new ArrayList<>();
+ annotatedTypes.add("@A int @B []");
+ // The string representation of these types changed in JDK 19, see JDK-8281238
+ if (Runtime.version().feature() >= 19) {
+ annotatedTypes.add("@A List<@B Integer>");
+ annotatedTypes.add("@A List");
+ annotatedTypes.add("@A List<@A int @B []>");
+ annotatedTypes.add("Map.@A Entry<@B Integer, @C Number>");
+ }
+
List<String> files = new ArrayList<>();
AtomicInteger idx = new AtomicInteger();
- for (String[] group : types) {
+ for (String[] group :
+ ObjectArrays.<String[]>concat(annotatedTypes.toArray(new String[0]), types)) {
StringBuilder sb = new StringBuilder();
Joiner.on('\n')
.appendTo(
diff --git a/javatests/com/google/turbine/processing/ProcessingIntegrationTest.java b/javatests/com/google/turbine/processing/ProcessingIntegrationTest.java
index fee2c75..65c7ed5 100644
--- a/javatests/com/google/turbine/processing/ProcessingIntegrationTest.java
+++ b/javatests/com/google/turbine/processing/ProcessingIntegrationTest.java
@@ -48,6 +48,9 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.io.Writer;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Optional;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
@@ -61,6 +64,7 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
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.Test;
@@ -804,4 +808,60 @@ public class ProcessingIntegrationTest {
"C#f<U>(java.util.List<U>)U <: A#f<U>(java.util.List<U>)U ? false",
"C#f<U>(java.util.List<U>)U <: B#f<U>(java.util.List<U>)U ? false");
}
+
+ @SupportedAnnotationTypes("*")
+ public static class URIProcessor extends AbstractProcessor {
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ private boolean first = true;
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!first) {
+ return false;
+ }
+ first = false;
+ try {
+ FileObject output =
+ processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "foo", "Bar");
+ Path path = Paths.get(output.toUri());
+ processingEnv
+ .getMessager()
+ .printMessage(Diagnostic.Kind.ERROR, output.toUri() + " - " + path);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ return false;
+ }
+ }
+
+ @Test
+ public void uriProcessing() throws IOException {
+ ImmutableList<Tree.CompUnit> units =
+ parseUnit(
+ "=== T.java ===", //
+ "class T {}");
+ TurbineError e =
+ assertThrows(
+ TurbineError.class,
+ () ->
+ Binder.bind(
+ units,
+ ClassPathBinder.bindClasspath(ImmutableList.of()),
+ ProcessorInfo.create(
+ ImmutableList.of(new URIProcessor()),
+ getClass().getClassLoader(),
+ ImmutableMap.of(),
+ SourceVersion.latestSupported()),
+ TestClassPaths.TURBINE_BOOTCLASSPATH,
+ Optional.empty()));
+ assertThat(
+ e.diagnostics().stream()
+ .filter(d -> d.severity().equals(Diagnostic.Kind.ERROR))
+ .map(d -> d.message()))
+ .containsExactly("file:///foo/Bar - " + Paths.get(URI.create("file:///foo/Bar")));
+ }
}
diff --git a/javatests/com/google/turbine/processing/TurbineFilerTest.java b/javatests/com/google/turbine/processing/TurbineFilerTest.java
index 83dcc70..96c325b 100644
--- a/javatests/com/google/turbine/processing/TurbineFilerTest.java
+++ b/javatests/com/google/turbine/processing/TurbineFilerTest.java
@@ -23,7 +23,6 @@ import static org.junit.Assert.assertThrows;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
-import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import com.google.turbine.diag.SourceFile;
import java.io.FileNotFoundException;
@@ -127,8 +126,7 @@ public class TurbineFilerTest {
Collection<SourceFile> unused = filer.finishRound();
FileObject output = filer.getResource(StandardLocation.SOURCE_OUTPUT, "com.foo", "Bar.java");
- assertThat(new String(ByteStreams.toByteArray(output.openInputStream()), UTF_8))
- .isEqualTo("hello");
+ assertThat(new String(output.openInputStream().readAllBytes(), UTF_8)).isEqualTo("hello");
assertThat(output.getCharContent(false).toString()).isEqualTo("hello");
assertThat(CharStreams.toString(output.openReader(true))).isEqualTo("hello");
}
@@ -142,8 +140,7 @@ public class TurbineFilerTest {
Collection<SourceFile> unused = filer.finishRound();
FileObject output = filer.getResource(StandardLocation.CLASS_OUTPUT, "com.foo", "Baz.class");
- assertThat(new String(ByteStreams.toByteArray(output.openInputStream()), UTF_8))
- .isEqualTo("goodbye");
+ assertThat(new String(output.openInputStream().readAllBytes(), UTF_8)).isEqualTo("goodbye");
assertThat(output.getCharContent(false).toString()).isEqualTo("goodbye");
assertThat(CharStreams.toString(output.openReader(true))).isEqualTo("goodbye");
}
@@ -153,7 +150,7 @@ public class TurbineFilerTest {
FileObject resource =
filer.getResource(StandardLocation.ANNOTATION_PROCESSOR_PATH, "META-INF", "MANIFEST.MF");
- assertThat(new String(ByteStreams.toByteArray(resource.openInputStream()), UTF_8))
+ assertThat(new String(resource.openInputStream().readAllBytes(), UTF_8))
.contains("Manifest-Version:");
assertThat(CharStreams.toString(resource.openReader(true))).contains("Manifest-Version:");
assertThat(resource.getCharContent(false).toString()).contains("Manifest-Version:");
diff --git a/javatests/com/google/turbine/processing/TurbineTypesAsMemberOfTest.java b/javatests/com/google/turbine/processing/TurbineTypesAsMemberOfTest.java
new file mode 100644
index 0000000..1a368c9
--- /dev/null
+++ b/javatests/com/google/turbine/processing/TurbineTypesAsMemberOfTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022 Google Inc. All Rights Reserved.
+ *
+ * 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.turbine.processing;
+
+import static com.google.common.truth.TruthJUnit.assume;
+import static org.junit.Assert.assertThrows;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TurbineTypesAsMemberOfTest extends AbstractTurbineTypesBiFunctionTest<String> {
+
+ @Parameters(name = "{index}: {0}")
+ public static Iterable<Object[]> parameters() throws Exception {
+ return binaryParameters();
+ }
+
+ public TurbineTypesAsMemberOfTest(
+ String testDescription, TypesBiFunctionInput javacInput, TypesBiFunctionInput turbineInput) {
+ super(testDescription, javacInput, turbineInput);
+ }
+
+ @Test
+ public void asMemberOf() {
+ assume().that(javacInput.lhs.getKind()).isEqualTo(TypeKind.DECLARED);
+ assume().that(javacInput.rhs.getKind()).isAnyOf(TypeKind.TYPEVAR, TypeKind.DECLARED);
+
+ TypeBiFunction<String> predicate =
+ (types, lhs, rhs) -> types.asMemberOf((DeclaredType) lhs, element(rhs)).toString();
+
+ try {
+ String unused = javacInput.apply(predicate);
+ } catch (IllegalArgumentException e) {
+ assertThrows(
+ turbineInput.format("asMemberOf"),
+ IllegalArgumentException.class,
+ () -> turbineInput.apply(predicate));
+ return;
+ }
+
+ test("asMemberOf", predicate);
+ }
+
+ private static Element element(TypeMirror rhs) {
+ switch (rhs.getKind()) {
+ case TYPEVAR:
+ return ((TypeVariable) rhs).asElement();
+ case DECLARED:
+ return ((DeclaredType) rhs).asElement();
+ default:
+ throw new AssertionError(rhs.getKind());
+ }
+ }
+}
diff --git a/javatests/com/google/turbine/testing/TestResources.java b/javatests/com/google/turbine/testing/TestResources.java
index 86c7632..6c456ab 100644
--- a/javatests/com/google/turbine/testing/TestResources.java
+++ b/javatests/com/google/turbine/testing/TestResources.java
@@ -19,7 +19,6 @@ package com.google.turbine.testing;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
-import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
@@ -32,7 +31,7 @@ public final class TestResources {
public static byte[] getResourceBytes(Class<?> clazz, String resource) {
try (InputStream is = requireNonNull(clazz.getResourceAsStream(resource), resource)) {
- return ByteStreams.toByteArray(is);
+ return is.readAllBytes();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/javatests/com/google/turbine/zip/ZipTest.java b/javatests/com/google/turbine/zip/ZipTest.java
index e9dfc44..b64531a 100644
--- a/javatests/com/google/turbine/zip/ZipTest.java
+++ b/javatests/com/google/turbine/zip/ZipTest.java
@@ -22,9 +22,10 @@ import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableMap;
import com.google.common.hash.Hashing;
-import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
@@ -38,6 +39,7 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.junit.Rule;
import org.junit.Test;
@@ -113,9 +115,7 @@ public class ZipTest {
JarEntry je = entries.nextElement();
result.put(
je.getName(),
- Hashing.goodFastHash(128)
- .hashBytes(ByteStreams.toByteArray(jf.getInputStream(je)))
- .padToLong());
+ Hashing.goodFastHash(128).hashBytes(jf.getInputStream(je).readAllBytes()).padToLong());
}
}
return result;
@@ -164,4 +164,164 @@ public class ZipTest {
ZipException e = assertThrows(ZipException.class, () -> actual(path));
assertThat(e).hasMessageThat().isEqualTo("zip file comment length was 33, expected 17");
}
+
+ // Create a zip64 archive with an extensible data sector
+ @Test
+ public void zip64extension() throws IOException {
+
+ ByteBuffer buf = ByteBuffer.allocate(1000);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ // The jar has a single entry named 'hello', with the value 'world'
+ byte[] name = "hello".getBytes(UTF_8);
+ byte[] value = "world".getBytes(UTF_8);
+ int crc = Hashing.crc32().hashBytes(value).asInt();
+
+ int localHeaderPosition = buf.position();
+
+ // local file header signature 4 bytes (0x04034b50)
+ buf.putInt((int) ZipFile.LOCSIG);
+ // version needed to extract 2 bytes
+ buf.putShort((short) 0);
+ // general purpose bit flag 2 bytes
+ buf.putShort((short) 0);
+ // compression method 2 bytes
+ buf.putShort((short) 0);
+ // last mod file time 2 bytes
+ buf.putShort((short) 0);
+ // last mod file date 2 bytes
+ buf.putShort((short) 0);
+ // crc-32 4 bytes
+ buf.putInt(crc);
+ // compressed size 4 bytes
+ buf.putInt(value.length);
+ // uncompressed size 4 bytes
+ buf.putInt(value.length);
+ // file name length 2 bytes
+ buf.putShort((short) name.length);
+ // extra field length 2 bytes
+ buf.putShort((short) 0);
+ // file name (variable size)
+ buf.put(name);
+ // extra field (variable size)
+ // file data
+ buf.put(value);
+
+ int centralDirectoryPosition = buf.position();
+
+ // central file header signature 4 bytes (0x02014b50)
+ buf.putInt((int) ZipFile.CENSIG);
+ // version made by 2 bytes
+ buf.putShort((short) 0);
+ // version needed to extract 2 bytes
+ buf.putShort((short) 0);
+ // general purpose bit flag 2 bytes
+ buf.putShort((short) 0);
+ // compression method 2 bytes
+ buf.putShort((short) 0);
+ // last mod file time 2 bytes
+ buf.putShort((short) 0);
+ // last mod file date 2 bytes
+ buf.putShort((short) 0);
+ // crc-32 4 bytes
+ buf.putInt(crc);
+ // compressed size 4 bytes
+ buf.putInt(value.length);
+ // uncompressed size 4 bytes
+ buf.putInt(value.length);
+ // file name length 2 bytes
+ buf.putShort((short) name.length);
+ // extra field length 2 bytes
+ buf.putShort((short) 0);
+ // file comment length 2 bytes
+ buf.putShort((short) 0);
+ // disk number start 2 bytes
+ buf.putShort((short) 0);
+ // internal file attributes 2 bytes
+ buf.putShort((short) 0);
+ // external file attributes 4 bytes
+ buf.putInt(0);
+ // relative offset of local header 4 bytes
+ buf.putInt(localHeaderPosition);
+ // file name (variable size)
+ buf.put(name);
+
+ int centralDirectorySize = buf.position() - centralDirectoryPosition;
+ int zip64eocdPosition = buf.position();
+
+ // zip64 end of central dir
+ // signature 4 bytes (0x06064b50)
+ buf.putInt(Zip.ZIP64_ENDSIG);
+ // size of zip64 end of central
+ // directory record 8 bytes
+ buf.putLong(Zip.ZIP64_ENDSIZ + 5);
+ // version made by 2 bytes
+ buf.putShort((short) 0);
+ // version needed to extract 2 bytes
+ buf.putShort((short) 0);
+ // number of this disk 4 bytes
+ buf.putInt(0);
+ // number of the disk with the
+ // start of the central directory 4 bytes
+ buf.putInt(0);
+ // total number of entries in the
+ // central directory on this disk 8 bytes
+ buf.putLong(1);
+ // total number of entries in the
+ // central directory 8 bytes
+ buf.putLong(1);
+ // size of the central directory 8 bytes
+ buf.putLong(centralDirectorySize);
+ // offset of start of central
+ // directory with respect to
+ // offset of start of central
+ // the starting disk number 8 bytes
+ buf.putLong(centralDirectoryPosition);
+ // zip64 extensible data sector (variable size)
+ buf.put((byte) 3);
+ buf.putInt(42);
+
+ // zip64 end of central dir locator
+ // signature 4 bytes (0x07064b50)
+ buf.putInt(Zip.ZIP64_LOCSIG);
+ // number of the disk with the
+ // start of the zip64 end of
+ // central directory 4 bytes
+ buf.putInt(0);
+ // relative offset of the zip64
+ // end of central directory record 8 bytes
+ buf.putLong(zip64eocdPosition);
+ // total number of disks 4 bytes
+ buf.putInt(0);
+
+ // end of central dir signature 4 bytes (0x06054b50)
+ buf.putInt((int) ZipFile.ENDSIG);
+ // number of this disk 2 bytes
+ buf.putShort((short) 0);
+ // number of the disk with the
+ // start of the central directory 2 bytes
+ buf.putShort((short) 0);
+ // total number of entries in the
+ // central directory on this disk 2 bytes
+ buf.putShort((short) 1);
+ // total number of entries in
+ // the central directory 2 bytes
+ buf.putShort((short) Zip.ZIP64_MAGICCOUNT);
+ // size of the central directory 4 bytes
+ buf.putInt(centralDirectorySize);
+ // offset of start of central
+ // directory with respect to
+ // the starting disk number 4 bytes
+ buf.putInt(centralDirectoryPosition);
+ // .ZIP file comment length 2 bytes
+ buf.putShort((short) 0);
+ // .ZIP file comment (variable size)
+
+ byte[] bytes = new byte[buf.position()];
+ buf.rewind();
+ buf.get(bytes);
+ Path path = temporaryFolder.newFile("test.jar").toPath();
+ Files.write(path, bytes);
+ assertThat(actual(path)).isEqualTo(expected(path));
+ }
}
diff --git a/pom.xml b/pom.xml
index b007e74..a2bf088 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,14 +30,15 @@
<url>https://github.com/google/turbine</url>
<properties>
- <asm.version>9.2</asm.version>
+ <asm.version>9.4</asm.version>
<guava.version>31.0.1-jre</guava.version>
- <errorprone.version>2.11.0</errorprone.version>
+ <errorprone.version>2.16</errorprone.version>
<maven-javadoc-plugin.version>3.3.1</maven-javadoc-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<protobuf.version>3.19.2</protobuf.version>
<grpc.version>1.43.2</grpc.version>
+ <native.maven.plugin.version>0.9.11</native.maven.plugin.version>
</properties>
<organization>
@@ -333,5 +334,44 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>native</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.graalvm.buildtools</groupId>
+ <artifactId>native-maven-plugin</artifactId>
+ <version>${native.maven.plugin.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>build-native</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ <execution>
+ <id>test-native</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <phase>test</phase>
+ </execution>
+ </executions>
+ <configuration>
+ <imageName>turbine</imageName>
+ <mainClass>com.google.turbine.main.Main</mainClass>
+ <classpath>
+ <param>${project.build.directory}/${project.artifactId}-${project.version}-all-deps.jar</param>
+ </classpath>
+ <buildArgs>
+ <buildArg>--no-fallback</buildArg>
+ </buildArgs>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>
</project>