Skip to content

Commit

Permalink
Fix a JDK 17 incompatibility
Browse files Browse the repository at this point in the history
Fixes #2330

PiperOrigin-RevId: 373683703
  • Loading branch information
cushon authored and Error Prone Team committed May 13, 2021
1 parent 8c6f73c commit 91e56ea
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 37 deletions.
19 changes: 10 additions & 9 deletions check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.base.Predicate;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
Expand Down Expand Up @@ -133,7 +132,6 @@
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.FatalError;
import com.sun.tools.javac.util.Filter;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
import com.sun.tools.javac.util.Name;
Expand All @@ -153,6 +151,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -654,11 +653,8 @@ private static Stream<MethodSymbol> findSuperMethods(
* in an unspecified order.
*/
public static Stream<MethodSymbol> matchingMethods(
Name name,
java.util.function.Predicate<MethodSymbol> predicate,
Type startClass,
Types types) {
Filter<Symbol> matchesMethodPredicate =
Name name, Predicate<MethodSymbol> predicate, Type startClass, Types types) {
Predicate<Symbol> matchesMethodPredicate =
sym -> sym instanceof MethodSymbol && predicate.test((MethodSymbol) sym);

// Iterate over all classes and interfaces that startClass inherits from.
Expand All @@ -672,8 +668,8 @@ public static Stream<MethodSymbol> matchingMethods(
return Stream.empty();
}
return Streams.stream(
superClassSymbols.getSymbolsByName(
name, matchesMethodPredicate, NON_RECURSIVE))
scope(superClassSymbols)
.getSymbolsByName(name, matchesMethodPredicate, NON_RECURSIVE))
// By definition of the filter, we know that the symbol is a MethodSymbol.
.map(symbol -> (MethodSymbol) symbol);
});
Expand Down Expand Up @@ -2179,5 +2175,10 @@ public static boolean isLocal(Symbol symbol) {
}
}

/** Returns a compatibility adapter around {@link Scope}. */
public static ErrorProneScope scope(Scope scope) {
return new ErrorProneScope(scope);
}

private ASTHelpers() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2021 The Error Prone Authors.
*
* 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.errorprone.util;

import static com.google.common.base.Preconditions.checkState;

import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Scope.LookupKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.util.Name;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.function.Predicate;

/** A compatibility wrapper around {@link com.sun.tools.javac.util.Filter} */
public final class ErrorProneScope {

@SuppressWarnings("unchecked") // reflection
public Iterable<Symbol> getSymbolsByName(Name name, Predicate<Symbol> predicate) {
return (Iterable<Symbol>) invoke(getSymbolsByName, name, maybeAsFilter(predicate));
}

@SuppressWarnings("unchecked") // reflection
public Iterable<Symbol> getSymbolsByName(
Name name, Predicate<Symbol> predicate, LookupKind lookupKind) {
return (Iterable<Symbol>)
invoke(getSymbolsByNameLookupKind, name, maybeAsFilter(predicate), lookupKind);
}

@SuppressWarnings("unchecked") // reflection
public Iterable<Symbol> getSymbols(Predicate<Symbol> predicate) {
return (Iterable<Symbol>) invoke(getSymbols, maybeAsFilter(predicate));
}

public boolean anyMatch(Predicate<Symbol> predicate) {
return (boolean) invoke(anyMatch, maybeAsFilter(predicate));
}

private static final Class<?> filterClass = getFilterClass();

private static Class<?> getFilterClass() {
try {
return Class.forName("com.sun.tools.javac.util.Filter");
} catch (ClassNotFoundException e) {
return null;
}
}

private static final Method anyMatch = getImpl("anyMatch", Predicate.class);

private static final Method getSymbolsByName =
getImpl("getSymbolsByName", Name.class, Predicate.class);

private static final Method getSymbolsByNameLookupKind =
getImpl("getSymbolsByName", Name.class, Predicate.class, LookupKind.class);

private static final Method getSymbols = getImpl("getSymbols", Predicate.class);

private static Method getImpl(String name, Class<?>... parameters) {
return filterClass != null
? getMethodOrDie(
Scope.class,
name,
Arrays.stream(parameters)
.map(p -> p.equals(Predicate.class) ? filterClass : p)
.toArray(Class<?>[]::new))
: getMethodOrDie(Scope.class, name, parameters);
}

private final Scope scope;

ErrorProneScope(Scope scope) {
this.scope = scope;
}

private Object invoke(Method method, Object... args) {
try {
return method.invoke(scope, args);
} catch (ReflectiveOperationException e) {
throw new LinkageError(e.getMessage(), e);
}
}

private Object maybeAsFilter(Predicate<Symbol> predicate) {
if (filterClass == null) {
return predicate;
}
return Proxy.newProxyInstance(
getClass().getClassLoader(),
new Class<?>[] {filterClass},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
checkState(method.getName().equals("accepts"));
return predicate.test((Symbol) args[0]);
}
});
}

