Bug 99622 Rename method misses ambiguously overridden method
RippleMethodFinder2 now has a MultiMap for the fTypeToMethod field
because with Generics it is possible to implement more than one method
in a super interface
Change-Id: I187127fae2dc2d6439a795bef915109875ca1eca
Signed-off-by: Nikolay Metchev <nikolaymetchev@gmail.com>
Signed-off-by: Jeff Johnston <jjohnstn@redhat.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/70037
Tested-by: JDT Bot <jdt-bot@eclipse.org>
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/MethodOverrideTester.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/MethodOverrideTester.java
index 00a5374..04ef60c 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/MethodOverrideTester.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/MethodOverrideTester.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,12 +10,15 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Nikolay Metchev <nikolaymetchev@gmail.com> - [rename] https://bugs.eclipse.org/99622
*******************************************************************************/
package org.eclipse.jdt.internal.corext.util;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import org.eclipse.core.runtime.Assert;
@@ -180,6 +183,28 @@
}
return method;
}
+
+ /**
+ * Finds all overridden methods in a type and its super types. First the super class is examined and then the implemented interfaces.
+ * With generics it is possible that 2 methods in the same type are overidden at the same time. In that case all overrides are returned
+ * @param type The type to find methods in
+ * @param overriding The overriding method
+ * @return The overridden methods or an empty set if no method is overridden
+ * @throws JavaModelException if a problem occurs
+ */
+ public Set<IMethod> findAllOverriddenMethodsInHierarchy(IType type, IMethod overriding) throws JavaModelException {
+ Set<IMethod> ans = findAllOverriddenMethodsInType(type, overriding);
+ IType superClass= fHierarchy.getSuperclass(type);
+ if (superClass != null) {
+ ans.addAll(findAllOverriddenMethodsInHierarchy(superClass, overriding));
+ }
+ IType[] superInterfaces= fHierarchy.getSuperInterfaces(type);
+ for (int i= 0; i < superInterfaces.length; i++) {
+ ans.addAll(findAllOverriddenMethodsInHierarchy(superInterfaces[i], overriding));
+ }
+ return ans;
+ }
+
/**
* Finds an overridden method in a type. With generics it is possible that 2 methods in the same type are overridden at the same time.
@@ -203,6 +228,33 @@
}
return null;
}
+
+ /**
+ * Finds all overridden methods in a type. With generics it is possible that 2 methods in the same type are overridden at the same time.
+ * In that case all overridden methods found are returned.
+ * @param overriddenType The type to find methods in
+ * @param overriding The overriding method
+ * @return All overridden methods or an empty set if no method is overridden
+ * @throws JavaModelException if a problem occurs
+ */
+ public Set<IMethod> findAllOverriddenMethodsInType(IType overriddenType, IMethod overriding) throws JavaModelException {
+ Set<IMethod> ans = new HashSet<>();
+ int flags= overriding.getFlags();
+ if (Flags.isPrivate(flags) || Flags.isStatic(flags) || overriding.isConstructor())
+ return ans;
+ IMethod[] overriddenMethods= overriddenType.getMethods();
+ for (int i= 0; i < overriddenMethods.length; i++) {
+ IMethod overridden= overriddenMethods[i];
+ flags= overridden.getFlags();
+ if (Flags.isPrivate(flags) || Flags.isStatic(flags) || overridden.isConstructor())
+ continue;
+ if (isSubsignature(overriding, overridden)) {
+ ans.add(overridden);
+ }
+ }
+ return ans;
+ }
+
/**
* Finds an overriding method in a type.
@@ -549,4 +601,14 @@
}
}
+ /**
+ * Finds all overrides for the passed in method.
+ * With generics it is possible that 2 methods in the same type are overridden at the same time. In that case all overrides are returned
+ * @param overriding The overriding method
+ * @return The overridden methods or an empty set if no method is overridden
+ * @throws JavaModelException if a problem occurs
+ */
+ public Set<IMethod> findAllOverridenMethods(IMethod overriding) throws JavaModelException {
+ return findAllOverriddenMethodsInHierarchy(overriding.getDeclaringType(), overriding);
+ }
}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test41/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test41/in/A.java
new file mode 100644
index 0000000..ab751ae
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test41/in/A.java
@@ -0,0 +1,16 @@
+//can rename A.m to k
+package p;
+interface I {
+
+}
+class B<T, K extends I> {
+ void m(T t) {
+ }
+ void m(K t) {
+ }
+}
+class A extends B<I, I> {
+ @Override
+ void m(I i) {
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test41/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test41/out/A.java
new file mode 100644
index 0000000..192c543
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test41/out/A.java
@@ -0,0 +1,16 @@
+//can rename A.m to k
+package p;
+interface I {
+
+}
+class B<T, K extends I> {
+ void k(T t) {
+ }
+ void k(K t) {
+ }
+}
+class A extends B<I, I> {
+ @Override
+ void k(I i) {
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test42/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test42/in/A.java
new file mode 100644
index 0000000..3f7c770
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test42/in/A.java
@@ -0,0 +1,16 @@
+//can rename A.m(T) to k
+package p;
+interface I {
+
+}
+class A<T, K extends I> {
+ void m(T t) {
+ }
+ void m(K t) {
+ }
+}
+class B extends A<I, I> {
+ @Override
+ void m(I i) {
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test42/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test42/out/A.java
new file mode 100644
index 0000000..fa2814b
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test42/out/A.java
@@ -0,0 +1,16 @@
+//can rename A.m(T) to k
+package p;
+interface I {
+
+}
+class A<T, K extends I> {
+ void k(T t) {
+ }
+ void k(K t) {
+ }
+}
+class B extends A<I, I> {
+ @Override
+ void k(I i) {
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test43/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test43/in/A.java
new file mode 100644
index 0000000..0272802
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test43/in/A.java
@@ -0,0 +1,20 @@
+//can rename A.m(Object) to k
+package p;
+
+class A1 extends C3 {
+ class A extends C<Object> implements I1<Object> {
+ public void m(Object o) {
+ }
+ }
+}
+
+class C3 {
+ class C<E> {
+ public void m(E e) {
+ }
+ }
+}
+
+interface I1<T> {
+ void m(T t);
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test43/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test43/out/A.java
new file mode 100644
index 0000000..ffa882a
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test43/out/A.java
@@ -0,0 +1,20 @@
+//can rename A.m(Object) to k
+package p;
+
+class A1 extends C3 {
+ class A extends C<Object> implements I1<Object> {
+ public void k(Object o) {
+ }
+ }
+}
+
+class C3 {
+ class C<E> {
+ public void k(E e) {
+ }
+ }
+}
+
+interface I1<T> {
+ void k(T t);
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test44/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test44/in/A.java
new file mode 100644
index 0000000..2ecc25f
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test44/in/A.java
@@ -0,0 +1,20 @@
+//can rename A.m(E) to k
+package p;
+
+class A1 extends C3 {
+ class A2 extends A<Object> implements I1<Object> {
+ public void m(Object o) {
+ }
+ }
+}
+
+class C3 {
+ class A<E> {
+ public void m(E e) {
+ }
+ }
+}
+
+interface I1<T> {
+ void m(T t);
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test44/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test44/out/A.java
new file mode 100644
index 0000000..8005006
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test44/out/A.java
@@ -0,0 +1,20 @@
+//can rename A.m(E) to k
+package p;
+
+class A1 extends C3 {
+ class A2 extends A<Object> implements I1<Object> {
+ public void k(Object o) {
+ }
+ }
+}
+
+class C3 {
+ class A<E> {
+ public void k(E e) {
+ }
+ }
+}
+
+interface I1<T> {
+ void k(T t);
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test45/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test45/in/A.java
new file mode 100644
index 0000000..a2bb91a
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test45/in/A.java
@@ -0,0 +1,20 @@
+//can rename A.m(T) to k
+package p;
+
+class A1 extends C3 {
+ class A2 extends C<Object> implements A<Object> {
+ public void m(Object o) {
+ }
+ }
+}
+
+class C3 {
+ class C<E> {
+ public void m(E e) {
+ }
+ }
+}
+
+interface A<T> {
+ void m(T t);
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test45/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test45/out/A.java
new file mode 100644
index 0000000..646443e
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test45/out/A.java
@@ -0,0 +1,20 @@
+//can rename A.m(T) to k
+package p;
+
+class A1 extends C3 {
+ class A2 extends C<Object> implements A<Object> {
+ public void k(Object o) {
+ }
+ }
+}
+
+class C3 {
+ class C<E> {
+ public void k(E e) {
+ }
+ }
+}
+
+interface A<T> {
+ void k(T t);
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test46/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test46/in/A.java
new file mode 100644
index 0000000..a9876bb
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test46/in/A.java
@@ -0,0 +1,10 @@
+//can rename A.m(E[]) to k
+package p;
+
+class A<E> {
+ void m(E[] e) {}
+ void m(String[] t) {};
+}
+class Sub extends A<String> {
+ void m(String... s) {}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test46/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test46/out/A.java
new file mode 100644
index 0000000..40e6eb0
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test46/out/A.java
@@ -0,0 +1,10 @@
+//can rename A.m(E[]) to k
+package p;
+
+class A<E> {
+ void k(E[] e) {}
+ void k(String[] t) {};
+}
+class Sub extends A<String> {
+ void k(String... s) {}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test47/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test47/in/A.java
new file mode 100644
index 0000000..bad38ad
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test47/in/A.java
@@ -0,0 +1,10 @@
+//can rename A.m(String[]) to k
+package p;
+
+class A<E> {
+ void m(E[] e) {}
+ void m(String[] t) {};
+}
+class Sub extends A<String> {
+ void m(String... s) {}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test47/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test47/out/A.java
new file mode 100644
index 0000000..6f7da09
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test47/out/A.java
@@ -0,0 +1,10 @@
+//can rename A.m(String[]) to k
+package p;
+
+class A<E> {
+ void k(E[] e) {}
+ void k(String[] t) {};
+}
+class Sub extends A<String> {
+ void k(String... s) {}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test48/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test48/in/A.java
new file mode 100644
index 0000000..4ebe646
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test48/in/A.java
@@ -0,0 +1,10 @@
+//can rename A.m(String...) to k
+package p;
+
+class Sup<E> {
+ void m(E[] e) {}
+ void m(String[] t) {};
+}
+class A extends Sup<String> {
+ void m(String... s) {}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test48/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test48/out/A.java
new file mode 100644
index 0000000..56ae7cf
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameVirtualMethodInClass/test48/out/A.java
@@ -0,0 +1,10 @@
+//can rename A.m(String...) to k
+package p;
+
+class Sup<E> {
+ void k(E[] e) {}
+ void k(String[] t) {};
+}
+class A extends Sup<String> {
+ void k(String... s) {}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameVirtualMethodInClassTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameVirtualMethodInClassTests.java
index 4d6c8c1..9dd1b70 100644
--- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameVirtualMethodInClassTests.java
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameVirtualMethodInClassTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Nikolay Metchev <nikolaymetchev@gmail.com> - [rename] https://bugs.eclipse.org/99622
*******************************************************************************/
package org.eclipse.jdt.ui.tests.refactoring;
@@ -495,6 +496,38 @@
helper2();
}
+ public void test41() throws Exception {
+ helper2_0("m", "k", new String[] { "QI;" });
+ }
+
+ public void test42() throws Exception {
+ helper2_0("m", "k", new String[] { "QT;" });
+ }
+
+ public void test43() throws Exception {
+ helper2_0("m", "k", new String[] { "QObject;" });
+ }
+
+ public void test44() throws Exception {
+ helper2_0("m", "k", new String[] { "QE;" });
+ }
+
+ public void test45() throws Exception {
+ helper2_0("m", "k", new String[] { "QT;" });
+ }
+
+ public void test46() throws Exception {
+ helper2_0("m", "k", new String[] { "[QE;" });
+ }
+
+ public void test47() throws Exception {
+ helper2_0("m", "k", new String[] { "[QString;" });
+ }
+
+ public void test48() throws Exception {
+ helper2_0("m", "k", new String[] { "[QString;" });
+ }
+
//anonymous inner class
@Test
public void test23() throws Exception{
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameVirtualMethodProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameVirtualMethodProcessor.java
index dba9de0..8c52643 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameVirtualMethodProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameVirtualMethodProcessor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Nikolay Metchev <nikolaymetchev@gmail.com> - [rename] https://bugs.eclipse.org/99622
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.rename;
@@ -46,7 +47,6 @@
public class RenameVirtualMethodProcessor extends RenameMethodProcessor {
- private IMethod fOriginalMethod;
private boolean fActivationChecked;
private ITypeHierarchy fCachedHierarchy= null;
@@ -57,7 +57,6 @@
*/
public RenameVirtualMethodProcessor(IMethod method) {
super(method);
- fOriginalMethod= getMethod();
}
/**
@@ -71,7 +70,6 @@
this(method);
RefactoringStatus initializeStatus= initialize(arguments);
status.merge(initializeStatus);
- fOriginalMethod= getMethod();
}
/*
@@ -84,16 +82,11 @@
*/
RenameVirtualMethodProcessor(IMethod topLevel, IMethod[] ripples, TextChangeManager changeManager, ITypeHierarchy hierarchy, GroupCategorySet categorySet) {
super(topLevel, changeManager, categorySet);
- fOriginalMethod= getMethod();
fActivationChecked= true; // is top level
fCachedHierarchy= hierarchy; // may be null
setMethodsToRename(ripples);
}
- public IMethod getOriginalMethod() {
- return fOriginalMethod;
- }
-
private ITypeHierarchy getCachedHierarchy(IType declaring, IProgressMonitor monitor) throws JavaModelException {
if (fCachedHierarchy != null && declaring.equals(fCachedHierarchy.getType()))
return fCachedHierarchy;
@@ -117,19 +110,7 @@
monitor.beginTask("", 3); //$NON-NLS-1$
if (!fActivationChecked) {
// the following code may change the method to be changed.
- IMethod method= getMethod();
- fOriginalMethod= method;
-
- ITypeHierarchy hierarchy= null;
- IType declaringType= method.getDeclaringType();
- if (!declaringType.isInterface())
- hierarchy= getCachedHierarchy(declaringType, new SubProgressMonitor(monitor, 1));
-
- IMethod topmost= getMethod();
- if (MethodChecks.isVirtual(topmost))
- topmost= MethodChecks.getTopmostMethod(getMethod(), hierarchy, monitor);
- if (topmost != null)
- initialize(topmost);
+ initialize(getMethod());
fActivationChecked= true;
}
} finally{
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RippleMethodFinder2.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RippleMethodFinder2.java
index 7ab3b4d..c571c16 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RippleMethodFinder2.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RippleMethodFinder2.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Nikolay Metchev <nikolaymetchev@gmail.com> - [rename] https://bugs.eclipse.org/99622
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.rename;
@@ -28,10 +29,10 @@
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
-import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IRegion;
import org.eclipse.jdt.core.IType;
@@ -50,14 +51,15 @@
import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
import org.eclipse.jdt.internal.corext.refactoring.base.ReferencesInBinaryContext;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+import org.eclipse.jdt.internal.corext.util.MethodOverrideTester;
import org.eclipse.jdt.internal.corext.util.SearchUtils;
public class RippleMethodFinder2 {
private final IMethod fMethod;
- private List<IMethod> fDeclarations;
+ private Set<IMethod> fDeclarations;
private ITypeHierarchy fHierarchy;
- private Map<IType, IMethod> fTypeToMethod;
+ private MultiMap<IType, IMethod> fTypeToMethod;
private Set<IType> fRootTypes;
private MultiMap<IType, IType> fRootReps;
private Map<IType, ITypeHierarchy> fRootHierarchies;
@@ -66,6 +68,7 @@
private final boolean fExcludeBinaries;
private final ReferencesInBinaryContext fBinaryRefs;
private Map<IMethod, SearchMatch> fDeclarationToMatch;
+ private boolean fSearchOnlyInCompilationUnit = false;
private static class MultiMap<K, V> {
HashMap<K, Collection<V>> fImplementation= new HashMap<>();
@@ -131,9 +134,10 @@
}
- private RippleMethodFinder2(IMethod method, boolean excludeBinaries){
+ private RippleMethodFinder2(IMethod method, boolean excludeBinaries, boolean searchOnlyInCompilationUnit){
fMethod= method;
fExcludeBinaries= excludeBinaries;
+ fSearchOnlyInCompilationUnit= searchOnlyInCompilationUnit;
fBinaryRefs= null;
}
@@ -149,7 +153,17 @@
if (! MethodChecks.isVirtual(method))
return new IMethod[]{ method };
- return new RippleMethodFinder2(method, excludeBinaries).getAllRippleMethods(pm, owner);
+ return new RippleMethodFinder2(method, excludeBinaries, false).getAllRippleMethods(pm, owner);
+ } finally{
+ pm.done();
+ }
+ }
+ public static IMethod[] getRelatedMethodsInCompilationUnit(IMethod method, NullProgressMonitor pm, WorkingCopyOwner owner) throws CoreException {
+ try{
+ if (! MethodChecks.isVirtual(method))
+ return new IMethod[]{ method };
+
+ return new RippleMethodFinder2(method, true, true).getAllRippleMethods(pm, owner);
} finally{
pm.done();
}
@@ -198,6 +212,7 @@
Assert.isTrue(false, "Search for method declaration did not find original element: " + fMethod.toString()); //$NON-NLS-1$
createHierarchyOfDeclarations(new SubProgressMonitor(pm, 1), owner);
+ addMissedSuperTypes();
createTypeToMethod();
createUnionFind();
checkCanceled(pm);
@@ -206,7 +221,7 @@
fRootTypes= null;
Map<IType, List<IType>> partitioning= new HashMap<>();
- for (IType type : fTypeToMethod.keySet()) {
+ for (IType type : fTypeToMethod.fImplementation.keySet()) {
IType rep= fUnionFind.find(type);
List<IType> types= partitioning.get(rep);
if (types == null)
@@ -225,7 +240,7 @@
boolean hasRelatedInterfaces= false;
List<IMethod> relatedMethods= new ArrayList<>();
for (IType relatedType : relatedTypes) {
- relatedMethods.add(fTypeToMethod.get(relatedType));
+ relatedMethods.addAll(fTypeToMethod.get(relatedType));
if (relatedType.isInterface())
hasRelatedInterfaces= true;
}
@@ -283,15 +298,17 @@
HashSet<IType> marriedAlienTypeReps= new HashSet<>();
for (IType alienType : alienTypes) {
checkCanceled(pm);
- IMethod alienMethod= fTypeToMethod.get(alienType);
- ITypeHierarchy hierarchy= hierarchy(pm, owner, alienType);
+ Collection<IMethod> alienMethods= fTypeToMethod.get(alienType);
+ for (IMethod alienMethod : alienMethods) {
+ ITypeHierarchy hierarchy= hierarchy(pm, owner, alienType);
- for (IType subtype : hierarchy.getAllSubtypes(alienType)) {
- if (relatedSubTypes.contains(subtype)) {
- if (JavaModelUtil.isVisibleInHierarchy(alienMethod, subtype.getPackageFragment())) {
- marriedAlienTypeReps.add(fUnionFind.find(alienType));
- } else {
- // not overridden
+ for (IType subtype : hierarchy.getAllSubtypes(alienType)) {
+ if (relatedSubTypes.contains(subtype)) {
+ if (JavaModelUtil.isVisibleInHierarchy(alienMethod, subtype.getPackageFragment())) {
+ marriedAlienTypeReps.add(fUnionFind.find(alienType));
+ } else {
+ // not overridden
+ }
}
}
}
@@ -303,7 +320,7 @@
for (IType marriedAlienTypeRep : marriedAlienTypeReps) {
List<IType> marriedAlienTypes= partitioning.get(marriedAlienTypeRep);
for (IType marriedAlienInterfaceType : marriedAlienTypes) {
- relatedMethods.add(fTypeToMethod.get(marriedAlienInterfaceType));
+ relatedMethods.addAll(fTypeToMethod.get(marriedAlienInterfaceType));
}
alienTypes.removeAll(marriedAlienTypes); //not alien any more
relatedTypesToProcess.addAll(marriedAlienTypes); //process freshly married types again
@@ -385,6 +402,16 @@
return hierarchy;
}
+ private void addMissedSuperTypes() throws JavaModelException {
+ Set<IMethod> newDeclarations = new HashSet<>();
+ for (IMethod method : fDeclarations) {
+ MethodOverrideTester methodOverrideTester= new MethodOverrideTester(method.getDeclaringType(), fHierarchy);
+ newDeclarations.addAll(methodOverrideTester.findAllOverridenMethods(method));
+ }
+ fDeclarations.addAll(newDeclarations);
+
+ }
+
private ITypeHierarchy getCachedHierarchy(IType type, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
IType rep= fUnionFind.find(type);
if (rep != null) {
@@ -402,7 +429,7 @@
}
private void findAllDeclarations(IProgressMonitor monitor, WorkingCopyOwner owner) throws CoreException {
- fDeclarations= new ArrayList<>();
+ fDeclarations= new HashSet<>();
class MethodRequestor extends SearchRequestor {
@Override
@@ -427,7 +454,12 @@
int matchRule= SearchPattern.R_ERASURE_MATCH | SearchPattern.R_CASE_SENSITIVE;
SearchPattern pattern= SearchPattern.createPattern(fMethod, limitTo, matchRule);
SearchParticipant[] participants= SearchUtils.getDefaultSearchParticipants();
- IJavaSearchScope scope= RefactoringScopeFactory.createRelatedProjectsScope(fMethod.getJavaProject(), IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SYSTEM_LIBRARIES);
+ IJavaSearchScope scope;
+ if (fSearchOnlyInCompilationUnit) {
+ scope= RefactoringScopeFactory.create(fMethod.getCompilationUnit());
+ } else {
+ scope= RefactoringScopeFactory.createRelatedProjectsScope(fMethod.getJavaProject(), IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SYSTEM_LIBRARIES);
+ }
MethodRequestor requestor= new MethodRequestor();
SearchEngine searchEngine= owner != null ? new SearchEngine(owner) : new SearchEngine();
@@ -449,19 +481,19 @@
}
private void createTypeToMethod() {
- fTypeToMethod= new HashMap<>();
+ fTypeToMethod= new MultiMap<>();
for (IMethod declaration : fDeclarations) {
fTypeToMethod.put(declaration.getDeclaringType(), declaration);
}
}
private void createUnionFind() throws JavaModelException {
- fRootTypes= new HashSet<>(fTypeToMethod.keySet());
+ fRootTypes= new HashSet<>(fTypeToMethod.fImplementation.keySet());
fUnionFind= new UnionFind();
- for (IType type : fTypeToMethod.keySet()) {
+ for (IType type : fTypeToMethod.fImplementation.keySet()) {
fUnionFind.init(type);
}
- for (IType type : fTypeToMethod.keySet()) {
+ for (IType type : fTypeToMethod.fImplementation.keySet()) {
uniteWithSupertypes(type, type);
}
fRootReps= new MultiMap<>();
@@ -481,15 +513,17 @@
uniteWithSupertypes(anchor, supertype);
} else {
//check whether method in supertype is really overridden:
- IMember superMethod= fTypeToMethod.get(supertype);
- if (JavaModelUtil.isVisibleInHierarchy(superMethod, anchor.getPackageFragment())) {
- IType rep= fUnionFind.find(anchor);
- fUnionFind.union(rep, superRep);
- // current type is no root anymore
- fRootTypes.remove(anchor);
- uniteWithSupertypes(supertype, supertype);
- } else {
- //Not overridden -> overriding chain ends here.
+ Collection<IMethod> superMethods= fTypeToMethod.get(supertype);
+ for (IMethod superMethod : superMethods) {
+ if (JavaModelUtil.isVisibleInHierarchy(superMethod, anchor.getPackageFragment())) {
+ IType rep= fUnionFind.find(anchor);
+ fUnionFind.union(rep, superRep);
+ // current type is no root anymore
+ fRootTypes.remove(anchor);
+ uniteWithSupertypes(supertype, supertype);
+ } else {
+ //Not overridden -> overriding chain ends here.
+ }
}
}
}
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java
index 088c574..04fa907 100644
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java
+++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java
@@ -10,12 +10,15 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Nikolay Metchev <nikolaymetchev@gmail.com> - [rename] https://bugs.eclipse.org/99622
*******************************************************************************/
package org.eclipse.jdt.internal.ui.refactoring.reorg;
import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
@@ -37,6 +40,7 @@
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogSettings;
@@ -71,6 +75,8 @@
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.SimpleName;
@@ -80,6 +86,7 @@
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
import org.eclipse.jdt.internal.corext.refactoring.rename.RenamingNameSuggestor;
+import org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder2;
import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
@@ -215,12 +222,12 @@
ASTNode selectedNode= NodeFinder.perform(root, fOriginalSelection.x, fOriginalSelection.y);
final int pos;
- ASTNode[] sameNodes;
+ Name nameNode= null;
if (! (selectedNode instanceof Name)) {
return; // TODO: show dialog
} else if (this.fJavaElement != null &&
this.fJavaElement.getElementType() == IJavaElement.JAVA_MODULE) {
- Name nameNode = (Name) selectedNode;
+ nameNode = (Name) selectedNode;
ASTNode parent = nameNode.getParent();
while(parent instanceof Name) {
nameNode = (Name) parent;
@@ -228,14 +235,12 @@
}
fOriginalName= nameNode.getFullyQualifiedName();
pos= nameNode.getStartPosition();
- sameNodes= LinkedNodeFinder.findByNode(root, nameNode);
} else if (! (selectedNode instanceof SimpleName)) {
return; // TODO: show dialog
} else {
- SimpleName nameNode = (SimpleName)selectedNode;
- fOriginalName = nameNode.getIdentifier();
+ nameNode = (SimpleName)selectedNode;
+ fOriginalName = ((SimpleName)nameNode).getIdentifier();
pos = nameNode.getStartPosition();
- sameNodes= LinkedNodeFinder.findByNode(root, nameNode);
}
if (viewer instanceof ITextViewerExtension6) {
@@ -248,9 +253,7 @@
}
}
- //TODO: copied from LinkedNamesAssistProposal#apply(..):
- // sort for iteration order, starting with the node @ offset
- Arrays.sort(sameNodes, new Comparator<ASTNode>() {
+ Set<ASTNode> sameNodes= new TreeSet<>(new Comparator<ASTNode>() {
@Override
public int compare(ASTNode o1, ASTNode o2) {
return rank(o1) - rank(o2);
@@ -270,12 +273,33 @@
return relativeRank;
}
});
- for (int i= 0; i < sameNodes.length; i++) {
- ASTNode elem= sameNodes[i];
+ sameNodes.add(nameNode);
+ IBinding resolvedNameNode= nameNode.resolveBinding();
+ if (resolvedNameNode != null && resolvedNameNode instanceof IMethodBinding) {
+ IJavaElement javaElement= resolvedNameNode.getJavaElement();
+ if (javaElement instanceof IMethod) {
+ IMethod[] relatedMethods= RippleMethodFinder2.getRelatedMethodsInCompilationUnit((IMethod) javaElement, new NullProgressMonitor(), null);
+ for (IMethod iMethod : relatedMethods) {
+ sameNodes.add(NodeFinder.perform(root, iMethod.getNameRange()));
+ }
+ }
+ }
+ for (ASTNode astNode : new ArrayList<>(sameNodes)) {
+ if (astNode instanceof SimpleName) {
+ for (SimpleName sameNode : LinkedNodeFinder.findByNode(root, (SimpleName) astNode)) {
+ sameNodes.add(sameNode);
+ }
+ }
+ }
+ //TODO: copied from LinkedNamesAssistProposal#apply(..):
+ // sort for iteration order, starting with the node @ offset
+ int i=0;
+ for (ASTNode elem : sameNodes) {
LinkedPosition linkedPosition= new LinkedPosition(document, elem.getStartPosition(), elem.getLength(), i);
if (i == 0)
fNamePosition= linkedPosition;
fLinkedPositionGroup.addPosition(linkedPosition);
+ i++;
}
fLinkedModeModel= new LinkedModeModel();
@@ -300,7 +324,7 @@
// startAnimation();
fgActiveLinkedMode= this;
- } catch (BadLocationException e) {
+ } catch (BadLocationException | CoreException e) {
JavaPlugin.log(e);
}
}
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameMethodUserInterfaceStarter.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameMethodUserInterfaceStarter.java
deleted file mode 100644
index c83c51b..0000000
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameMethodUserInterfaceStarter.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.ui.refactoring.reorg;
-
-import org.eclipse.swt.widgets.Shell;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.NullProgressMonitor;
-
-import org.eclipse.jface.dialogs.MessageDialog;
-
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-
-import org.eclipse.jdt.core.IMethod;
-
-import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
-import org.eclipse.jdt.internal.corext.refactoring.rename.RenameVirtualMethodProcessor;
-import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
-import org.eclipse.jdt.internal.corext.util.Messages;
-
-import org.eclipse.jdt.ui.JavaElementLabels;
-
-public class RenameMethodUserInterfaceStarter extends RenameUserInterfaceStarter {
-
- @Override
- public boolean activate(Refactoring refactoring, Shell parent, int saveMode) throws CoreException {
- RenameVirtualMethodProcessor processor= refactoring.getAdapter(RenameVirtualMethodProcessor.class);
- if (processor != null) {
- RefactoringStatus status= processor.checkInitialConditions(new NullProgressMonitor());
- if (!status.hasFatalError()) {
- IMethod method= processor.getMethod();
- if (!method.equals(processor.getOriginalMethod())) {
- String message= null;
- if (method.getDeclaringType().isInterface()) {
- message= Messages.format(
- RefactoringCoreMessages.MethodChecks_implements,
- new String[]{
- JavaElementUtil.createMethodSignature(method),
- JavaElementLabels.getElementLabel(method.getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED)});
- } else {
- message= Messages.format(
- RefactoringCoreMessages.MethodChecks_overrides,
- new String[]{
- JavaElementUtil.createMethodSignature(method),
- JavaElementLabels.getElementLabel(method.getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED)});
- }
- message= Messages.format(
- ReorgMessages.RenameMethodUserInterfaceStarter_message,
- message);
- if (!MessageDialog.openQuestion(parent,
- ReorgMessages.RenameMethodUserInterfaceStarter_name,
- message)) {
- return false;
- }
- }
- }
- }
- return super.activate(refactoring, parent, saveMode);
- }
-}
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameUserInterfaceManager.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameUserInterfaceManager.java
index 41dd42e..dd59a6f 100644
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameUserInterfaceManager.java
+++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameUserInterfaceManager.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2021 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Nikolay Metchev <nikolaymetchev@gmail.com> - [rename] https://bugs.eclipse.org/99622
*******************************************************************************/
package org.eclipse.jdt.internal.ui.refactoring.reorg;
@@ -44,8 +45,8 @@
put(RenameFieldProcessor.class, RenameUserInterfaceStarter.class, RenameFieldWizard.class);
put(RenameEnumConstProcessor.class, RenameUserInterfaceStarter.class, RenameEnumConstWizard.class);
put(RenameTypeParameterProcessor.class, RenameUserInterfaceStarter.class, RenameTypeParameterWizard.class);
- put(RenameNonVirtualMethodProcessor.class, RenameMethodUserInterfaceStarter.class, RenameMethodWizard.class);
- put(RenameVirtualMethodProcessor.class, RenameMethodUserInterfaceStarter.class, RenameMethodWizard.class);
+ put(RenameNonVirtualMethodProcessor.class, RenameUserInterfaceStarter.class, RenameMethodWizard.class);
+ put(RenameVirtualMethodProcessor.class, RenameUserInterfaceStarter.class, RenameMethodWizard.class);
put(RenameLocalVariableProcessor.class, RenameUserInterfaceStarter.class, RenameLocalVariableWizard.class);
put(RenameModuleProcessor.class, RenameUserInterfaceStarter.class, RenameModuleWizard.class);
}