Bug 559681 - [14] Refactor rename is not working for component of a
record.

Change-Id: I75893fd3252d9fbf94c5ea498df5fc7aed2e9fb6
Signed-off-by: Kalyan Prasad Tatavarthi <kalyan_prasad@in.ibm.com>
diff --git a/org.eclipse.jdt.core.manipulation/.settings/.api_filters b/org.eclipse.jdt.core.manipulation/.settings/.api_filters
index c5b31fb..3b5fe9f 100644
--- a/org.eclipse.jdt.core.manipulation/.settings/.api_filters
+++ b/org.eclipse.jdt.core.manipulation/.settings/.api_filters
@@ -172,6 +172,25 @@
             </message_arguments>
         </filter>
     </resource>
+    <resource path="core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java">
+        <filter id="0"/>
+    </resource>
+    <resource path="core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java" type="org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder">
+        <filter id="640712815">
+            <message_arguments>
+                <message_argument value="ITypeBinding"/>
+                <message_argument value="LinkedNodeFinder"/>
+                <message_argument value="isRecord()"/>
+            </message_arguments>
+        </filter>
+        <filter id="640712815">
+            <message_arguments>
+                <message_argument value="RecordDeclaration"/>
+                <message_argument value="LinkedNodeFinder"/>
+                <message_argument value="recordComponents()"/>
+            </message_arguments>
+        </filter>
+    </resource>
     <resource path="core extension/org/eclipse/jdt/internal/corext/dom/ScopeAnalyzer.java" type="org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer">
         <filter comment="For Java 13 Enable Preview feature" id="640712815">
             <message_arguments>
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java
index c49519e..c0caae2 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -8,12 +8,17 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.dom;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.dom.AST;
@@ -28,7 +33,11 @@
 import org.eclipse.jdt.core.dom.IVariableBinding;
 import org.eclipse.jdt.core.dom.LabeledStatement;
 import org.eclipse.jdt.core.dom.NodeFinder;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+
