Bug 394037 - [refactoring] renaming an argument with declared lifting
fails to rename occurrences
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
index bf21284..84fb0ca 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
@@ -1891,6 +1891,8 @@
 						key = fakedBinding.getKey();
 						if (key != null)
 							this.bindingTables.bindingKeysToBindings.put(key, fakedBinding);
+						// for repeated lookup of fakedVariable (using this same method) we also need the AST mapping:
+						this.newAstToOldAst.put(fakedVariable, fakedArgument);
 					}
 				}
 			}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
index 1ee8eb9..2f1e493 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
@@ -215,6 +215,14 @@
 		if (this.fakedRoleVariable != null)
 			this.fakedRoleVariable.setParent(this, FAKED_ROLE_VARIABLE);
 	}
+	/**
+	 * Retrieve a variable declaration that represents the role side (inner)
+	 * of an argument with declared lifting, else null.
+	 * @since 3.9
+	 */
+	public SingleVariableDeclaration getFakedRoleVariable() {
+		return this.fakedRoleVariable;
+	}
 // SH}
 
 	/**
diff --git a/plugins/org.eclipse.objectteams.otdt.refactoring/src/org/eclipse/objectteams/otdt/internal/refactoring/adaptor/RenameAdaptor.java b/plugins/org.eclipse.objectteams.otdt.refactoring/src/org/eclipse/objectteams/otdt/internal/refactoring/adaptor/RenameAdaptor.java
index 3877e9a..2d6f99f 100644
--- a/plugins/org.eclipse.objectteams.otdt.refactoring/src/org/eclipse/objectteams/otdt/internal/refactoring/adaptor/RenameAdaptor.java
+++ b/plugins/org.eclipse.objectteams.otdt.refactoring/src/org/eclipse/objectteams/otdt/internal/refactoring/adaptor/RenameAdaptor.java
@@ -35,8 +35,13 @@
 import org.eclipse.jdt.core.ITypeHierarchy;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.BaseCallMessageSend;
+import org.eclipse.jdt.core.dom.IBinding;
 import org.eclipse.jdt.core.dom.MethodDeclaration;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
+import base org.eclipse.jdt.internal.corext.refactoring.rename.TempOccurrenceAnalyzer;
 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
 import org.eclipse.jdt.internal.ui.JavaPlugin;
 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
@@ -302,4 +307,37 @@
 			return status;
 		}		
 	}
+
+	/**
+	 * Find more occurrences, currently:
+	 * - references to an argument with declared lifting via the fakedRoleVariable.
+	 */
+	@SuppressWarnings("decapsulation")
+	protected class TempOccurrenceAnalyzer playedBy TempOccurrenceAnalyzer {
+
+		boolean addReferenceNode(SimpleName name)                      -> get Set<SimpleName> fReferenceNodes
+        		with {  result 										<- 		base.fReferenceNodes.add(name) }
+		VariableDeclaration getFTempDeclaration() 						-> get VariableDeclaration fTempDeclaration;
+		void setFTempDeclaration(VariableDeclaration fTempDeclaration)	-> set VariableDeclaration fTempDeclaration;
+		void setFTempBinding(IBinding fTempBinding) 					-> set IBinding fTempBinding;
+
+		void perform() -> void perform();
+		
+		void performAgain() <- after void perform();
+	
+		private void performAgain() {
+			VariableDeclaration fTempDeclaration = getFTempDeclaration();
+			if (fTempDeclaration instanceof SingleVariableDeclaration) {
+				VariableDeclaration roleVar = ((SingleVariableDeclaration) fTempDeclaration).getFakedRoleVariable();
+				if (roleVar != null) {
+					// remember original declaration, faked one will be added in getReferenceAndDeclarationNodes():
+					addReferenceNode(fTempDeclaration.getName());
+					// re-initialize and search again using the faked roleVar:
+					setFTempDeclaration(roleVar);
+					setFTempBinding(roleVar.resolveBinding());
+					perform();
+				}
+			}			
+		}		
+	}
 }
