Skip to content

Commit

Permalink
Plumb VisitorState through to Signatures
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 658956389
  • Loading branch information
cushon authored and Error Prone Team committed Aug 11, 2024
1 parent ac6597f commit 32fe079
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 28 deletions.
45 changes: 30 additions & 15 deletions check_api/src/main/java/com/google/errorprone/util/Signatures.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,57 @@

package com.google.errorprone.util;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;

import com.google.errorprone.VisitorState;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.DefaultTypeVisitor;
import com.sun.tools.javac.code.Types.SignatureGenerator;
import com.sun.tools.javac.util.Name;
import java.util.Arrays;
import com.sun.tools.javac.util.Names;

/** Signature generation. */
public final class Signatures {

/** Returns the binary names of the class. */
public static String classDescriptor(Type type, Types types) {
SigGen sig = new SigGen(types);
public static String classDescriptor(Type type, VisitorState state) {
return new Signatures(state).classDescriptor(type);
}

private String classDescriptor(Type type) {
SigGen sig = new SigGen();
sig.assembleClassSig(types.erasure(type));
return sig.toString();
}

/** Returns a JVMS 4.3.3 method descriptor. */
public static String descriptor(Type type, Types types) {
SigGen sig = new SigGen(types);
public static String descriptor(Type type, VisitorState state) {
return new Signatures(state).descriptor(type);
}

private String descriptor(Type type) {
SigGen sig = new SigGen();
sig.assembleSig(types.erasure(type));
return sig.toString();
}

private static class SigGen extends SignatureGenerator {
final Types types;
final Names names;

private Signatures(VisitorState state) {
this.types = state.getTypes();
this.names = state.getNames();
}

private class SigGen extends Types.SignatureGenerator {

private final com.sun.tools.javac.util.ByteBuffer buffer =
new com.sun.tools.javac.util.ByteBuffer();

protected SigGen(Types types) {
protected SigGen() {
super(types);
}

Expand All @@ -70,12 +85,14 @@ protected void append(Name name) {
buffer.appendName(name);
}

@SuppressWarnings("CatchingUnchecked") // handles InvalidUtfException on JDK 21+
@Override
public String toString() {
// We could use buffer.toName(Names), but we want a string anyways and this
// avoids plumbing a Context or instances of Names through.
// Names always uses UTF-8 internally.
return new String(Arrays.copyOf(buffer.elems, buffer.length), UTF_8);
try {
return buffer.toName(names).toString();
} catch (Exception e) {
throw new AssertionError(e);
}
}
}

Expand Down Expand Up @@ -154,6 +171,4 @@ public String visitType(Type t, Void s) {
return t.toString();
}
};

private Signatures() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public Description matchClass(ClassTree tree, VisitorState state) {
.map(MethodSymbol.class::cast)
.filter(m -> m.isConstructor() || m.owner.equals(origin))
.collect(
groupingBy(m -> methodReferenceDescriptor(types, m), toCollection(ArrayList::new)));
groupingBy(m -> methodReferenceDescriptor(state, m), toCollection(ArrayList::new)));

// look for groups of ambiguous method references
for (Tree member : tree.getMembers()) {
Expand All @@ -70,7 +70,7 @@ public Description matchClass(ClassTree tree, VisitorState state) {
if (isSuppressed(msym, state)) {
continue;
}
List<MethodSymbol> clash = methods.remove(methodReferenceDescriptor(types, msym));
List<MethodSymbol> clash = methods.remove(methodReferenceDescriptor(state, msym));
if (clash == null) {
continue;
}
Expand Down Expand Up @@ -104,13 +104,13 @@ public Description matchClass(ClassTree tree, VisitorState state) {
}

/** Returns a string descriptor of a method's reference type. */
private static String methodReferenceDescriptor(Types types, MethodSymbol sym) {
private static String methodReferenceDescriptor(VisitorState state, MethodSymbol sym) {
StringBuilder sb = new StringBuilder();
sb.append(sym.getSimpleName()).append('(');
if (!sym.isStatic()) {
sb.append(Signatures.descriptor(sym.owner.type, types));
sb.append(Signatures.descriptor(sym.owner.type, state));
}
sym.params().stream().map(p -> Signatures.descriptor(p.type, types)).forEachOrdered(sb::append);
sym.params().stream().map(p -> Signatures.descriptor(p.type, state)).forEachOrdered(sb::append);
sb.append(")");
return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private static String functionalInterfaceSignature(VisitorState state, MethodSym
private static String functionalInterfaceSignature(VisitorState state, Type type) {
Types types = state.getTypes();
if (!maybeFunctionalInterface(type, types, state)) {
return Signatures.descriptor(type, types);
return Signatures.descriptor(type, state);
}
Type descriptorType = types.findDescriptorType(type);
List<Type> fiparams = descriptorType.getParameterTypes();
Expand All @@ -180,10 +180,10 @@ private static String functionalInterfaceSignature(VisitorState state, Type type
// types in general. The except is nullary functional interfaces, since the lambda parameters
// will never be implicitly typed.
String result =
fiparams.isEmpty() ? Signatures.descriptor(descriptorType.getReturnType(), types) : "_";
fiparams.isEmpty() ? Signatures.descriptor(descriptorType.getReturnType(), state) : "_";
return String.format(
"(%s)->%s",
fiparams.stream().map(t -> Signatures.descriptor(t, types)).collect(joining(",")), result);
fiparams.stream().map(t -> Signatures.descriptor(t, state)).collect(joining(",")), result);
}

private static boolean maybeFunctionalInterface(Type type, Types types, VisitorState state) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
Expand Down Expand Up @@ -80,9 +79,8 @@ protected Description check(ExpressionTree tree, VisitorState state) {
// e.g. package symbols
return Description.NO_MATCH;
}
Types types = state.getTypes();
// check for information associated with the class
if (apiDiff.isClassUnsupported(Signatures.classDescriptor(receiver.type, types))
if (apiDiff.isClassUnsupported(Signatures.classDescriptor(receiver.type, state))
|| classOrEnclosingClassIsForbiddenByAnnotation(receiver, state)) {
return buildDescription(tree)
.setMessage(String.format("%s is not available", receiver))
Expand All @@ -94,9 +92,9 @@ protected Description check(ExpressionTree tree, VisitorState state) {
}
ClassMemberKey memberKey =
ClassMemberKey.create(
sym.getSimpleName().toString(), Signatures.descriptor(sym.type, types));
sym.getSimpleName().toString(), Signatures.descriptor(sym.type, state));
ClassSymbol owner = sym.owner.enclClass();
if (apiDiff.isMemberUnsupported(Signatures.classDescriptor(owner.type, types), memberKey)
if (apiDiff.isMemberUnsupported(Signatures.classDescriptor(owner.type, state), memberKey)
|| hasAnnotationForbiddingUse(sym, state)) {
return buildDescription(tree)
.setMessage(String.format("%s#%s is not available in %s", owner, sym, receiver))
Expand Down

0 comments on commit 32fe079

Please sign in to comment.