private static Method getMethodOrDie(Class<?> clazz, String name, Class<?>... parameters) {
try {
return clazz.getMethod(name, parameters);
} catch (NoSuchMethodException e) {
throw new LinkageError(e.getMessage(), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public static ImmutableSet<VarSymbol> findAllIdents(VisitorState state) {
for (Type type : superTypes) {
Scope scope = type.tsym.members();
ImmutableList.Builder<VarSymbol> varsList = ImmutableList.builder();
for (Symbol var : scope.getSymbols(VarSymbol.class::isInstance)) {
for (Symbol var : ASTHelpers.scope(scope).getSymbols(VarSymbol.class::isInstance)) {
varsList.add((VarSymbol) var);
}
result.addAll(varsList.build().reverse());
Expand Down Expand Up @@ -250,10 +250,12 @@ public static ImmutableSet<VarSymbol> findAllIdents(VisitorState state) {
ASTHelpers.getType(memberSelectTree.getExpression()),
/* skipInterface= */ false);
for (Symbol var :
scope.getSymbols(
sym ->
sym instanceof VarSymbol
&& sym.getSimpleName().equals(memberSelectTree.getIdentifier()))) {
ASTHelpers.scope(scope)
.getSymbols(
sym ->
sym instanceof VarSymbol
&& sym.getSimpleName()
.equals(memberSelectTree.getIdentifier()))) {
result.add((VarSymbol) var);
}
}
Expand Down Expand Up @@ -330,7 +332,8 @@ public static ImmutableList<VarSymbol> findAllFields(Type classType, VisitorStat
if (scope == null) {
return ImmutableList.<VarSymbol>of().stream();
}
return ImmutableList.copyOf(scope.getSymbols(VarSymbol.class::isInstance))
return ImmutableList.copyOf(
ASTHelpers.scope(scope).getSymbols(VarSymbol.class::isInstance))
.reverse()
.stream()
.map(v -> (VarSymbol) v)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ private Description check(Tree tree, Name simpleName, VisitorState state) {
PackageSymbol javaLang = symtab.enterPackage(symtab.java_base, state.getNames().java_lang);
Symbol other =
getFirst(
javaLang.members().getSymbolsByName(simpleName, s -> s.getModifiers().contains(PUBLIC)),
ASTHelpers.scope(javaLang.members())
.getSymbolsByName(simpleName, s -> s.getModifiers().contains(PUBLIC)),
null);
Symbol symbol = ASTHelpers.getSymbol(tree);
if (other == null || other.equals(symbol)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
Expand Down Expand Up @@ -64,8 +65,7 @@ private static boolean finalNoOverrides(Type type, VisitorState state) {
// implements and we collect all overrides of java.lang.Object.toString(). If one of those
// overrides is present, then we don't flag it.
return Iterables.isEmpty(
types
.membersClosure(type, /* skipInterface= */ false)
ASTHelpers.scope(types.membersClosure(type, /* skipInterface= */ false))
.getSymbolsByName(
names.toString,
m ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,7 @@ private static MethodSymbol superclassConstructorSymbol(NewClassTree tree, Visit

return (MethodSymbol)
getOnlyElement(
superclass
.members()
ASTHelpers.scope(superclass.members())
.getSymbols(
member ->
member.isConstructor()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.predicates.TypePredicates;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.util.ASTHelpers.TargetType;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type;
Expand Down Expand Up @@ -77,9 +78,9 @@ public Description matchMemberReference(MemberReferenceTree tree, VisitorState s
return NO_MATCH;
}
MethodSymbol symbol = getSymbol(tree);
WriteableScope members = targetType.type().tsym.members();
if (!members.anyMatch(
sym -> isFunctionalInterfaceInvocation(symbol, targetType.type(), sym, state))
Scope members = targetType.type().tsym.members();
if (!ASTHelpers.scope(members)
.anyMatch(sym -> isFunctionalInterfaceInvocation(symbol, targetType.type(), sym, state))
&& !isKnownAlias(tree, targetType.type(), state)) {
return NO_MATCH;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ private static Symbol getFinalizer(VisitorState state, ClassSymbol enclosing) {
}

private static Stream<VarSymbol> getFields(TypeSymbol s) {
return Streams.stream(s.members().getSymbols(m -> m.getKind() == ElementKind.FIELD))
return Streams.stream(
ASTHelpers.scope(s.members()).getSymbols(m -> m.getKind() == ElementKind.FIELD))
.map(VarSymbol.class::cast);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.util.Filter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeKind;
Expand Down Expand Up @@ -229,13 +229,8 @@ Violation areFieldsImmutable(
if (classSym.members() == null) {
return Violation.absent();
}
Filter<Symbol> instanceFieldFilter =
new Filter<Symbol>() {
@Override
public boolean accepts(Symbol symbol) {
return symbol.getKind() == ElementKind.FIELD && !symbol.isStatic();
}
};
Predicate<Symbol> instanceFieldFilter =
symbol -> symbol.getKind() == ElementKind.FIELD && !symbol.isStatic();
Map<Symbol, Tree> declarations = new HashMap<>();
if (tree.isPresent()) {
for (Tree member : tree.get().getMembers()) {
Expand All @@ -248,7 +243,8 @@ public boolean accepts(Symbol symbol) {
// javac gives us members in reverse declaration order
// handling them in declaration order leads to marginally better diagnostics
List<Symbol> members =
ImmutableList.copyOf(classSym.members().getSymbols(instanceFieldFilter)).reverse();
ImmutableList.copyOf(ASTHelpers.scope(classSym.members()).getSymbols(instanceFieldFilter))
.reverse();
for (Symbol member : members) {
Optional<Tree> memberTree = Optional.ofNullable(declarations.get(member));
Violation info =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.util.Filter;
import com.sun.tools.javac.util.Name;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -400,7 +399,7 @@ private static boolean hasTimeSourceMethod(MethodInvocationTree tree, VisitorSta
// Adapted from ASTHelpers.findMatchingMethods(); but this short-circuits
private static boolean hasMatchingMethods(
Name name, final Predicate<MethodSymbol> predicate, Type startClass, Types types) {
Filter<Symbol> matchesMethodPredicate =
Predicate<Symbol> matchesMethodPredicate =
sym -> sym instanceof MethodSymbol && predicate.apply((MethodSymbol) sym);

// Iterate over all classes and interfaces that startClass inherits from.
Expand All @@ -410,7 +409,8 @@ private static boolean hasMatchingMethods(
Scope superClassSymbols = superClassSymbol.members();
if (superClassSymbols != null) { // Can be null if superClass is a type variable
if (!Iterables.isEmpty(
superClassSymbols.getSymbolsByName(name, matchesMethodPredicate, NON_RECURSIVE))) {
ASTHelpers.scope(superClassSymbols)
.getSymbolsByName(name, matchesMethodPredicate, NON_RECURSIVE))) {
return true;
}
}
Expand Down

0 comments on commit 91e56ea

Please sign in to comment.