diff --git a/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/src/org/eclipse/objectteams/otdt/ui/tests/refactoring/misc/ChangeSignatureTests.java b/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/src/org/eclipse/objectteams/otdt/ui/tests/refactoring/misc/ChangeSignatureTests.java
index b4c82f8..eda6ba7 100644
--- a/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/src/org/eclipse/objectteams/otdt/ui/tests/refactoring/misc/ChangeSignatureTests.java
+++ b/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/src/org/eclipse/objectteams/otdt/ui/tests/refactoring/misc/ChangeSignatureTests.java
@@ -195,6 +195,41 @@
 //		assertParticipant(classA);
 	}
 
+	void helperRename(ICompilationUnit cu, IType declaringClass, String[] signature, int idx, String oldName, String newName, String expectedInfo)
+			  throws JavaModelException, CoreException, Exception, IOException 
+	{
+		IMethod method = declaringClass.getMethod("m", signature);
+		assertTrue("method does not exist", method.exists());
+		assertTrue("refactoring not available", RefactoringAvailabilityTester.isChangeSignatureAvailable(method));
+
+		ChangeSignatureProcessor processor= new ChangeSignatureProcessor(method);
+		Refactoring ref= new ProcessorBasedRefactoring(processor);
+
+		processor.setDelegateUpdating(false);
+		markAsRenamed(processor.getParameterInfos().get(idx), oldName, newName);
+		RefactoringStatus initialConditions= ref.checkInitialConditions(new NullProgressMonitor());
+		assertTrue("precondition was supposed to pass:"+initialConditions.getEntryWithHighestSeverity(), initialConditions.isOK());
+		RefactoringStatus result= performRefactoring(ref, true);
+		if (expectedInfo != null) {
+			assertTrue("precondition was supposed to create an info:"+result.getEntryWithHighestSeverity(), result.hasInfo());
+			assertEquals("wrong info", expectedInfo, result.getEntryMatchingSeverity(RefactoringStatus.INFO).getMessage());
+		} else {
+			assertEquals("precondition was supposed to pass", null, result);
+		}
+
+		IPackageFragment pack= (IPackageFragment)cu.getParent();
+		String newCuName= getSimpleTestFileName(true, true);
+		ICompilationUnit newcu= pack.getCompilationUnit(newCuName);
+		assertTrue(newCuName + " does not exist", newcu.exists());
+		String expectedFileContents= getFileContents(getTestFileName(true, false));
+		assertEqualLines("invalid content", expectedFileContents, newcu.getSource());
+	}
+
+	private void markAsRenamed(ParameterInfo parameterInfo, String oldName, String newName) {
+		assertEquals(parameterInfo.getOldName(), oldName);
+		parameterInfo.setNewName(newName);
+	}
+
 	private void helperPermute(String[] newOrder, String[] signature, boolean createDelegate) throws Exception{
 		ICompilationUnit cu= createCUfromTestFile(getPackageP(), true, true);
 		IType classA= getType(cu, "A");
@@ -328,4 +363,10 @@
 	public void testReorder01() throws Exception {
 		helperPermute(new String[]{"ignore", "b", "a"}, new String[]{"I", "Z", "QString;"}, false);
 	}
+
+	public void testRename01() throws Exception {
+		ICompilationUnit cu= createCUfromTestFile(getPackageP(), true, true);
+		IType teamType = cu.getType("MyTeam");
+		helperRename(cu, teamType, new String[]{"QA;"}, 0, "arg", "renamed", null);
+	}
 }
diff --git a/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/testdata/ChangeSignature/canModify/A_testRename01_in.java b/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/testdata/ChangeSignature/canModify/A_testRename01_in.java
new file mode 100644
index 0000000..f1f38db
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/testdata/ChangeSignature/canModify/A_testRename01_in.java
@@ -0,0 +1,12 @@
+package p;
+
+class A {}
+
+team class MyTeam {
+	protected class R playedBy A {}
+	
+	public Object m(A as R arg) {
+		System.out.println(arg);
+		return arg;
+	}
+}
\ No newline at end of file
diff --git a/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/testdata/ChangeSignature/canModify/A_testRename01_out.java b/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/testdata/ChangeSignature/canModify/A_testRename01_out.java
new file mode 100644
index 0000000..b541af1
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.ui.tests.refactoring/testdata/ChangeSignature/canModify/A_testRename01_out.java
@@ -0,0 +1,12 @@
+package p;
+
+class A {}
+
+team class MyTeam {
+	protected class R playedBy A {}
+	
+	public Object m(A as R renamed) {
+		System.out.println(renamed);
+		return renamed;
+	}
+}
\ No newline at end of file