+import org.eclipse.jdt.internal.ui.util.ASTHelper;
 
 
 /**
@@ -43,6 +52,62 @@
 	}
 
 
+	public static SimpleName getAssociatedRecordComponentNode(SimpleName simpleName) {
+		SimpleName rcName= null;
+		ASTNode parent= simpleName;
+		if (simpleName == null) {
+			return null;
+		}
+		if (!ASTHelper.isRecordDeclarationNodeSupportedInAST(simpleName.getAST())) {
+			return null;
+		}
+		IBinding binding= simpleName.resolveBinding();
+		if (binding instanceof IVariableBinding) {
+			IVariableBinding vbinding= (IVariableBinding) binding;
+			IVariableBinding bBinding= vbinding.getVariableDeclaration();
+			if (!bBinding.isField()) {
+				return null;
+			}
+			ITypeBinding typeBinding= vbinding.getDeclaringClass().getTypeDeclaration();
+			if (!typeBinding.isRecord()) {
+				return null;
+			}
+		} else if (binding instanceof IMethodBinding) {
+			IMethodBinding mBinding = (IMethodBinding)binding;
+			ITypeBinding typeBinding= mBinding.getDeclaringClass().getTypeDeclaration();
+			IMethodBinding bBinding= mBinding.getMethodDeclaration();
+			if (bBinding.getParameterTypes().length != 0 || !typeBinding.isRecord()) {
+				return null;
+			}
+
+		} else {
+			return null;
+		}
+		RecordDeclaration recordDeclaration= null;
+		while(parent != null) {
+			parent= parent.getParent();
+			if (parent instanceof RecordDeclaration) {
+				recordDeclaration= (RecordDeclaration) parent;
+				break;
+			}
+		}
+		if (recordDeclaration != null) {
+			List<ASTNode> ff=recordDeclaration.recordComponents();
+			for (ASTNode nd : ff) {
+				if (nd instanceof SingleVariableDeclaration) {
+					SimpleName name= ((SingleVariableDeclaration) nd).getName();
+					if (simpleName.getIdentifier().equals(name.getIdentifier())) {
+						rcName= name;
+						break;
+					}
+				}
+			}
+		}
+		return rcName;
+	}
+
+
+
 	/**
 	 * Find all nodes connected to the given binding. e.g. Declaration of a field and all references.
 	 * For types this includes also the constructor declaration, for methods also overridden methods
@@ -69,6 +134,11 @@
 	public static SimpleName[] findByNode(ASTNode root, SimpleName name) {
 		IBinding binding = name.resolveBinding();
 		if (binding != null) {
+			SimpleName recNode= getAssociatedRecordComponentNode(name);
+			if (recNode != null) {
+				IBinding recBinding= recNode.resolveBinding();
+				return findByBinding(root, recBinding);
+			}
 			return findByBinding(root, binding);
 		}
 		SimpleName[] names= findByProblems(root, name);
@@ -238,9 +308,17 @@
 				return false;
 			}
 			binding= getDeclaration(binding);
-
+			SimpleName rcNode= getAssociatedRecordComponentNode(node);
 			if (fBinding == binding) {
 				fResult.add(node);
+			} else if (rcNode != null) {
+				IBinding rcBinding= rcNode.resolveBinding();
+				if (rcBinding != null) {
+					rcBinding= getDeclaration(rcBinding);
+					if (fBinding == rcBinding) {
+						fResult.add(node);
+					}
+				}
 			} else if (binding.getKind() != fBinding.getKind()) {
 				return false;
 			} else if (binding.getKind() == IBinding.METHOD) {
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/in/A.java
new file mode 100644
index 0000000..2236fa8
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/in/A.java
@@ -0,0 +1,14 @@
+package p;
+record A(int f){
+	A{
+		this.f= f;
+	}
+	
+	public void val(int f) {
+		
+	}
+
+	public int getVal() {
+		return f();
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/in/B.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/in/B.java
new file mode 100644
index 0000000..5c15421
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/in/B.java
@@ -0,0 +1,8 @@
+package p;
+class B(){
+
+	public int val() {
+		A a= new A(10);
+		return a.f();
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/out/A.java
new file mode 100644
index 0000000..10ffd7b
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/out/A.java
@@ -0,0 +1,14 @@
+package p;
+record A(int g){
+	A{
+		this.g= g;
+	}
+	
+	public void val(int f) {
+		
+	}
+
+	public int getVal() {
+		return g();
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/out/B.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/out/B.java
new file mode 100644
index 0000000..cb5705d
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test0/out/B.java
@@ -0,0 +1,8 @@
+package p;
+class B(){
+
+	public int val() {
+		A a= new A(10);
+		return a.g();
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/in/A.java
new file mode 100644
index 0000000..d1c49f2
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/in/A.java
@@ -0,0 +1,18 @@
+package p;
+record A(int f){
+	A{
+		this.f= f;
+	}
+	
+	public void val(int f) {
+		
+	}
+
+	public int getVal() {
+		return f();
+	}
+	
+	public int f() {
+		return f;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/in/B.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/in/B.java
new file mode 100644
index 0000000..5c15421
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/in/B.java
@@ -0,0 +1,8 @@
+package p;
+class B(){
+
+	public int val() {
+		A a= new A(10);
+		return a.f();
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/out/A.java
new file mode 100644
index 0000000..73f2528
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/out/A.java
@@ -0,0 +1,18 @@
+package p;
+record A(int g){
+	A{
+		this.g= g;
+	}
+	
+	public void val(int f) {
+		
+	}
+
+	public int getVal() {
+		return g();
+	}
+	
+	public int g() {
+		return g;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/out/B.java b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/out/B.java
new file mode 100644
index 0000000..cb5705d
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/RenameRecordComponentField/test1/out/B.java
@@ -0,0 +1,8 @@
+package p;
+class B(){
+
+	public int val() {
+		A a= new A(10);
+		return a.g();
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllRefactoringTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllRefactoringTests.java
index 0b6447e..5f1ae0c 100644
--- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllRefactoringTests.java
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllRefactoringTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -96,6 +100,7 @@
 		//--fields
 		suite.addTest(RenamePrivateFieldTests.suite());
 		suite.addTest(RenameNonPrivateFieldTests.suite());
+		suite.addTest(RenameRecordComponentFieldTests.suite());
 
 		//--initializers
 		suite.addTest(MoveInitializerTests.suite());
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/Java14Setup.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/Java14Setup.java
new file mode 100644
index 0000000..ff353c8
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/Java14Setup.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ui.tests.refactoring;
+
+import org.eclipse.jdt.testplugin.JavaProjectHelper;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+
+import junit.framework.Test;
+
+public class Java14Setup extends RefactoringTestSetup {
+
+	public Java14Setup(Test test) {
+		super(test);
+	}
+
+	/*
+	 * @see org.eclipse.jdt.ui.tests.refactoring.RefactoringTestSetup#addRTJar(org.eclipse.jdt.core.IJavaProject)
+	 */
+	@Override
+	protected IPackageFragmentRoot addRTJar(IJavaProject project) throws CoreException {
+		return JavaProjectHelper.addRTJar_14(project, true);
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameRecordComponentFieldTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameRecordComponentFieldTests.java
new file mode 100644
index 0000000..a96044e
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/RenameRecordComponentFieldTests.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ui.tests.refactoring;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.ltk.core.refactoring.RefactoringCore;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
+import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
+
+import org.eclipse.jdt.core.IAnnotatable;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
+import org.eclipse.jdt.core.refactoring.descriptors.RenameJavaElementDescriptor;
+
+import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
+import org.eclipse.jdt.internal.corext.refactoring.rename.RenameFieldProcessor;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class RenameRecordComponentFieldTests extends RefactoringTest {
+
+	private static final Class<RenameRecordComponentFieldTests> clazz= RenameRecordComponentFieldTests.class;
+	private static final String REFACTORING_PATH= "RenameRecordComponentField/";
+
+	private String fPrefixPref;
+	public RenameRecordComponentFieldTests(String name) {
+		super(name);
+	}
+
+	public static Test suite() {
+		return new Java14Setup( new TestSuite(clazz));
+	}
+
+	public static Test setUpTest(Test someTest) {
+		return new Java14Setup(someTest);
+	}
+
+	@Override
+	protected String getRefactoringPath() {
+		return REFACTORING_PATH;
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		Hashtable<String, String> options= JavaCore.getOptions();
+		fPrefixPref= options.get(JavaCore.CODEASSIST_FIELD_PREFIXES);
+		options.put(JavaCore.CODEASSIST_FIELD_PREFIXES, getPrefixes());
+		JavaCore.setOptions(options);
+		fIsPreDeltaTest= true;
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		Hashtable<String, String> options= JavaCore.getOptions();
+		options.put(JavaCore.CODEASSIST_FIELD_PREFIXES, fPrefixPref);
+		JavaCore.setOptions(options);
+	}
+
+	private String getPrefixes(){
+		return "f";
+	}
+
+	private void helper1(String fieldName, String newFieldName, boolean updateReferences) throws Exception{
+		ParticipantTesting.reset();
+		ICompilationUnit cu= createCUfromTestFile(getPackageP(), "A");
+		ICompilationUnit cu2= createCUfromTestFile(getPackageP(), "B");
+		IType classA= getType(cu, "A");
+		IField field= classA.getField(fieldName);
+		IMethod method= classA.getMethod(fieldName, new String[] {});
+		RenameJavaElementDescriptor descriptor= RefactoringSignatureDescriptorFactory.createRenameJavaElementDescriptor(IJavaRefactorings.RENAME_FIELD);
+		descriptor.setJavaElement(field);
+		descriptor.setNewName(newFieldName);
+		descriptor.setUpdateReferences(updateReferences);
+		descriptor.setUpdateTextualOccurrences(false);
+		descriptor.setRenameGetters(false);
+		descriptor.setRenameSetters(false);
+
+		RenameRefactoring refactoring= (RenameRefactoring) createRefactoring(descriptor);
+		RenameFieldProcessor processor= (RenameFieldProcessor) refactoring.getProcessor();
+		assertEquals("getter rename enabled", false, processor.canEnableGetterRenaming() == null);
+		assertEquals("setter rename enabled", false, processor.canEnableSetterRenaming() == null);
+
+		List<IAnnotatable> elements= new ArrayList<>();
+		elements.add(field);
+		List<RenameArguments> args= new ArrayList<>();
+		args.add(new RenameArguments(newFieldName, updateReferences));
+		if (method != null && method.exists()) {
+			elements.add(method);
+			args.add(new RenameArguments(newFieldName, updateReferences));
+		}
+
+
+		String[] renameHandles= ParticipantTesting.createHandles(elements.toArray());
+
+		RefactoringStatus result= performRefactoring(refactoring);
+		assertEquals("was supposed to pass", null, result);
+		assertEqualLines("invalid renaming", getFileContents(getOutputTestFileName("A")), cu.getSource());
+		assertEqualLines("invalid renaming", getFileContents(getOutputTestFileName("B")), cu2.getSource());
+
+		ParticipantTesting.testRename(
+			renameHandles,
+			args.toArray(new RenameArguments[args.size()]));
+
+		assertTrue("anythingToUndo", RefactoringCore.getUndoManager().anythingToUndo());
+		assertTrue("! anythingToRedo", !RefactoringCore.getUndoManager().anythingToRedo());
+
+		RefactoringCore.getUndoManager().performUndo(null, new NullProgressMonitor());
+		assertEqualLines("invalid undo", getFileContents(getInputTestFileName("A")), cu.getSource());
+		assertEqualLines("invalid undo", getFileContents(getInputTestFileName("B")), cu2.getSource());
+
+		assertTrue("! anythingToUndo", !RefactoringCore.getUndoManager().anythingToUndo());
+		assertTrue("anythingToRedo", RefactoringCore.getUndoManager().anythingToRedo());
+
+		RefactoringCore.getUndoManager().performRedo(null, new NullProgressMonitor());
+		assertEqualLines("invalid redo", getFileContents(getOutputTestFileName("A")), cu.getSource());
+		assertEqualLines("invalid redo", getFileContents(getOutputTestFileName("B")), cu2.getSource());
+	}
+
+	private void helper1(boolean updateReferences) throws Exception{
+		helper1("f", "g", updateReferences);
+	}
+
+	private void helper1() throws Exception{
+		helper1(true);
+	}
+
+	//--------- tests ----------
+
+	public void test0() throws Exception{
+		helper1();
+	}
+
+	public void test1() throws Exception{
+		helper1();
+	}
+
+}
diff --git a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java
index 3dcdbfe..5db47aa 100644
--- a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java
+++ b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Ferenc Hechler, ferenc_hechler@users.sourceforge.net - 83258 [jar exporter] Deploy java application as executable jar
@@ -264,7 +268,7 @@
 
 	/**
 	 * Sets the compiler options to 13 for the given project.
-	 * 
+	 *
 	 * @param project the java project
 	 * @param enable_preview_feature sets enable-preview compliance project option based on the
 	 *            value specified.
@@ -371,7 +375,7 @@
 
 	/**
 	 * Sets the compiler options to 14.
-	 * 
+	 *
 	 * @param options the compiler options to configure
 	 */
 	public static void set14_CompilerOptions(Map<String, String> options) {
@@ -890,6 +894,12 @@
 		return addLibrary(jproject, rtJarPath[0], rtJarPath[1], rtJarPath[2]);
 	}
 
+	public static IPackageFragmentRoot addRTJar_14(IJavaProject jproject, boolean enable_preview_feature) throws CoreException {
+		IPath[] rtJarPath= findRtJar(RT_STUBS14);
+		set14CompilerOptions(jproject, enable_preview_feature);
+		return addLibrary(jproject, rtJarPath[0], rtJarPath[1], rtJarPath[2]);
+	}
+
 	/**
 	 * Adds a variable entry with source attachment to a IJavaProject.
 	 * Can return null if variable can not be resolved.
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameFieldProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameFieldProcessor.java
index c0a29ef..63124db 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameFieldProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/rename/RenameFieldProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -60,6 +64,7 @@
 import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.core.search.SearchPattern;
 
+import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
 import org.eclipse.jdt.internal.corext.codemanipulation.GetterSetterUtil;
 import org.eclipse.jdt.internal.corext.refactoring.Checks;
@@ -99,7 +104,6 @@
 import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper;
 
 import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 
 public class RenameFieldProcessor extends JavaRenameProcessor implements IReferenceUpdating, ITextUpdating, IDelegateUpdating {
 
@@ -110,6 +114,7 @@
 	private static final String ATTRIBUTE_DEPRECATE= "deprecate"; //$NON-NLS-1$
 
 	protected IField fField;
+	private boolean fIsRecordComponent= false;
 	private SearchResultGroup[] fReferences;
 	private TextChangeManager fChangeManager;
 	protected boolean fUpdateReferences;
@@ -161,12 +166,14 @@
 		fDelegateUpdating= false;
 		fDelegateDeprecation= true;
 		fIsComposite= true;
+		fIsRecordComponent= false;
 	}
 
 	private void initialize(IField field) {
-		fField= field;
-		if (fField != null)
+		assignField(field);
+		if (fField != null) {
 			setNewElementName(fField.getElementName());
+		}
 		fUpdateReferences= true;
 		fUpdateTextualMatches= false;
 
@@ -219,6 +226,12 @@
 				result.rename(setter, new RenameArguments(getNewSetterName(), getUpdateReferences()));
 			}
 		}
+		if (fIsRecordComponent) {
+			IMethod accessor= getAccessor();
+			if (accessor != null) {
+				result.rename(accessor, new RenameArguments(getNewElementName(), getUpdateReferences()));
+			}
+		}
 		return result;
 	}
 
@@ -367,6 +380,10 @@
 		return GetterSetterUtil.getSetter(fField);
 	}
 
+	private IMethod getAccessor() throws CoreException {
+		return JavaModelUtil.findMethod(fField.getElementName(), new String[0], false, fField.getDeclaringType());
+	}
+
 	public String getNewGetterName() throws CoreException {
 		IMethod primaryGetterCandidate= JavaModelUtil.findMethod(GetterSetterUtil.getGetterName(fField, new String[0]), new String[0], false, fField.getDeclaringType());
 		if (! JavaModelUtil.isBoolean(fField) || (primaryGetterCandidate != null && primaryGetterCandidate.exists()))
@@ -421,6 +438,8 @@
 				count++;
 			if (fRenameSetter && getSetter() != null)
 				count++;
+			if (fIsRecordComponent && getAccessor() != null)
+				count++;
 		} catch (CoreException e) {
 			// no-op
 		}
@@ -439,7 +458,7 @@
 			String message= Messages.format(RefactoringCoreMessages.RenameFieldRefactoring_deleted, BasicElementLabels.getFileName(fField.getCompilationUnit()));
 			return RefactoringStatus.createFatalErrorStatus(message);
 		}
-		fField= primary;
+		assignField(primary);
 
 		return Checks.checkIfCuBroken(fField);
 	}
@@ -705,6 +724,12 @@
 			pm.worked(1);
 		}
 
+		if (fIsRecordComponent) {
+			addAccessorOccurrences(new SubProgressMonitor(pm, 1), result);
+		} else {
+			pm.worked(1);
+		}
+
 		if (fUpdateTextualMatches) {
 			addTextMatches(new SubProgressMonitor(pm, 5));
 		} else {
@@ -754,7 +779,9 @@
 			addMethodDelegate(getGetter(), getNewGetterName(), rewrite);
 		if (getSetter() != null && fRenameSetter)
 			addMethodDelegate(getSetter(), getNewSetterName(), rewrite);
-
+		if (fIsRecordComponent && getAccessor() != null) {
+			addMethodDelegate(getAccessor(), getNewElementName(), rewrite);
+		}
 		final CompilationUnitChange change= rewrite.createChange(true);
 		if (change != null) {
 			change.setKeepPreviewEdits(true);
@@ -809,6 +836,14 @@
 		addAccessorOccurrences(pm, getSetter(), RefactoringCoreMessages.RenameFieldRefactoring_Update_setter_occurrence, getNewSetterName(), status);
 	}
 
+	private void addAccessorOccurrences(IProgressMonitor pm, RefactoringStatus status) throws CoreException {
+		if (getAccessor() != null) {
+			addAccessorOccurrences(pm, getAccessor(), RefactoringCoreMessages.RenameFieldRefactoring_Update_getter_occurrence, getNewElementName(), status);
+		} else {
+			addFieldAccessorOccurrences(pm, RefactoringCoreMessages.RenameFieldRefactoring_Update_getter_occurrence, getNewElementName(), status);
+		}
+	}
+
 	private void addAccessorOccurrences(IProgressMonitor pm, IMethod accessor, String editName, String newAccessorName, RefactoringStatus status) throws CoreException {
 		Assert.isTrue(accessor.exists());
 
@@ -829,10 +864,45 @@
 		}
 	}
 
+	private void addFieldAccessorOccurrences(IProgressMonitor pm, String editName, String newAccessorName, RefactoringStatus status) throws CoreException {
+		Assert.isTrue(fField.exists());
+
+		IJavaSearchScope scope= RefactoringScopeFactory.create(fField.getDeclaringType());
+		SearchPattern pattern= SearchPattern.createPattern(fField.getElementName(), IJavaSearchConstants.METHOD,
+				IJavaSearchConstants.REFERENCES, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_ERASURE_MATCH);
+		SearchResultGroup[] groupedResults= RefactoringSearchEngine.search(
+				pattern, scope, new MethodOccurenceCollector(fField.getElementName()), pm, status);
+		for (SearchResultGroup groupedResult : groupedResults) {
+			ICompilationUnit cu= groupedResult.getCompilationUnit();
+			if (cu == null)
+				continue;
+			SearchMatch[] results= groupedResult.getSearchResults();
+			for (SearchMatch searchResult : results) {
+				TextEdit edit= new ReplaceEdit(searchResult.getOffset(), searchResult.getLength(), newAccessorName);
+				addTextEdit(fChangeManager.get(cu), editName, edit);
+			}
+		}
+	}
+
 	private void addTextMatches(IProgressMonitor pm) throws CoreException {
 		TextMatchUpdater.perform(pm, createRefactoringScope(), this, fChangeManager, fReferences);
 	}
 
+	private void assignField(IField field) {
+		fField= field;
+		fIsRecordComponent= false;
+		if (fField != null) {
+			IJavaElement parent= fField.getDeclaringType();
+			try {
+				if (parent instanceof IType && ((IType) parent).isRecord() && !Flags.isStatic(fField.getFlags())) {
+					fIsRecordComponent= true;
+				}
+			} catch (JavaModelException e) {
+				//do nothing
+			}
+		}
+	}
+
 	//----------------
 	private RefactoringStatus analyzeRenameChanges(IProgressMonitor pm) throws CoreException {
 		ICompilationUnit[] newWorkingCopies= null;
@@ -916,7 +986,7 @@
 			if (element == null || !element.exists() || element.getElementType() != IJavaElement.FIELD)
 				return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.RENAME_FIELD);
 			else
-				fField= (IField) element;
+				assignField((IField) element);
 		} else
 			return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
 		final String name= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);