Merge remote-tracking branch 'aosp/upstream-master' into turbine
* aosp/upstream-master:
Don't hang if we run out of input while seeking for matching `)` or `}`
Improve diagnostics for unresolvable fields inside constant expressions
Don't crash on multiple visibility modifiers
Fix a crash reporting missing symbols in constant expressions
Don't report an error if a static type import cannot be resolved
Make missing symbol diagnostics more consistent
Migrate off jsr305 annotations
Improve diagnostics for missing enclosing classes
Remove unused options
Bug: 110098902
Test: m checkbuild
Test: turbine framework.jar with syntax error introduced
Change-Id: I865e2e2ca466e635fa7281c25b311d3da904646c
diff --git a/java/com/google/turbine/binder/Binder.java b/java/com/google/turbine/binder/Binder.java
index cbafdef..d4b151f 100644
--- a/java/com/google/turbine/binder/Binder.java
+++ b/java/com/google/turbine/binder/Binder.java
@@ -31,6 +31,7 @@
import com.google.turbine.binder.bound.PackageSourceBoundModule;
import com.google.turbine.binder.bound.SourceBoundClass;
import com.google.turbine.binder.bound.SourceHeaderBoundClass;
+import com.google.turbine.binder.bound.SourceModuleInfo;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
@@ -112,7 +113,7 @@
canonicalizeTypes(
syms, tenv, CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv));
- ImmutableList<ModuleInfo> boundModules =
+ ImmutableList<SourceModuleInfo> boundModules =
bindModules(
modules,
CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv),
@@ -244,7 +245,7 @@
return builder.build();
}
- private static ImmutableList<ModuleInfo> bindModules(
+ private static ImmutableList<SourceModuleInfo> bindModules(
SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules,
CompoundEnv<ClassSymbol, TypeBoundClass> env,
CompoundEnv<ModuleSymbol, ModuleInfo> moduleEnv,
@@ -274,7 +275,7 @@
return null;
}
});
- ImmutableList.Builder<ModuleInfo> bound = ImmutableList.builder();
+ ImmutableList.Builder<SourceModuleInfo> bound = ImmutableList.builder();
for (PackageSourceBoundModule module : modules.asMap().values()) {
bound.add(ModuleBinder.bind(module, env, moduleEnv, moduleVersion));
}
@@ -378,12 +379,12 @@
/** The result of binding: bound nodes for sources in the compilation, and the classpath. */
public static class BindingResult {
private final ImmutableMap<ClassSymbol, SourceTypeBoundClass> units;
- private final ImmutableList<ModuleInfo> modules;
+ private final ImmutableList<SourceModuleInfo> modules;
private final CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv;
public BindingResult(
ImmutableMap<ClassSymbol, SourceTypeBoundClass> units,
- ImmutableList<ModuleInfo> modules,
+ ImmutableList<SourceModuleInfo> modules,
CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
this.units = units;
this.modules = modules;
@@ -395,7 +396,7 @@
return units;
}
- public ImmutableList<ModuleInfo> modules() {
+ public ImmutableList<SourceModuleInfo> modules() {
return modules;
}
diff --git a/java/com/google/turbine/binder/CanonicalTypeBinder.java b/java/com/google/turbine/binder/CanonicalTypeBinder.java
index 2ff56a3..20db0d7 100644
--- a/java/com/google/turbine/binder/CanonicalTypeBinder.java
+++ b/java/com/google/turbine/binder/CanonicalTypeBinder.java
@@ -27,6 +27,7 @@
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
+import com.google.turbine.diag.SourceFile;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.types.Canonicalize;
@@ -41,16 +42,17 @@
ClassSymbol sym, SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) {
ClassTy superClassType = null;
if (base.superClassType() != null) {
- superClassType = Canonicalize.canonicalizeClassTy(env, base.owner(), base.superClassType());
+ superClassType =
+ Canonicalize.canonicalizeClassTy(base.source(), env, base.owner(), base.superClassType());
}
ImmutableList.Builder<ClassTy> interfaceTypes = ImmutableList.builder();
for (ClassTy i : base.interfaceTypes()) {
- interfaceTypes.add(Canonicalize.canonicalizeClassTy(env, base.owner(), i));
+ interfaceTypes.add(Canonicalize.canonicalizeClassTy(base.source(), env, base.owner(), i));
}
ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
- typeParameters(env, sym, base.typeParameterTypes());
- ImmutableList<MethodInfo> methods = methods(env, sym, base.methods());
- ImmutableList<FieldInfo> fields = fields(env, sym, base.fields());
+ typeParameters(base.source(), env, sym, base.typeParameterTypes());
+ ImmutableList<MethodInfo> methods = methods(base.source(), env, sym, base.methods());
+ ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields());
return new SourceTypeBoundClass(
interfaceTypes.build(),
superClassType,
@@ -71,13 +73,16 @@
}
private static ImmutableList<FieldInfo> fields(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<FieldInfo> fields) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ImmutableList<FieldInfo> fields) {
ImmutableList.Builder<FieldInfo> result = ImmutableList.builder();
for (FieldInfo base : fields) {
result.add(
new FieldInfo(
base.sym(),
- Canonicalize.canonicalize(env, sym, base.type()),
+ Canonicalize.canonicalize(source, env, sym, base.type()),
base.access(),
base.annotations(),
base.decl(),
@@ -87,16 +92,19 @@
}
private static ImmutableList<MethodInfo> methods(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<MethodInfo> methods) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ImmutableList<MethodInfo> methods) {
ImmutableList.Builder<MethodInfo> result = ImmutableList.builder();
for (MethodInfo base : methods) {
- ImmutableMap<TyVarSymbol, TyVarInfo> tps = typeParameters(env, sym, base.tyParams());
- Type ret = Canonicalize.canonicalize(env, sym, base.returnType());
+ ImmutableMap<TyVarSymbol, TyVarInfo> tps = typeParameters(source, env, sym, base.tyParams());
+ Type ret = Canonicalize.canonicalize(source, env, sym, base.returnType());
ImmutableList.Builder<ParamInfo> parameters = ImmutableList.builder();
for (ParamInfo parameter : base.parameters()) {
- parameters.add(param(env, sym, parameter));
+ parameters.add(param(source, env, sym, parameter));
}
- ImmutableList<Type> exceptions = canonicalizeList(env, sym, base.exceptions());
+ ImmutableList<Type> exceptions = canonicalizeList(source, env, sym, base.exceptions());
result.add(
new MethodInfo(
base.sym(),
@@ -108,40 +116,47 @@
base.defaultValue(),
base.decl(),
base.annotations(),
- base.receiver() != null ? param(env, sym, base.receiver()) : null));
+ base.receiver() != null ? param(source, env, sym, base.receiver()) : null));
}
return result.build();
}
private static ParamInfo param(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base) {
return new ParamInfo(
- Canonicalize.canonicalize(env, sym, base.type()),
+ Canonicalize.canonicalize(source, env, sym, base.type()),
base.name(),
base.annotations(),
base.access());
}
private static ImmutableMap<TyVarSymbol, TyVarInfo> typeParameters(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Map<TyVarSymbol, TyVarInfo> tps) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ Map<TyVarSymbol, TyVarInfo> tps) {
ImmutableMap.Builder<TyVarSymbol, TyVarInfo> result = ImmutableMap.builder();
for (Map.Entry<TyVarSymbol, TyVarInfo> e : tps.entrySet()) {
TyVarInfo info = e.getValue();
Type superClassBound = null;
if (info.superClassBound() != null) {
- superClassBound = Canonicalize.canonicalize(env, sym, info.superClassBound());
+ superClassBound = Canonicalize.canonicalize(source, env, sym, info.superClassBound());
}
- ImmutableList<Type> interfaceBounds = canonicalizeList(env, sym, info.interfaceBounds());
+ ImmutableList<Type> interfaceBounds =
+ canonicalizeList(source, env, sym, info.interfaceBounds());
result.put(e.getKey(), new TyVarInfo(superClassBound, interfaceBounds, info.annotations()));
}
return result.build();
}
private static ImmutableList<Type> canonicalizeList(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<Type> types) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ImmutableList<Type> types) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type type : types) {
- result.add(Canonicalize.canonicalize(env, sym, type));
+ result.add(Canonicalize.canonicalize(source, env, sym, type));
}
return result.build();
}
diff --git a/java/com/google/turbine/binder/ConstBinder.java b/java/com/google/turbine/binder/ConstBinder.java
index 4cb40a2..4b48dd3 100644
--- a/java/com/google/turbine/binder/ConstBinder.java
+++ b/java/com/google/turbine/binder/ConstBinder.java
@@ -182,7 +182,7 @@
return null;
}
EnumConstantValue enumValue = (EnumConstantValue) value;
- if (!enumValue.sym().owner().toString().equals("java/lang/annotation/RetentionPolicy")) {
+ if (!enumValue.sym().owner().binaryName().equals("java/lang/annotation/RetentionPolicy")) {
return null;
}
return RetentionPolicy.valueOf(enumValue.sym().name());
diff --git a/java/com/google/turbine/binder/ConstEvaluator.java b/java/com/google/turbine/binder/ConstEvaluator.java
index d661fb9..7e79919 100644
--- a/java/com/google/turbine/binder/ConstEvaluator.java
+++ b/java/com/google/turbine/binder/ConstEvaluator.java
@@ -199,18 +199,24 @@
}
LookupResult result = scope.lookup(new LookupKey(flat));
if (result == null) {
- throw error(classTy.position(), ErrorKind.SYMBOL_NOT_FOUND, flat.peekFirst());
+ throw error(classTy.position(), ErrorKind.CANNOT_RESOLVE, flat.peekFirst());
}
ClassSymbol classSym = (ClassSymbol) result.sym();
for (String bit : result.remaining()) {
- classSym = Resolve.resolve(env, origin, classSym, bit);
- if (classSym == null) {
- throw error(classTy.position(), ErrorKind.SYMBOL_NOT_FOUND, bit);
- }
+ classSym = resolveNext(classTy.position(), classSym, bit);
}
return classSym;
}
+ private ClassSymbol resolveNext(int position, ClassSymbol sym, String bit) {
+ ClassSymbol next = Resolve.resolve(env, origin, sym, bit);
+ if (next == null) {
+ throw error(
+ position, ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(sym.binaryName() + '$' + bit));
+ }
+ return next;
+ }
+
/** Evaluates a reference to another constant variable. */
Const evalConstVar(ConstVarName t) {
FieldInfo field = resolveField(t);
@@ -256,7 +262,10 @@
}
return field;
}
- return null;
+ throw error(
+ t.position(),
+ ErrorKind.CANNOT_RESOLVE,
+ String.format("field %s", Iterables.getLast(t.name())));
}
private FieldInfo resolveQualifiedField(ConstVarName t) {
@@ -267,6 +276,10 @@
if (result == null) {
return null;
}
+ if (result.remaining().isEmpty()) {
+ // unexpectedly resolved qualified name to a type
+ return null;
+ }
ClassSymbol sym = (ClassSymbol) result.sym();
for (int i = 0; i < result.remaining().size() - 1; i++) {
sym = Resolve.resolve(env, sym, sym, result.remaining().get(i));
@@ -984,7 +997,12 @@
}
public Const.Value evalFieldInitializer(Expression expression, Type type) {
- Const value = eval(expression);
+ Const value;
+ try {
+ value = eval(expression);
+ } catch (TurbineError error) {
+ return null;
+ }
if (value == null || value.kind() != Const.Kind.PRIMITIVE) {
return null;
}
diff --git a/java/com/google/turbine/binder/CtSymClassBinder.java b/java/com/google/turbine/binder/CtSymClassBinder.java
index 0d71b8d..5988ac5 100644
--- a/java/com/google/turbine/binder/CtSymClassBinder.java
+++ b/java/com/google/turbine/binder/CtSymClassBinder.java
@@ -34,7 +34,7 @@
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Constructs a platform {@link ClassPath} from the current JDK's ct.sym file. */
public class CtSymClassBinder {
diff --git a/java/com/google/turbine/binder/HierarchyBinder.java b/java/com/google/turbine/binder/HierarchyBinder.java
index c3e82ba..2545c17 100644
--- a/java/com/google/turbine/binder/HierarchyBinder.java
+++ b/java/com/google/turbine/binder/HierarchyBinder.java
@@ -31,6 +31,7 @@
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.tree.Tree;
+import com.google.turbine.tree.Tree.ClassTy;
import java.util.ArrayDeque;
/** Type hierarchy binding. */
@@ -116,24 +117,31 @@
// Resolve the base symbol in the qualified name.
LookupResult result = lookup(ty, new LookupKey(flat));
if (result == null) {
- throw TurbineError.format(base.source(), ty.position(), ErrorKind.SYMBOL_NOT_FOUND, ty);
+ throw TurbineError.format(base.source(), ty.position(), ErrorKind.CANNOT_RESOLVE, ty);
}
// Resolve pieces in the qualified name referring to member types.
// This needs to consider member type declarations inherited from supertypes and interfaces.
ClassSymbol sym = (ClassSymbol) result.sym();
for (String bit : result.remaining()) {
- try {
- sym = Resolve.resolve(env, origin, sym, bit);
- } catch (LazyBindingError e) {
- throw error(ty.position(), ErrorKind.CYCLIC_HIERARCHY, e.getMessage());
- }
- if (sym == null) {
- throw error(ty.position(), ErrorKind.SYMBOL_NOT_FOUND, bit);
- }
+ sym = resolveNext(ty, sym, bit);
}
return sym;
}
+ private ClassSymbol resolveNext(ClassTy ty, ClassSymbol sym, String bit) {
+ ClassSymbol next;
+ try {
+ next = Resolve.resolve(env, origin, sym, bit);
+ } catch (LazyBindingError e) {
+ throw error(ty.position(), ErrorKind.CYCLIC_HIERARCHY, e.getMessage());
+ }
+ if (next == null) {
+ throw error(
+ ty.position(), ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(sym.binaryName() + '$' + bit));
+ }
+ return next;
+ }
+
/** Resolve a qualified type name to a symbol. */
private LookupResult lookup(Tree tree, LookupKey lookup) {
// Handle any lexically enclosing class declarations (if we're binding a member class).
diff --git a/java/com/google/turbine/binder/JimageClassBinder.java b/java/com/google/turbine/binder/JimageClassBinder.java
index 40be3a3..5afc5d8 100644
--- a/java/com/google/turbine/binder/JimageClassBinder.java
+++ b/java/com/google/turbine/binder/JimageClassBinder.java
@@ -48,7 +48,7 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Constructs a platform {@link ClassPath} from the current JDK's jimage file using jrtfs. */
public class JimageClassBinder {
diff --git a/java/com/google/turbine/binder/ModuleBinder.java b/java/com/google/turbine/binder/ModuleBinder.java
index 23c9624..312ec45 100644
--- a/java/com/google/turbine/binder/ModuleBinder.java
+++ b/java/com/google/turbine/binder/ModuleBinder.java
@@ -29,6 +29,7 @@
import com.google.turbine.binder.bound.ModuleInfo.RequireInfo;
import com.google.turbine.binder.bound.ModuleInfo.UseInfo;
import com.google.turbine.binder.bound.PackageSourceBoundModule;
+import com.google.turbine.binder.bound.SourceModuleInfo;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.env.CompoundEnv;
import com.google.turbine.binder.env.Env;
@@ -54,7 +55,7 @@
/** Binding pass for modules. */
public class ModuleBinder {
- public static ModuleInfo bind(
+ public static SourceModuleInfo bind(
PackageSourceBoundModule module,
CompoundEnv<ClassSymbol, TypeBoundClass> env,
Env<ModuleSymbol, ModuleInfo> moduleEnv,
@@ -80,7 +81,7 @@
this.scope = module.scope().toScope(Resolve.resolveFunction(env, /* origin= */ null));
}
- private ModuleInfo bind() {
+ private SourceModuleInfo bind() {
// bind annotations; constant fields are already bound
ConstEvaluator constEvaluator =
new ConstEvaluator(
@@ -146,7 +147,7 @@
.addAll(requires.build());
}
- return new ModuleInfo(
+ return new SourceModuleInfo(
module.module().moduleName(),
moduleVersion.orNull(),
flags,
@@ -155,7 +156,8 @@
exports.build(),
opens.build(),
uses.build(),
- provides.build());
+ provides.build(),
+ module.source());
}
private RequireInfo bindRequires(ModRequires directive) {
@@ -204,13 +206,15 @@
LookupKey key = new LookupKey(simpleNames);
LookupResult result = scope.lookup(key);
if (result == null) {
- throw error(ErrorKind.SYMBOL_NOT_FOUND, pos, Joiner.on('.').join(simpleNames));
+ throw error(
+ ErrorKind.SYMBOL_NOT_FOUND, pos, new ClassSymbol(Joiner.on('/').join(simpleNames)));
}
ClassSymbol sym = (ClassSymbol) result.sym();
for (String name : result.remaining()) {
sym = Resolve.resolve(env, /* origin= */ null, sym, name);
if (sym == null) {
- throw error(ErrorKind.SYMBOL_NOT_FOUND, pos, name);
+ throw error(
+ ErrorKind.SYMBOL_NOT_FOUND, pos, new ClassSymbol(sym.binaryName() + '$' + name));
}
}
return sym;
diff --git a/java/com/google/turbine/binder/Resolve.java b/java/com/google/turbine/binder/Resolve.java
index d06dbc1..d722373 100644
--- a/java/com/google/turbine/binder/Resolve.java
+++ b/java/com/google/turbine/binder/Resolve.java
@@ -27,11 +27,7 @@
import com.google.turbine.binder.env.LazyEnv.LazyBindingError;
import com.google.turbine.binder.lookup.CanonicalSymbolResolver;
import com.google.turbine.binder.lookup.ImportScope.ResolveFunction;
-import com.google.turbine.binder.lookup.LookupResult;
import com.google.turbine.binder.sym.ClassSymbol;
-import com.google.turbine.diag.SourceFile;
-import com.google.turbine.diag.TurbineError;
-import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.TurbineVisibility;
import java.util.Objects;
@@ -104,18 +100,6 @@
}
@Override
- public ClassSymbol resolve(SourceFile source, int position, LookupResult result) {
- ClassSymbol sym = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
- sym = resolveOne(sym, bit);
- if (sym == null) {
- throw TurbineError.format(source, position, ErrorKind.SYMBOL_NOT_FOUND, bit);
- }
- }
- return sym;
- }
-
- @Override
public ClassSymbol resolveOne(ClassSymbol sym, String bit) {
BoundClass ci = env.get(sym);
if (ci == null) {
diff --git a/java/com/google/turbine/binder/TypeBinder.java b/java/com/google/turbine/binder/TypeBinder.java
index 964958b..e0546ac 100644
--- a/java/com/google/turbine/binder/TypeBinder.java
+++ b/java/com/google/turbine/binder/TypeBinder.java
@@ -560,14 +560,11 @@
for (Tree.Anno tree : trees) {
LookupResult lookupResult = scope.lookup(new LookupKey(tree.name()));
if (lookupResult == null) {
- throw error(tree.position(), ErrorKind.SYMBOL_NOT_FOUND, Joiner.on('.').join(tree.name()));
+ throw error(tree.position(), ErrorKind.CANNOT_RESOLVE, Joiner.on('.').join(tree.name()));
}
ClassSymbol sym = (ClassSymbol) lookupResult.sym();
for (String name : lookupResult.remaining()) {
- sym = Resolve.resolve(env, owner, sym, name);
- if (sym == null) {
- throw error(tree.position(), ErrorKind.SYMBOL_NOT_FOUND, name);
- }
+ sym = resolveNext(tree.position(), sym, name);
}
if (env.get(sym).kind() != TurbineTyKind.ANNOTATION) {
throw error(tree.position(), ErrorKind.NOT_AN_ANNOTATION, sym);
@@ -577,6 +574,15 @@
return result.build();
}
+ private ClassSymbol resolveNext(int position, ClassSymbol sym, String bit) {
+ ClassSymbol next = Resolve.resolve(env, owner, sym, bit);
+ if (next == null) {
+ throw error(
+ position, ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(sym.binaryName() + '$' + bit));
+ }
+ return next;
+ }
+
private ImmutableList<Type> bindTyArgs(CompoundScope scope, ImmutableList<Tree.Type> targs) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Tree.Type ty : targs) {
@@ -627,7 +633,7 @@
// resolve the prefix to a symbol
LookupResult result = scope.lookup(new LookupKey(names));
if (result == null || result.sym() == null) {
- throw error(t.position(), ErrorKind.SYMBOL_NOT_FOUND, t);
+ throw error(t.position(), ErrorKind.CANNOT_RESOLVE, t);
}
Symbol sym = result.sym();
int annoIdx = flat.size() - result.remaining().size() - 1;
@@ -660,10 +666,8 @@
sym, bindTyArgs(scope, flat.get(idx++).tyargs()), annotations));
for (; idx < flat.size(); idx++) {
Tree.ClassTy curr = flat.get(idx);
- sym = Resolve.resolve(env, owner, sym, curr.name());
- if (sym == null) {
- throw error(curr.position(), ErrorKind.CANNOT_RESOLVE, curr.name());
- }
+ sym = resolveNext(curr.position(), sym, curr.name());
+
annotations = bindAnnotations(scope, curr.annos());
classes.add(
new Type.ClassTy.SimpleClassTy(sym, bindTyArgs(scope, curr.tyargs()), annotations));
diff --git a/java/com/google/turbine/binder/bound/BoundClass.java b/java/com/google/turbine/binder/bound/BoundClass.java
index ad26af7..61dee0f 100644
--- a/java/com/google/turbine/binder/bound/BoundClass.java
+++ b/java/com/google/turbine/binder/bound/BoundClass.java
@@ -19,7 +19,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.model.TurbineTyKind;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* The initial bound tree representation.
diff --git a/java/com/google/turbine/binder/bound/ModuleInfo.java b/java/com/google/turbine/binder/bound/ModuleInfo.java
index 9afd474..f21213b 100644
--- a/java/com/google/turbine/binder/bound/ModuleInfo.java
+++ b/java/com/google/turbine/binder/bound/ModuleInfo.java
@@ -19,7 +19,7 @@
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.type.AnnoInfo;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A bound module declaration (see JLS §7.7). */
public class ModuleInfo {
diff --git a/java/com/google/turbine/binder/bound/SourceModuleInfo.java b/java/com/google/turbine/binder/bound/SourceModuleInfo.java
new file mode 100644
index 0000000..1163e9f
--- /dev/null
+++ b/java/com/google/turbine/binder/bound/SourceModuleInfo.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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.binder.bound;
+
+import com.google.common.collect.ImmutableList;
+import com.google.turbine.binder.bound.ModuleInfo.ExportInfo;
+import com.google.turbine.binder.bound.ModuleInfo.OpenInfo;
+import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo;
+import com.google.turbine.binder.bound.ModuleInfo.RequireInfo;
+import com.google.turbine.binder.bound.ModuleInfo.UseInfo;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.type.AnnoInfo;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/** A {@link ModuleInfo} that corresponds to a source file being compiled. */
+public class SourceModuleInfo extends ModuleInfo {
+
+ private final SourceFile source;
+
+ public SourceModuleInfo(
+ String name,
+ @Nullable String version,
+ int flags,
+ ImmutableList<AnnoInfo> annos,
+ ImmutableList<RequireInfo> requires,
+ ImmutableList<ExportInfo> exports,
+ ImmutableList<OpenInfo> opens,
+ ImmutableList<UseInfo> uses,
+ ImmutableList<ProvideInfo> provides,
+ SourceFile source) {
+ super(name, version, flags, annos, requires, exports, opens, uses, provides);
+ this.source = source;
+ }
+
+ public SourceFile source() {
+ return source;
+ }
+}
diff --git a/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java b/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java
index 73f2832..b44614c 100644
--- a/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java
+++ b/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java
@@ -29,7 +29,7 @@
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A HeaderBoundClass for classes compiled from source. */
public class SourceTypeBoundClass implements TypeBoundClass {
diff --git a/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java b/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
index 76a06e5..cfab044 100644
--- a/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
+++ b/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
@@ -53,7 +53,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.function.Function;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A bound class backed by a class file.
@@ -83,7 +83,7 @@
new Supplier<ClassFile>() {
@Override
public ClassFile get() {
- ClassFile cf = ClassReader.read(jarFile + "!" + sym, bytes.get());
+ ClassFile cf = ClassReader.read(jarFile + "!" + sym.binaryName(), bytes.get());
verify(
cf.name().equals(sym.binaryName()),
"expected class data for %s, saw %s instead",
diff --git a/java/com/google/turbine/binder/env/CompoundEnv.java b/java/com/google/turbine/binder/env/CompoundEnv.java
index 43ce768..9b216e3 100644
--- a/java/com/google/turbine/binder/env/CompoundEnv.java
+++ b/java/com/google/turbine/binder/env/CompoundEnv.java
@@ -19,7 +19,7 @@
import static java.util.Objects.requireNonNull;
import com.google.turbine.binder.sym.Symbol;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** An {@link Env} that chains two existing envs together. */
public class CompoundEnv<S extends Symbol, V> implements Env<S, V> {
diff --git a/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java b/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java
index 64d7c10..1e6eee1 100644
--- a/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java
+++ b/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java
@@ -17,17 +17,9 @@
package com.google.turbine.binder.lookup;
import com.google.turbine.binder.sym.ClassSymbol;
-import com.google.turbine.diag.SourceFile;
/** Canonical type resolution. Breaks a circular dependency between binding and import handling. */
public interface CanonicalSymbolResolver extends ImportScope.ResolveFunction {
- /**
- * Resolves a type by canonical name (member types must be qualified by the type that declares
- * them, not by types that are inherited into).
- */
- @Override
- ClassSymbol resolve(SourceFile source, int position, LookupResult result);
-
/** Resolves a single member type of the given symbol by canonical name. */
@Override
ClassSymbol resolveOne(ClassSymbol sym, String bit);
diff --git a/java/com/google/turbine/binder/lookup/CompoundScope.java b/java/com/google/turbine/binder/lookup/CompoundScope.java
index a14eb05..11309bf 100644
--- a/java/com/google/turbine/binder/lookup/CompoundScope.java
+++ b/java/com/google/turbine/binder/lookup/CompoundScope.java
@@ -18,7 +18,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A {@link Scope} that chains other scopes together. */
public class CompoundScope implements Scope {
diff --git a/java/com/google/turbine/binder/lookup/CompoundTopLevelIndex.java b/java/com/google/turbine/binder/lookup/CompoundTopLevelIndex.java
index 526e493..de50a2e 100644
--- a/java/com/google/turbine/binder/lookup/CompoundTopLevelIndex.java
+++ b/java/com/google/turbine/binder/lookup/CompoundTopLevelIndex.java
@@ -19,7 +19,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A {@link TopLevelIndex} that aggregates multiple indices into one. */
// Note: this implementation doesn't detect if the indices contain incompatible information,
diff --git a/java/com/google/turbine/binder/lookup/ImportIndex.java b/java/com/google/turbine/binder/lookup/ImportIndex.java
index 305bbfd..eb3ac8f 100644
--- a/java/com/google/turbine/binder/lookup/ImportIndex.java
+++ b/java/com/google/turbine/binder/lookup/ImportIndex.java
@@ -90,7 +90,7 @@
new Supplier<ImportScope>() {
@Override
public ImportScope get() {
- return staticNamedImport(source, cpi, i);
+ return staticNamedImport(cpi, i);
}
}));
}
@@ -103,17 +103,41 @@
LookupResult result = cpi.scope().lookup(new LookupKey(i.type()));
if (result == null) {
throw TurbineError.format(
- source, i.position(), ErrorKind.SYMBOL_NOT_FOUND, Joiner.on('.').join(i.type()));
+ source,
+ i.position(),
+ ErrorKind.SYMBOL_NOT_FOUND,
+ new ClassSymbol(Joiner.on('/').join(i.type())));
}
- ClassSymbol sym = resolve.resolve(source, i.position(), result);
+ ClassSymbol sym = (ClassSymbol) result.sym();
+ for (String bit : result.remaining()) {
+ sym = resolveNext(source, i.position(), resolve, sym, bit);
+ }
+ ClassSymbol resolved = sym;
return new ImportScope() {
@Override
public LookupResult lookup(LookupKey lookupKey, ResolveFunction unused) {
- return new LookupResult(sym, lookupKey);
+ return new LookupResult(resolved, lookupKey);
}
};
}
+ private static ClassSymbol resolveNext(
+ SourceFile source,
+ int position,
+ CanonicalSymbolResolver resolve,
+ ClassSymbol sym,
+ String bit) {
+ ClassSymbol next = resolve.resolveOne(sym, bit);
+ if (next == null) {
+ throw TurbineError.format(
+ source,
+ position,
+ ErrorKind.SYMBOL_NOT_FOUND,
+ new ClassSymbol(sym.binaryName() + '$' + bit));
+ }
+ return next;
+ }
+
/**
* Resolve the base class symbol of a possibly non-canonical static named import. For example,
* {@code import static java.util.HashMap.Entry;} is a non-canonical import for {@code
@@ -121,7 +145,7 @@
* hierarchy analysis is complete, so for now we resolve the base {@code java.util.HashMap} and
* defer the rest.
*/
- private static ImportScope staticNamedImport(SourceFile source, TopLevelIndex cpi, ImportDecl i) {
+ private static ImportScope staticNamedImport(TopLevelIndex cpi, ImportDecl i) {
LookupResult base = cpi.scope().lookup(new LookupKey(i.type()));
if (base == null) {
return null;
@@ -129,8 +153,16 @@
return new ImportScope() {
@Override
public LookupResult lookup(LookupKey lookupKey, ResolveFunction resolve) {
- ClassSymbol result = resolve.resolve(source, i.position(), base);
- return new LookupResult(result, lookupKey);
+ ClassSymbol sym = (ClassSymbol) base.sym();
+ for (String bit : base.remaining()) {
+ sym = resolve.resolveOne(sym, bit);
+ if (sym == null) {
+ // Assume that static imports that don't resolve to types are non-type member imports,
+ // even if the simple name matched what we're looking for.
+ return null;
+ }
+ }
+ return new LookupResult(sym, lookupKey);
}
};
}
diff --git a/java/com/google/turbine/binder/lookup/ImportScope.java b/java/com/google/turbine/binder/lookup/ImportScope.java
index 69ab78d..8b28cb3 100644
--- a/java/com/google/turbine/binder/lookup/ImportScope.java
+++ b/java/com/google/turbine/binder/lookup/ImportScope.java
@@ -17,9 +17,6 @@
package com.google.turbine.binder.lookup;
import com.google.turbine.binder.sym.ClassSymbol;
-import com.google.turbine.diag.SourceFile;
-import com.google.turbine.diag.TurbineError;
-import com.google.turbine.diag.TurbineError.ErrorKind;
/**
* A scope for imports. Non-canonical imports depend on hierarchy analysis, so to break the cycle we
@@ -34,19 +31,7 @@
*/
@FunctionalInterface
interface ResolveFunction {
-
ClassSymbol resolveOne(ClassSymbol base, String name);
-
- default ClassSymbol resolve(SourceFile source, int position, LookupResult result) {
- ClassSymbol sym = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
- sym = resolveOne(sym, bit);
- if (sym == null) {
- throw TurbineError.format(source, position, ErrorKind.SYMBOL_NOT_FOUND, bit);
- }
- }
- return sym;
- }
}
/** See {@link Scope#lookup(LookupKey)}. */
diff --git a/java/com/google/turbine/binder/lookup/MemberImportIndex.java b/java/com/google/turbine/binder/lookup/MemberImportIndex.java
index e2ce5cb..45eefb5 100644
--- a/java/com/google/turbine/binder/lookup/MemberImportIndex.java
+++ b/java/com/google/turbine/binder/lookup/MemberImportIndex.java
@@ -23,6 +23,8 @@
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
+import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.tree.Tree.ImportDecl;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -53,7 +55,14 @@
@Override
public ClassSymbol get() {
LookupResult result = tli.scope().lookup(new LookupKey(i.type()));
- return result != null ? resolve.resolve(source, i.position(), result) : null;
+ if (result == null) {
+ return null;
+ }
+ ClassSymbol sym = (ClassSymbol) result.sym();
+ for (String bit : result.remaining()) {
+ sym = resolveNext(resolve, source, i.position(), sym, bit);
+ }
+ return sym;
}
}));
} else {
@@ -79,6 +88,23 @@
this.classes = packageScopes.build();
}
+ private static ClassSymbol resolveNext(
+ CanonicalSymbolResolver resolve,
+ SourceFile source,
+ int position,
+ ClassSymbol sym,
+ String bit) {
+ ClassSymbol next = resolve.resolveOne(sym, bit);
+ if (next == null) {
+ throw TurbineError.format(
+ source,
+ position,
+ ErrorKind.SYMBOL_NOT_FOUND,
+ new ClassSymbol(sym.binaryName() + '$' + bit));
+ }
+ return next;
+ }
+
/** Resolves the owner of a single-member static import of the given simple name. */
public ClassSymbol singleMemberImport(String simpleName) {
Supplier<ClassSymbol> cachedResult = cache.get(simpleName);
diff --git a/java/com/google/turbine/binder/lookup/Scope.java b/java/com/google/turbine/binder/lookup/Scope.java
index 682a62a..12466f4 100644
--- a/java/com/google/turbine/binder/lookup/Scope.java
+++ b/java/com/google/turbine/binder/lookup/Scope.java
@@ -16,7 +16,7 @@
package com.google.turbine.binder.lookup;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A scope that defines types, and supports qualified name resolution. */
public interface Scope {
diff --git a/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java b/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java
index 403c53f..7fc7913 100644
--- a/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java
+++ b/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java
@@ -23,7 +23,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* An index of canonical type names where all members are known statically.
@@ -85,7 +85,7 @@
/** Inserts a {@link ClassSymbol} into the index, creating any needed packages. */
public boolean insert(ClassSymbol sym) {
- Iterator<String> it = Splitter.on('/').split(sym.toString()).iterator();
+ Iterator<String> it = Splitter.on('/').split(sym.binaryName()).iterator();
Node curr = root;
while (it.hasNext()) {
String simpleName = it.next();
diff --git a/java/com/google/turbine/binder/sym/ClassSymbol.java b/java/com/google/turbine/binder/sym/ClassSymbol.java
index 63dcfb1..2adf15f 100644
--- a/java/com/google/turbine/binder/sym/ClassSymbol.java
+++ b/java/com/google/turbine/binder/sym/ClassSymbol.java
@@ -47,7 +47,7 @@
@Override
public String toString() {
- return className;
+ return className.replace('/', '.');
}
@Override
diff --git a/java/com/google/turbine/bytecode/ClassFile.java b/java/com/google/turbine/bytecode/ClassFile.java
index 502e295..b418d70 100644
--- a/java/com/google/turbine/bytecode/ClassFile.java
+++ b/java/com/google/turbine/bytecode/ClassFile.java
@@ -26,7 +26,7 @@
import java.util.Deque;
import java.util.List;
import java.util.Map;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A JVMS §4.1 ClassFile. */
public class ClassFile {
@@ -131,7 +131,7 @@
private final String name;
private final String descriptor;
@Nullable private final String signature;
- @Nullable private final Const.Value value;
+ private final Const.@Nullable Value value;
private final List<AnnotationInfo> annotations;
private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
@@ -174,8 +174,7 @@
}
/** The compile-time constant value. */
- @Nullable
- public Const.Value value() {
+ public Const.@Nullable Value value() {
return value;
}
@@ -234,7 +233,7 @@
private final String descriptor;
@Nullable private final String signature;
private final List<String> exceptions;
- @Nullable private final AnnotationInfo.ElementValue defaultValue;
+ private final AnnotationInfo.@Nullable ElementValue defaultValue;
private final List<AnnotationInfo> annotations;
private final ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations;
private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
@@ -290,8 +289,7 @@
}
/** The value of the AnnotationDefault attribute. */
- @Nullable
- public AnnotationInfo.ElementValue defaultValue() {
+ public AnnotationInfo.@Nullable ElementValue defaultValue() {
return defaultValue;
}
diff --git a/java/com/google/turbine/bytecode/ClassReader.java b/java/com/google/turbine/bytecode/ClassReader.java
index c8b4734..0032e63 100644
--- a/java/com/google/turbine/bytecode/ClassReader.java
+++ b/java/com/google/turbine/bytecode/ClassReader.java
@@ -18,6 +18,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.errorprone.annotations.CheckReturnValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
@@ -32,8 +33,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A JVMS §4 class file reader. */
public class ClassReader {
diff --git a/java/com/google/turbine/bytecode/sig/Sig.java b/java/com/google/turbine/bytecode/sig/Sig.java
index 8a326ec..e85740f 100644
--- a/java/com/google/turbine/bytecode/sig/Sig.java
+++ b/java/com/google/turbine/bytecode/sig/Sig.java
@@ -18,7 +18,7 @@
import com.google.common.collect.ImmutableList;
import com.google.turbine.model.TurbineConstantTypeKind;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** JVMS 4.7.9.1 signatures. */
public class Sig {
diff --git a/java/com/google/turbine/diag/TurbineError.java b/java/com/google/turbine/diag/TurbineError.java
index b8d6b65..cd7d9e1 100644
--- a/java/com/google/turbine/diag/TurbineError.java
+++ b/java/com/google/turbine/diag/TurbineError.java
@@ -17,9 +17,13 @@
package com.google.turbine.diag;
import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.turbine.binder.sym.ClassSymbol;
/** A compilation error. */
public class TurbineError extends Error {
@@ -33,10 +37,11 @@
INVALID_LITERAL("invalid literal: %s"),
UNEXPECTED_TYPE_PARAMETER("unexpected type parameter %s"),
SYMBOL_NOT_FOUND("symbol not found %s"),
+ CLASS_FILE_NOT_FOUND("could not locate class file for %s"),
TYPE_PARAMETER_QUALIFIER("type parameter used as type qualifier"),
UNEXPECTED_TOKEN("unexpected token: %s"),
INVALID_ANNOTATION_ARGUMENT("invalid annotation argument"),
- CANNOT_RESOLVE("cannot resolve %s"),
+ CANNOT_RESOLVE("could not resolve %s"),
EXPRESSION_ERROR("could not evaluate constant expression"),
CYCLIC_HIERARCHY("cycle in class hierarchy: %s"),
NOT_AN_ANNOTATION("%s is not an annotation"),
@@ -58,7 +63,20 @@
/**
* Formats a diagnostic.
*
- * @param source the source file
+ * @param source the current source file
+ * @param kind the error kind
+ * @param args format args
+ */
+ public static TurbineError format(SourceFile source, ErrorKind kind, Object... args) {
+ String path = firstNonNull(source.path(), "<>");
+ String message = kind.format(args);
+ String diagnostic = path + ": error: " + message.trim() + System.lineSeparator();
+ return new TurbineError(kind, diagnostic, ImmutableList.copyOf(args));
+ }
+
+ /**
+ * Formats a diagnostic.
+ *
* @param position the diagnostic position
* @param kind the error kind
* @param args format args
@@ -78,18 +96,37 @@
.append(System.lineSeparator());
sb.append(Strings.repeat(" ", column)).append('^');
String diagnostic = sb.toString();
- return new TurbineError(kind, diagnostic);
+ return new TurbineError(kind, diagnostic, ImmutableList.copyOf(args));
}
- final ErrorKind kind;
+ private final ErrorKind kind;
+ private final ImmutableList<Object> args;
- private TurbineError(ErrorKind kind, String diagnostic) {
+ private TurbineError(ErrorKind kind, String diagnostic, ImmutableList<Object> args) {
super(diagnostic);
+ switch (kind) {
+ case SYMBOL_NOT_FOUND:
+ {
+ checkArgument(
+ args.size() == 1 && getOnlyElement(args) instanceof ClassSymbol,
+ "diagnostic (%s) has invalid argument args %s",
+ diagnostic,
+ args);
+ break;
+ }
+ default: // fall out
+ }
this.kind = kind;
+ this.args = args;
}
/** The diagnostic kind. */
public ErrorKind kind() {
return kind;
}
+
+ /** The diagnostic arguments. */
+ public ImmutableList<Object> args() {
+ return args;
+ }
}
diff --git a/java/com/google/turbine/lower/Lower.java b/java/com/google/turbine/lower/Lower.java
index d8b464b..29fca00 100644
--- a/java/com/google/turbine/lower/Lower.java
+++ b/java/com/google/turbine/lower/Lower.java
@@ -27,12 +27,12 @@
import com.google.turbine.binder.bound.AnnotationValue;
import com.google.turbine.binder.bound.ClassValue;
import com.google.turbine.binder.bound.EnumConstantValue;
-import com.google.turbine.binder.bound.ModuleInfo;
import com.google.turbine.binder.bound.ModuleInfo.ExportInfo;
import com.google.turbine.binder.bound.ModuleInfo.OpenInfo;
import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo;
import com.google.turbine.binder.bound.ModuleInfo.RequireInfo;
import com.google.turbine.binder.bound.ModuleInfo.UseInfo;
+import com.google.turbine.binder.bound.SourceModuleInfo;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
@@ -60,6 +60,9 @@
import com.google.turbine.bytecode.sig.Sig.MethodSig;
import com.google.turbine.bytecode.sig.Sig.TySig;
import com.google.turbine.bytecode.sig.SigWriter;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
+import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineVisibility;
@@ -80,7 +83,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Lowering from bound classes to bytecode. */
public class Lower {
@@ -109,7 +112,7 @@
/** Lowers all given classes to bytecode. */
public static Lowered lowerAll(
ImmutableMap<ClassSymbol, SourceTypeBoundClass> units,
- ImmutableList<ModuleInfo> modules,
+ ImmutableList<SourceModuleInfo> modules,
Env<ClassSymbol, BytecodeBoundClass> classpath) {
CompoundEnv<ClassSymbol, TypeBoundClass> env =
CompoundEnv.<ClassSymbol, TypeBoundClass>of(classpath).append(new SimpleEnv<>(units));
@@ -124,7 +127,7 @@
} else {
// multi-module mode: the output module-info.class are in a directory corresponding to their
// package
- for (ModuleInfo module : modules) {
+ for (SourceModuleInfo module : modules) {
result.put(module.name().replace('.', '/') + "/module-info", lower(module, env, symbols));
}
}
@@ -141,7 +144,9 @@
}
private static byte[] lower(
- ModuleInfo module, CompoundEnv<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> symbols) {
+ SourceModuleInfo module,
+ CompoundEnv<ClassSymbol, TypeBoundClass> env,
+ Set<ClassSymbol> symbols) {
return new Lower(env).lower(module, symbols);
}
@@ -152,7 +157,7 @@
this.env = env;
}
- private byte[] lower(ModuleInfo module, Set<ClassSymbol> symbols) {
+ private byte[] lower(SourceModuleInfo module, Set<ClassSymbol> symbols) {
String name = "module-info";
ImmutableList<AnnotationInfo> annotations = lowerAnnotations(module.annos());
ClassFile.ModuleInfo moduleInfo = lowerModule(module);
@@ -161,7 +166,7 @@
{
Set<ClassSymbol> all = new LinkedHashSet<>();
for (ClassSymbol sym : sig.classes) {
- addEnclosing(env, all, sym);
+ addEnclosing(module.source(), env, all, sym);
}
for (ClassSymbol innerSym : all) {
innerClasses.add(innerClass(env, innerSym));
@@ -185,7 +190,7 @@
return ClassWriter.writeClass(classfile);
}
- private ClassFile.ModuleInfo lowerModule(ModuleInfo module) {
+ private ClassFile.ModuleInfo lowerModule(SourceModuleInfo module) {
ImmutableList.Builder<ClassFile.ModuleInfo.RequireInfo> requires = ImmutableList.builder();
for (RequireInfo require : module.requires()) {
requires.add(
@@ -258,7 +263,7 @@
ImmutableList<AnnotationInfo> annotations = lowerAnnotations(info.annotations());
- ImmutableList<ClassFile.InnerClass> inners = collectInnerClasses(sym, info);
+ ImmutableList<ClassFile.InnerClass> inners = collectInnerClasses(info.source(), sym, info);
ImmutableList<TypeAnnotationInfo> typeAnnotations = classTypeAnnotations(info);
@@ -382,14 +387,14 @@
/** Creates inner class attributes for all referenced inner classes. */
private ImmutableList<ClassFile.InnerClass> collectInnerClasses(
- ClassSymbol origin, SourceTypeBoundClass info) {
+ SourceFile source, ClassSymbol origin, SourceTypeBoundClass info) {
Set<ClassSymbol> all = new LinkedHashSet<>();
- addEnclosing(env, all, origin);
+ addEnclosing(source, env, all, origin);
for (ClassSymbol sym : info.children().values()) {
- addEnclosing(env, all, sym);
+ addEnclosing(source, env, all, sym);
}
for (ClassSymbol sym : sig.classes) {
- addEnclosing(env, all, sym);
+ addEnclosing(source, env, all, sym);
}
ImmutableList.Builder<ClassFile.InnerClass> inners = ImmutableList.builder();
for (ClassSymbol innerSym : all) {
@@ -406,14 +411,17 @@
* classes' entries.
*/
private void addEnclosing(
- Env<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> all, ClassSymbol sym) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ Set<ClassSymbol> all,
+ ClassSymbol sym) {
TypeBoundClass info = env.get(sym);
if (info == null) {
- throw new AssertionError(sym);
+ throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, sym);
}
ClassSymbol owner = env.get(sym).owner();
if (owner != null) {
- addEnclosing(env, all, owner);
+ addEnclosing(source, env, all, owner);
all.add(sym);
}
}
diff --git a/java/com/google/turbine/model/TurbineVisibility.java b/java/com/google/turbine/model/TurbineVisibility.java
index 4f250c7..a30af4c 100644
--- a/java/com/google/turbine/model/TurbineVisibility.java
+++ b/java/com/google/turbine/model/TurbineVisibility.java
@@ -42,19 +42,27 @@
public static final int VISIBILITY_MASK =
TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_PRIVATE | TurbineFlag.ACC_PROTECTED;
+ /**
+ * Returns the {@link TurbineVisibility} corresponding to the given access bits.
+ *
+ * <p>If the input is ill-formed and corresponds to multiple visibilities, {@code PUBLIC}, {@code
+ * PROTECTED}, {@code PRIVATE}, and {@code PACKAGE}, are returned in that order. This means that
+ * turbine will occasionally produce valid output for invalid input. In general turbine performs
+ * the minimum possible error-checking, and the expectation is that it is run in parallel with
+ * javac or another non-header compiler as part of a build, and it defers well-formedness checking
+ * to the other tool.
+ */
public static TurbineVisibility fromAccess(int access) {
- switch (access & VISIBILITY_MASK) {
- case TurbineFlag.ACC_PUBLIC:
- return PUBLIC;
- case TurbineFlag.ACC_PRIVATE:
- return PRIVATE;
- case TurbineFlag.ACC_PROTECTED:
- return PROTECTED;
- case 0:
- return PACKAGE;
- default:
- throw new AssertionError(String.format("0x%x", access));
+ if ((access & TurbineFlag.ACC_PUBLIC) == TurbineFlag.ACC_PUBLIC) {
+ return PUBLIC;
}
+ if ((access & TurbineFlag.ACC_PROTECTED) == TurbineFlag.ACC_PROTECTED) {
+ return PROTECTED;
+ }
+ if ((access & TurbineFlag.ACC_PRIVATE) == TurbineFlag.ACC_PRIVATE) {
+ return PRIVATE;
+ }
+ return PACKAGE;
}
public int setAccess(int access) {
diff --git a/java/com/google/turbine/options/TurbineOptions.java b/java/com/google/turbine/options/TurbineOptions.java
index 20d81fe..7dd118e 100644
--- a/java/com/google/turbine/options/TurbineOptions.java
+++ b/java/com/google/turbine/options/TurbineOptions.java
@@ -21,7 +21,7 @@
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Header compilation options. */
public class TurbineOptions {
@@ -271,12 +271,6 @@
return this;
}
- // TODO(b/72379900): Remove this
- public Builder addDirectJarToTarget(String jar) {
- directJars.add(jar);
- return this;
- }
-
public Builder setTargetLabel(String targetLabel) {
this.targetLabel = targetLabel;
return this;
diff --git a/java/com/google/turbine/options/TurbineOptionsParser.java b/java/com/google/turbine/options/TurbineOptionsParser.java
index 419a04e..40c9ecc 100644
--- a/java/com/google/turbine/options/TurbineOptionsParser.java
+++ b/java/com/google/turbine/options/TurbineOptionsParser.java
@@ -28,7 +28,7 @@
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A command line options parser for {@link TurbineOptions}. */
public class TurbineOptionsParser {
@@ -73,7 +73,6 @@
case "--processorpath":
builder.addProcessorPathEntries(readList(argumentDeque));
break;
- // TODO(b/72379900): Remove this
case "--classpath":
builder.addClassPathEntries(readList(argumentDeque));
break;
@@ -102,27 +101,6 @@
case "--direct_dependencies":
builder.addDirectJars(readList(argumentDeque));
break;
- case "--direct_dependency":
- {
- // TODO(b/72379900): Remove this
- String jar = readOne(argumentDeque);
- readOne(argumentDeque);
- builder.addDirectJarToTarget(jar);
- if (!argumentDeque.isEmpty() && !argumentDeque.peekFirst().startsWith("--")) {
- argumentDeque.removeFirst(); // the aspect that created the dependency
- }
- break;
- }
- case "--indirect_dependency":
- {
- // TODO(b/72379900): Remove this
- readOne(argumentDeque);
- readOne(argumentDeque);
- if (!argumentDeque.isEmpty() && !argumentDeque.peekFirst().startsWith("--")) {
- argumentDeque.removeFirst(); // the aspect that created the dependency
- }
- break;
- }
case "--deps_artifacts":
builder.addAllDepsArtifacts(readList(argumentDeque));
break;
diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java
index e6a7f97..51f3128 100644
--- a/java/com/google/turbine/parse/ConstExpressionParser.java
+++ b/java/com/google/turbine/parse/ConstExpressionParser.java
@@ -20,6 +20,7 @@
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
+import com.google.errorprone.annotations.CheckReturnValue;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.Const;
@@ -29,8 +30,7 @@
import com.google.turbine.tree.Tree.ClassTy;
import com.google.turbine.tree.Tree.Expression;
import com.google.turbine.tree.TurbineOperatorKind;
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** A parser for compile-time constant expressions. */
public class ConstExpressionParser {
@@ -220,7 +220,8 @@
case NOT:
case TILDE:
case IDENT:
- return new Tree.TypeCast(position, asClassTy(cvar.name()), primary(false));
+ return new Tree.TypeCast(
+ position, asClassTy(cvar.position(), cvar.name()), primary(false));
default:
return expr;
}
@@ -229,12 +230,11 @@
}
}
- private ClassTy asClassTy(ImmutableList<String> names) {
+ private static ClassTy asClassTy(int pos, ImmutableList<String> names) {
ClassTy cty = null;
for (String bit : names) {
cty =
- new ClassTy(
- position, Optional.fromNullable(cty), bit, ImmutableList.of(), ImmutableList.of());
+ new ClassTy(pos, Optional.fromNullable(cty), bit, ImmutableList.of(), ImmutableList.of());
}
return cty;
}
@@ -419,14 +419,13 @@
return new Tree.Unary(position, expr, op);
}
- @Nullable
- private Tree.Expression qualIdent() {
+ private Tree.@Nullable Expression qualIdent() {
int pos = position;
ImmutableList.Builder<String> bits = ImmutableList.builder();
bits.add(lexer.stringValue());
eat();
if (token == Token.LBRACK) {
- return finishClassLiteral(pos, asClassTy(bits.build()));
+ return finishClassLiteral(pos, asClassTy(pos, bits.build()));
}
while (token == Token.DOT) {
eat();
@@ -437,7 +436,7 @@
case CLASS:
// TODO(cushon): only allow in annotations?
eat();
- return new Tree.ClassLiteral(pos, asClassTy(bits.build()));
+ return new Tree.ClassLiteral(pos, asClassTy(pos, bits.build()));
default:
return null;
}
diff --git a/java/com/google/turbine/parse/Parser.java b/java/com/google/turbine/parse/Parser.java
index 7b3a92e..752b2a5 100644
--- a/java/com/google/turbine/parse/Parser.java
+++ b/java/com/google/turbine/parse/Parser.java
@@ -29,6 +29,7 @@
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
@@ -62,8 +63,7 @@
import java.util.Deque;
import java.util.EnumSet;
import java.util.List;
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A parser for the subset of Java required for header compilation.
@@ -981,6 +981,8 @@
case LPAREN:
depth++;
break;
+ case EOF:
+ throw error(ErrorKind.UNEXPECTED_EOF);
default:
break;
}
@@ -999,6 +1001,8 @@
case LBRACE:
depth++;
break;
+ case EOF:
+ throw error(ErrorKind.UNEXPECTED_EOF);
default:
break;
}
diff --git a/java/com/google/turbine/parse/VariableInitializerParser.java b/java/com/google/turbine/parse/VariableInitializerParser.java
index 6226e3a..a39e9e8 100644
--- a/java/com/google/turbine/parse/VariableInitializerParser.java
+++ b/java/com/google/turbine/parse/VariableInitializerParser.java
@@ -17,6 +17,9 @@
package com.google.turbine.parse;
import com.google.common.collect.ImmutableList;
+import com.google.errorprone.annotations.CheckReturnValue;
+import com.google.turbine.diag.TurbineError;
+import com.google.turbine.diag.TurbineError.ErrorKind;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
@@ -232,6 +235,8 @@
next();
depth--;
break;
+ case EOF:
+ throw error(ErrorKind.UNEXPECTED_EOF);
default:
save();
next();
@@ -254,6 +259,8 @@
next();
depth--;
break;
+ case EOF:
+ throw error(ErrorKind.UNEXPECTED_EOF);
default:
save();
next();
@@ -330,4 +337,13 @@
}
}
}
+
+ @CheckReturnValue
+ private TurbineError error(ErrorKind kind, Object... args) {
+ return TurbineError.format(
+ lexer.source(),
+ Math.min(lexer.position(), lexer.source().source().length() - 1),
+ kind,
+ args);
+ }
}
diff --git a/java/com/google/turbine/type/Type.java b/java/com/google/turbine/type/Type.java
index cdd8605..61a5bbe 100644
--- a/java/com/google/turbine/type/Type.java
+++ b/java/com/google/turbine/type/Type.java
@@ -106,9 +106,9 @@
for (SimpleClassTy c : classes) {
if (!first) {
sb.append('.');
- sb.append(c.sym.toString().substring(c.sym.toString().lastIndexOf('$') + 1));
+ sb.append(c.sym.binaryName().substring(c.sym.binaryName().lastIndexOf('$') + 1));
} else {
- sb.append(c.sym);
+ sb.append(c.sym.binaryName());
}
if (!c.targs.isEmpty()) {
sb.append('<');
diff --git a/java/com/google/turbine/types/Canonicalize.java b/java/com/google/turbine/types/Canonicalize.java
index fc5d907..b7a9048 100644
--- a/java/com/google/turbine/types/Canonicalize.java
+++ b/java/com/google/turbine/types/Canonicalize.java
@@ -22,6 +22,9 @@
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
+import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
@@ -40,7 +43,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import javax.annotation.Nullable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Canonicalizes qualified type names so qualifiers are always the declaring class of the qualified
@@ -63,35 +66,38 @@
/** Canonicalizes the given type. */
public static Type canonicalize(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, Type type) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, Type type) {
switch (type.tyKind()) {
case PRIM_TY:
case VOID_TY:
case TY_VAR:
return type;
case WILD_TY:
- return canonicalizeWildTy(env, base, (WildTy) type);
+ return canonicalizeWildTy(source, env, base, (WildTy) type);
case ARRAY_TY:
{
Type.ArrayTy arrayTy = (Type.ArrayTy) type;
- return new Type.ArrayTy(canonicalize(env, base, arrayTy.elementType()), arrayTy.annos());
+ return new Type.ArrayTy(
+ canonicalize(source, env, base, arrayTy.elementType()), arrayTy.annos());
}
case CLASS_TY:
- return canonicalizeClassTy(env, base, (ClassTy) type);
+ return canonicalizeClassTy(source, env, base, (ClassTy) type);
default:
throw new AssertionError(type.tyKind());
}
}
/** Canonicalize a qualified class type, excluding type arguments. */
- private static ClassTy canon(Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
+ private static ClassTy canon(
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
if (isRaw(env, ty)) {
return Erasure.eraseClassTy(ty);
}
// if the first name is a simple name resolved inside a nested class, add explicit qualifiers
// for the enclosing declarations
Iterator<ClassTy.SimpleClassTy> it = ty.classes.iterator();
- Collection<ClassTy.SimpleClassTy> lexicalBase = lexicalBase(env, ty.classes.get(0).sym(), base);
+ Collection<ClassTy.SimpleClassTy> lexicalBase =
+ lexicalBase(source, env, ty.classes.get(0).sym(), base);
ClassTy canon =
!lexicalBase.isEmpty()
? new ClassTy(lexicalBase)
@@ -99,7 +105,7 @@
// canonicalize each additional simple name that appeared in source
while (it.hasNext()) {
- canon = canonOne(env, canon, it.next());
+ canon = canonOne(source, env, canon, it.next());
}
return canon;
}
@@ -122,7 +128,10 @@
/** Given a base symbol to canonicalize, find any implicit enclosing instances. */
private static Collection<ClassTy.SimpleClassTy> lexicalBase(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol first, ClassSymbol owner) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol first,
+ ClassSymbol owner) {
if ((env.get(first).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
return Collections.emptyList();
}
@@ -137,7 +146,11 @@
if ((env.get(owner).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
break;
}
- canonOwner = env.get(canonOwner).owner();
+ TypeBoundClass info = env.get(canonOwner);
+ if (info == null) {
+ throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, canonOwner);
+ }
+ canonOwner = info.owner();
}
return result;
}
@@ -167,7 +180,7 @@
* result.
*/
private static ClassTy canonOne(
- Env<ClassSymbol, TypeBoundClass> env, ClassTy base, ClassTy.SimpleClassTy ty) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassTy base, SimpleClassTy ty) {
// if the class is static, it has a trivial canonical qualifier with no type arguments
if ((env.get(ty.sym()).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
return new ClassTy(Collections.singletonList(ty));
@@ -196,7 +209,7 @@
break;
}
TypeBoundClass info = env.get(curr.sym());
- curr = canon(env, info.owner(), info.superClassType());
+ curr = canon(source, env, info.owner(), info.superClassType());
}
simples.add(ty);
return new ClassTy(simples.build());
@@ -315,36 +328,41 @@
}
public static ClassTy canonicalizeClassTy(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
// canonicalize type arguments first
ImmutableList.Builder<ClassTy.SimpleClassTy> args = ImmutableList.builder();
for (ClassTy.SimpleClassTy s : ty.classes) {
- args.add(new ClassTy.SimpleClassTy(s.sym(), canonicalize(s.targs(), base, env), s.annos()));
+ args.add(
+ new ClassTy.SimpleClassTy(
+ s.sym(), canonicalize(source, s.targs(), base, env), s.annos()));
}
ty = new ClassTy(args.build());
- return canon(env, base, ty);
+ return canon(source, env, base, ty);
}
private static ImmutableList<Type> canonicalize(
- ImmutableList<Type> targs, ClassSymbol base, Env<ClassSymbol, TypeBoundClass> env) {
+ SourceFile source,
+ ImmutableList<Type> targs,
+ ClassSymbol base,
+ Env<ClassSymbol, TypeBoundClass> env) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type a : targs) {
- result.add(canonicalize(env, base, a));
+ result.add(canonicalize(source, env, base, a));
}
return result.build();
}
private static Type canonicalizeWildTy(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, WildTy type) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, WildTy type) {
switch (type.boundKind()) {
case NONE:
return type;
case LOWER:
return new Type.WildLowerBoundedTy(
- canonicalize(env, base, type.bound()), type.annotations());
+ canonicalize(source, env, base, type.bound()), type.annotations());
case UPPER:
return new Type.WildUpperBoundedTy(
- canonicalize(env, base, type.bound()), type.annotations());
+ canonicalize(source, env, base, type.bound()), type.annotations());
default:
throw new AssertionError(type.boundKind());
}
diff --git a/javatests/com/google/turbine/binder/BinderErrorTest.java b/javatests/com/google/turbine/binder/BinderErrorTest.java
index a4c2e25..0f37537 100644
--- a/javatests/com/google/turbine/binder/BinderErrorTest.java
+++ b/javatests/com/google/turbine/binder/BinderErrorTest.java
@@ -46,7 +46,7 @@
"}",
},
{
- "<>:2: error: symbol not found NoSuch",
+ "<>:2: error: could not resolve NoSuch",
"public class A extends NoSuch {",
" ^",
}
@@ -61,7 +61,7 @@
},
// TODO(cushon): we'd prefer the caret at NoSuch instead of A
{
- "<>:4: error: symbol not found NoSuch", //
+ "<>:4: error: symbol not found a.A$NoSuch", //
"class B extends A.NoSuch {",
" ^",
}
@@ -73,7 +73,7 @@
"class B extends A<NoSuch> {}",
},
{
- "<>:3: error: symbol not found NoSuch",
+ "<>:3: error: could not resolve NoSuch",
"class B extends A<NoSuch> {}",
" ^",
}
@@ -84,7 +84,7 @@
"@Anno(foo=100, bar=200) class Test {}",
},
{
- "<>:2: error: cannot resolve foo", //
+ "<>:2: error: could not resolve foo", //
"@Anno(foo=100, bar=200) class Test {}",
" ^",
},
@@ -95,7 +95,7 @@
"@Anno(foo=100, bar=200) class Test {}",
},
{
- "<>:2: error: cannot resolve bar", //
+ "<>:2: error: could not resolve bar", //
"@Anno(foo=100, bar=200) class Test {}",
" ^",
},
@@ -146,8 +146,8 @@
"}",
},
{
- "<>:4: error: cycle in class hierarchy: p/OuterExtendsInner$Inner"
- + " -> p/OuterExtendsInner$Inner",
+ "<>:4: error: cycle in class hierarchy: p.OuterExtendsInner$Inner"
+ + " -> p.OuterExtendsInner$Inner",
" public static class Inner extends Foo {}",
" ^"
},
@@ -173,7 +173,7 @@
"}",
},
{
- "<>:2: error: symbol not found NoSuch", //
+ "<>:2: error: symbol not found java.util.List$NoSuch", //
"import java.util.List.NoSuch;",
" ^"
},
@@ -186,9 +186,9 @@
"}",
},
{
- "<>:2: error: symbol not found NoSuch", //
- "import static java.util.List.NoSuch;",
- " ^"
+ "<>:3: error: could not resolve NoSuch", //
+ "public class Test extends NoSuch {",
+ " ^"
},
},
{
@@ -199,7 +199,7 @@
"}",
},
{
- "<>:3: error: symbol not found NoSuchOther",
+ "<>:3: error: could not resolve NoSuchOther",
"public class Test extends NoSuchOther {",
" ^",
},
@@ -212,7 +212,7 @@
"}",
},
{
- "<>:3: error: symbol not found NoSuchOther",
+ "<>:3: error: could not resolve NoSuchOther",
"public class Test extends NoSuchOther {",
" ^",
},
@@ -225,7 +225,7 @@
"}",
},
{
- "<>:3: error: symbol not found NoSuchOther",
+ "<>:3: error: could not resolve NoSuchOther",
"public class Test extends NoSuchOther {",
" ^",
},
@@ -238,7 +238,7 @@
"}",
},
{
- "<>:3: error: symbol not found NoSuchOther",
+ "<>:3: error: could not resolve NoSuchOther",
"public class Test extends NoSuchOther {",
" ^",
},
@@ -250,7 +250,7 @@
"}",
},
{
- "<>:2: error: java/lang/Object is not an annotation", //
+ "<>:2: error: java.lang.Object is not an annotation", //
" @Object int x;",
" ^",
},
@@ -262,7 +262,7 @@
"}",
},
{
- "<>:2: error: java/lang/Deprecated is not @Repeatable", //
+ "<>:2: error: java.lang.Deprecated is not @Repeatable", //
" @Deprecated @Deprecated int x;",
" ^",
},
@@ -274,7 +274,7 @@
"}",
},
{
- "<>:2: error: symbol not found NoSuch.NoSuch", //
+ "<>:2: error: could not resolve NoSuch.NoSuch", //
" @NoSuch.NoSuch int x;",
" ^",
},
@@ -286,7 +286,7 @@
"}",
},
{
- "<>:2: error: symbol not found NoSuch", //
+ "<>:2: error: symbol not found java.lang.Deprecated$NoSuch", //
" @Deprecated.NoSuch int x;",
" ^",
},
@@ -301,7 +301,7 @@
"}",
},
{
- "<>:5: error: could not evaluate constant expression", //
+ "<>:5: error: could not resolve field NO_SUCH", //
" @Anno(value=Test.NO_SUCH) int x;",
" ^",
},
@@ -360,6 +360,49 @@
" ^",
},
},
+ {
+ {
+ "import java.util.List;", //
+ "@interface Anno { Class<?> value() default Object.class; }",
+ "@Anno(List.NoSuch.class)",
+ "public class Test {}",
+ },
+ {
+ "<>:3: error: symbol not found java.util.List$NoSuch", //
+ "@Anno(List.NoSuch.class)",
+ " ^",
+ },
+ },
+ {
+ {
+ "public class Test {", //
+ " @interface Anno {",
+ " Class<?>[] value() default Object.class;",
+ " }",
+ " @Anno(value={java.util.Map.Entry}) int x;",
+ "}",
+ },
+ {
+ "<>:5: error: could not resolve field Entry", //
+ " @Anno(value={java.util.Map.Entry}) int x;",
+ " ^",
+ },
+ },
+ {
+ {
+ "public class Test {", //
+ " @interface Anno {",
+ " Class<?>[] value() default Object.class;",
+ " }",
+ " @Anno(value={java.lang.Object}) int x;",
+ "}",
+ },
+ {
+ "<>:5: error: could not resolve field Object", //
+ " @Anno(value={java.lang.Object}) int x;",
+ " ^",
+ },
+ },
};
return Arrays.asList((Object[][]) testCases);
}
diff --git a/javatests/com/google/turbine/binder/BinderTest.java b/javatests/com/google/turbine/binder/BinderTest.java
index 9ba5705..700baf0 100644
--- a/javatests/com/google/turbine/binder/BinderTest.java
+++ b/javatests/com/google/turbine/binder/BinderTest.java
@@ -195,7 +195,7 @@
/* moduleVersion=*/ Optional.absent());
fail();
} catch (TurbineError e) {
- assertThat(e.getMessage()).contains("cycle in class hierarchy: a/A -> b/B -> a/A");
+ assertThat(e.getMessage()).contains("cycle in class hierarchy: a.A -> b.B -> a.A");
}
}
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index 698627c..6496756 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -302,6 +302,7 @@
"B70953542.test",
// TODO(cushon): support for source level 9 in integration tests
// "B74332665.test",
+ "memberimport.test",
};
List<Object[]> tests =
ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java
index 6409d4d..d97f46a 100644
--- a/javatests/com/google/turbine/lower/LowerTest.java
+++ b/javatests/com/google/turbine/lower/LowerTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
@@ -36,6 +37,7 @@
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.bytecode.ByteReader;
import com.google.turbine.bytecode.ConstantPoolReader;
+import com.google.turbine.diag.TurbineError;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
@@ -480,6 +482,151 @@
.isEqualTo(IntegrationTestSupport.dump(IntegrationTestSupport.canonicalize(expected)));
}
+ @Test
+ public void missingOuter() throws Exception {
+
+ Map<String, byte[]> lib =
+ IntegrationTestSupport.runJavac(
+ ImmutableMap.of(
+ "A.java",
+ lines(
+ "interface A {", //
+ " interface M {",
+ " interface I {}",
+ " } ",
+ "}"),
+ "B.java",
+ lines(
+ "interface B extends A {",
+ " interface BM extends M {",
+ " interface BI extends I {}",
+ " }",
+ "}")),
+ ImmutableList.of());
+
+ Path libJar = temporaryFolder.newFile("lib.jar").toPath();
+ try (OutputStream os = Files.newOutputStream(libJar);
+ JarOutputStream jos = new JarOutputStream(os)) {
+ jos.putNextEntry(new JarEntry("A$M.class"));
+ jos.write(lib.get("A$M"));
+ jos.putNextEntry(new JarEntry("A$M$I.class"));
+ jos.write(lib.get("A$M$I"));
+ jos.putNextEntry(new JarEntry("B.class"));
+ jos.write(lib.get("B"));
+ jos.putNextEntry(new JarEntry("B$BM.class"));
+ jos.write(lib.get("B$BM"));
+ jos.putNextEntry(new JarEntry("B$BM$BI.class"));
+ jos.write(lib.get("B$BM$BI"));
+ }
+
+ ImmutableMap<String, String> sources =
+ ImmutableMap.<String, String>builder()
+ .put(
+ "Test.java",
+ lines(
+ "public class Test extends B.BM {", //
+ " I i;",
+ "}"))
+ .build();
+
+ try {
+ IntegrationTestSupport.runTurbine(sources, ImmutableList.of(libJar));
+ fail();
+ } catch (TurbineError error) {
+ assertThat(error)
+ .hasMessageThat()
+ .contains("Test.java: error: could not locate class file for A");
+ }
+ }
+
+ @Test
+ public void missingOuter2() throws Exception {
+
+ Map<String, byte[]> lib =
+ IntegrationTestSupport.runJavac(
+ ImmutableMap.of(
+ "A.java",
+ lines(
+ "class A {", //
+ " class M { ",
+ " class I {} ",
+ " } ",
+ "}"),
+ "B.java",
+ lines(
+ "class B extends A { ",
+ " class BM extends M { ",
+ " class BI extends I {} ",
+ " } ",
+ "}")),
+ ImmutableList.of());
+
+ Path libJar = temporaryFolder.newFile("lib.jar").toPath();
+ try (OutputStream os = Files.newOutputStream(libJar);
+ JarOutputStream jos = new JarOutputStream(os)) {
+ jos.putNextEntry(new JarEntry("A$M.class"));
+ jos.write(lib.get("A$M"));
+ jos.putNextEntry(new JarEntry("A$M$I.class"));
+ jos.write(lib.get("A$M$I"));
+ jos.putNextEntry(new JarEntry("B.class"));
+ jos.write(lib.get("B"));
+ jos.putNextEntry(new JarEntry("B$BM.class"));
+ jos.write(lib.get("B$BM"));
+ jos.putNextEntry(new JarEntry("B$BM$BI.class"));
+ jos.write(lib.get("B$BM$BI"));
+ }
+
+ ImmutableMap<String, String> sources =
+ ImmutableMap.<String, String>builder()
+ .put(
+ "Test.java",
+ lines(
+ "public class Test extends B {", //
+ " class M extends BM {",
+ " I i;",
+ " }",
+ "}"))
+ .build();
+
+ try {
+ IntegrationTestSupport.runTurbine(sources, ImmutableList.of(libJar));
+ fail();
+ } catch (TurbineError error) {
+ assertThat(error)
+ .hasMessageThat()
+ .contains("Test.java: error: could not locate class file for A");
+ }
+ }
+
+ // If an element incorrectly has multiple visibility modifiers, pick one, and rely on javac to
+ // report a diagnostic.
+ @Test
+ public void multipleVisibilities() throws Exception {
+ ImmutableMap<String, String> sources =
+ ImmutableMap.of("Test.java", "public protected class Test {}");
+
+ Map<String, byte[]> lowered =
+ IntegrationTestSupport.runTurbine(sources, /* classpath= */ ImmutableList.of());
+ int[] testAccess = {0};
+ new ClassReader(lowered.get("Test"))
+ .accept(
+ new ClassVisitor(Opcodes.ASM6) {
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ testAccess[0] = access;
+ }
+ },
+ 0);
+ assertThat((testAccess[0] & TurbineFlag.ACC_PUBLIC) == TurbineFlag.ACC_PUBLIC).isTrue();
+ assertThat((testAccess[0] & TurbineFlag.ACC_PROTECTED) == TurbineFlag.ACC_PROTECTED).isFalse();
+ }
+
static String lines(String... lines) {
return Joiner.on("\n").join(lines);
}
diff --git a/javatests/com/google/turbine/lower/testdata/memberimport.test b/javatests/com/google/turbine/lower/testdata/memberimport.test
new file mode 100644
index 0000000..c32220a
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/memberimport.test
@@ -0,0 +1,18 @@
+=== A.java ===
+package a;
+public class A {
+ // this is not a field
+ // | this is a field
+ // | |
+ // v v
+ public static final Object Object = new Object() {};
+}
+=== B.java ===
+package b;
+import static a.A.Object; // <-- this is a field
+class B {
+ public static final Object x = null;
+ // ^
+ // |
+ // this is not a field
+}
diff --git a/javatests/com/google/turbine/options/TurbineOptionsTest.java b/javatests/com/google/turbine/options/TurbineOptionsTest.java
index 8342ccc..36f9e20 100644
--- a/javatests/com/google/turbine/options/TurbineOptionsTest.java
+++ b/javatests/com/google/turbine/options/TurbineOptionsTest.java
@@ -120,37 +120,6 @@
assertThat(options.depsArtifacts()).containsExactly("foo.jdeps", "bar.jdeps");
}
- /** Makes sure turbine accepts old-style arguments. */
- // TODO(b/72379900): Remove this.
- @Test
- public void testLegacyStrictJavaDepsArgs() throws Exception {
- String[] lines = {
- "--direct_dependency",
- "blaze-out/foo/libbar.jar",
- "//foo/bar",
- "--indirect_dependency",
- "blaze-out/foo/libbaz1.jar",
- "//foo/baz1",
- "--indirect_dependency",
- "blaze-out/foo/libbaz2.jar",
- "//foo/baz2",
- "--indirect_dependency",
- "blaze-out/proto/libproto.jar",
- "//proto",
- "java_proto_library",
- "--deps_artifacts",
- "foo.jdeps",
- "bar.jdeps",
- "",
- };
-
- TurbineOptions options =
- TurbineOptionsParser.parse(Iterables.concat(BASE_ARGS, Arrays.asList(lines)));
-
- assertThat(options.targetLabel()).hasValue("//java/com/google/test");
- assertThat(options.depsArtifacts()).containsExactly("foo.jdeps", "bar.jdeps");
- }
-
@Test
public void classpathArgs() throws Exception {
String[] lines = {
diff --git a/javatests/com/google/turbine/parse/ParseErrorTest.java b/javatests/com/google/turbine/parse/ParseErrorTest.java
index 0ec6208..c728c8a 100644
--- a/javatests/com/google/turbine/parse/ParseErrorTest.java
+++ b/javatests/com/google/turbine/parse/ParseErrorTest.java
@@ -122,6 +122,38 @@
}
}
+ @Test
+ public void dropParens() {
+ String input = "enum E { ONE(";
+ try {
+ Parser.parse(input);
+ fail("expected parsing to fail");
+ } catch (TurbineError e) {
+ assertThat(e.getMessage())
+ .isEqualTo(
+ lines(
+ "<>:1: error: unexpected end of input", //
+ "enum E { ONE(",
+ " ^"));
+ }
+ }
+
+ @Test
+ public void dropBlocks() {
+ String input = "class T { Object f = new Object() {";
+ try {
+ Parser.parse(input);
+ fail("expected parsing to fail");
+ } catch (TurbineError e) {
+ assertThat(e.getMessage())
+ .isEqualTo(
+ lines(
+ "<>:1: error: unexpected end of input", //
+ "class T { Object f = new Object() {",
+ " ^"));
+ }
+ }
+
private static String lines(String... lines) {
return Joiner.on(System.lineSeparator()).join(lines);
}
diff --git a/pom.xml b/pom.xml
index 58bc5f4..f9316f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,17 +23,18 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <version>22.0</version>
- </dependency>
- <dependency>
- <groupId>com.google.code.findbugs</groupId>
- <artifactId>jsr305</artifactId>
- <version>2.0.1</version>
+ <version>23.6-jre</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
- <version>2.0.12</version>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.checkerframework</groupId>
+ <artifactId>checker-qual</artifactId>
+ <version>2.0.0</version>
+ <optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>