From 6b13adfaa2899519ee4333ef730476e978186c3e Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 15 Jun 2026 02:56:29 -0700 Subject: [PATCH] Fix a crash in ReferenceEquality Use `getEnclosedElements` which handles symbol completion failures gracefully, and fix a bug in `SuggestedFixes.qualifyType` where it crashed if there were ambiguous wildcard imports. PiperOrigin-RevId: 932339804 --- .../errorprone/fixes/SuggestedFixes.java | 3 +++ .../bugpatterns/ReferenceEquality.java | 26 +++++++++---------- .../bugpatterns/ReferenceEqualityTest.java | 26 +++++++++++++++++++ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/check_api/src/main/java/com/google/errorprone/fixes/SuggestedFixes.java b/check_api/src/main/java/com/google/errorprone/fixes/SuggestedFixes.java index d5bba61bb5e..cfa2637744c 100644 --- a/check_api/src/main/java/com/google/errorprone/fixes/SuggestedFixes.java +++ b/check_api/src/main/java/com/google/errorprone/fixes/SuggestedFixes.java @@ -497,6 +497,9 @@ public static String qualifyType(VisitorState state, SuggestedFix.Builder fix, S return components.subList(i, components.size()).stream().collect(joining(".")); } // Type already imported or otherwise visible. + if (found.getKind().equals(ElementKind.OTHER)) { + continue; + } if (found.getQualifiedName().contentEquals(qualifiedName)) { return components.subList(i, components.size()).stream().collect(joining(".")); } diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/ReferenceEquality.java b/core/src/main/java/com/google/errorprone/bugpatterns/ReferenceEquality.java index fd180563827..fd89f3fa2be 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/ReferenceEquality.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/ReferenceEquality.java @@ -16,9 +16,10 @@ package com.google.errorprone.bugpatterns; -import static com.google.common.collect.Iterables.getOnlyElement; +import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; import static com.google.errorprone.VisitorState.memoize; +import static com.google.errorprone.util.ASTHelpers.getEnclosedElements; import static com.google.errorprone.util.ASTHelpers.getUpperBound; import static com.google.errorprone.util.ASTHelpers.isSameType; import static com.google.errorprone.util.ASTHelpers.isSubtype; @@ -34,7 +35,6 @@ import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.LambdaExpressionTree; import com.sun.source.tree.MethodTree; -import com.sun.tools.javac.code.Scope; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; @@ -105,14 +105,16 @@ private static boolean overridesMethodOnType( Type overriddenType, String overriddenMethodName, VisitorState state) { - Symbol overriddenMethodSymbol = getOnlyMember(state, overriddenType, overriddenMethodName); + Symbol overriddenMethodSymbol = getOnlyMember(overriddenType, overriddenMethodName); return methodSymbol.getSimpleName().contentEquals(overriddenMethodName) && methodSymbol.overrides( overriddenMethodSymbol, classType.tsym, state.getTypes(), /* checkResult= */ false); } - private static Symbol getOnlyMember(VisitorState state, Type type, String name) { - return getOnlyElement(type.tsym.members().getSymbolsByName(state.getName(name))); + private static Symbol getOnlyMember(Type type, String name) { + return getEnclosedElements(type.tsym).stream() + .filter(s -> s.getSimpleName().contentEquals(name)) + .collect(onlyElement()); } /** @@ -184,18 +186,16 @@ private static boolean definitelyUsesReferenceEquality(Type type, VisitorState s */ private static boolean implementsEquals(Type type, VisitorState state) { Name equalsName = EQUALS.get(state); - Symbol objectEquals = getOnlyMember(state, state.getSymtab().objectType, "equals"); + Symbol objectEquals = getOnlyMember(state.getSymtab().objectType, "equals"); for (Type sup : state.getTypes().closure(type)) { if (isSameType(sup, state.getSymtab().objectType, state)) { continue; } - Scope scope = sup.tsym.members(); - if (scope == null) { - continue; - } - for (Symbol sym : scope.getSymbolsByName(equalsName)) { - if (sym.overrides(objectEquals, type.tsym, state.getTypes(), /* checkResult= */ false)) { - return true; + for (Symbol sym : getEnclosedElements(sup.tsym)) { + if (sym.getSimpleName().contentEquals(equalsName)) { + if (sym.overrides(objectEquals, type.tsym, state.getTypes(), /* checkResult= */ false)) { + return true; + } } } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ReferenceEqualityTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ReferenceEqualityTest.java index 6613e62fd5a..28b7ae74688 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ReferenceEqualityTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ReferenceEqualityTest.java @@ -900,4 +900,30 @@ boolean f(MemorySegment a) { """) .doTest(); } + + @Test + public void ambiguousImport() { + compilationHelper + .addSourceLines( + "Objects.java", + """ + package test; + + public class Objects {} + """) + .addSourceLines( + "Test.java", + """ + import java.util.*; + import test.*; + + class Test { + boolean f(String a, String b) { + // BUG: Diagnostic contains: java.util.Objects.equals(a, b) + return a == b; + } + } + """) + .doTest(); + } }