Bug 560569 - [14] generated record class file has some kind of weird
side effect - REF_getField

Change-Id: Iba7fef7b8a208b34c20176925e7cf0202f02e97c
Signed-off-by: Manoj Palat <manpalat@in.ibm.com>
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java
index 2c37a44..058ed8b 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java
@@ -33,7 +33,7 @@
 	static {
 //		TESTS_NUMBERS = new int [] { 40 };
 //		TESTS_RANGE = new int[] { 1, -1 };
-//		TESTS_NAMES = new String[] { "testBug560531" };
+//		TESTS_NAMES = new String[] { "testBug560569_001" };
 	}
 	
 	public static Class<?> testClass() {
@@ -2038,4 +2038,41 @@
 			},
 		"0");
 }
+public void testBug560569_001() throws Exception {
+	runConformTest(
+		new String[] {
+			"X.java",
+			"interface Rentable { int year(); }\n"+
+			"record Car(String model, int year) implements Rentable {\n"+
+			"  public Car {\n"+
+			"  }\n"+
+			"  public String toString() {\n"+
+			"    return model + \" \" + year;\n"+
+			"  }\n"+
+			"}\n"+
+			"record Camel(int year) implements Rentable { }\n"+
+			"\n"+
+			"class X {\n"+
+			"       String model;\n"+
+			"       int year;\n"+
+			"       public String toString() {\n"+
+			"          return model + \" \" + year;\n"+
+			"       }\n"+
+			"       public static void main(String[] args) {\n"+
+			"               Car car = new Car(\"Maruti\", 2000);\n"+
+			"               System.out.println(car.hashCode() != 0);\n"+
+			"       }\n"+
+			"}\n"
+		},
+	 "true");
+	String expectedOutput = 
+			"Bootstrap methods:\n" + 
+			"  0 : # 68 invokestatic java/lang/runtime/ObjectMethods.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;\n" + 
+			"	Method arguments:\n" + 
+			"		#1 Car\n" + 
+			"		#69 model;year\n" + 
+			"		#71 REF_getField model:Ljava/lang/String;\n" + 
+			"		#72 REF_getField year:I\n";
+	RecordsRestrictedClassTest.verifyClassFile(expectedOutput, "Car.class", ClassFileBytesDisassembler.SYSTEM);
+}
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
index 7064e79..9533d86 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -3721,7 +3721,8 @@
 			
 			TypeBinding type = recordList.get(i);
 			assert type.isRecord(); // sanity check
-			int recordIndex = this.constantPool.literalIndexForType(type.constantPoolName());
+			char[] recordName = type.constantPoolName();
+			int recordIndex = this.constantPool.literalIndexForType(recordName);
 			this.contents[localContentsOffset++] = (byte) (recordIndex >> 8);
 			this.contents[localContentsOffset++] = (byte) recordIndex;
 
@@ -3742,20 +3743,13 @@
 			this.contents[localContentsOffset++] = (byte) (namesIndex >> 8);
 			this.contents[localContentsOffset++] = (byte) namesIndex;
 
-			List<MethodBinding> getters = new ArrayList<>();
 			for (FieldBinding field : recordComponents) {
-				MethodBinding[] candidates =  sourceType.getMethods(field.name);
-				for (MethodBinding candidate : candidates) {
-					if (candidate.parameters == null || candidate.parameters.length == 0) {
-						getters.add(candidate);
-						break;
-					}
-				}
-			}
-			for (MethodBinding getter : getters) {
-				int getterIndex = this.constantPool.literalIndexForMethodHandle(getter);
-				this.contents[localContentsOffset++] = (byte) (getterIndex >> 8);
-				this.contents[localContentsOffset++] = (byte) getterIndex;
+				int methodHandleIndex = this.constantPool.literalIndexForMethodHandleFieldRef(
+						ClassFileConstants.MethodHandleRefKindGetField, 
+						recordName, field.name, field.type.signature());
+
+				this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8);
+				this.contents[localContentsOffset++] = (byte) methodHandleIndex;
 			}
 		}
 		return localContentsOffset;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
index 9170fe1..4b31680 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
@@ -886,6 +886,24 @@
 
 		return index;
 	}
+	public int literalIndexForMethodHandleFieldRef(int referenceKind, char[] declaringClass, char[] name, char[] signature) {
+		assert referenceKind == MethodHandleRefKindGetField;
+		int indexForField = literalIndexForField(declaringClass, name, signature);
+
+		int index = this.currentIndex++;
+		int length = this.offsets.length;
+		if (length <= index) {
+			// resize
+			System.arraycopy(this.offsets, 0, (this.offsets = new int[index * 2]), 0, length);
+		}
+		
+		this.offsets[index] = this.currentOffset;
+		writeU1(MethodHandleTag);
+		writeU1(referenceKind);
+		writeU2(indexForField);
+
+		return index;
+	}
 	public int literalIndexForMethodType(char[] descriptor) {
 		int signatureIndex = literalIndex(descriptor);
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
index 2f38b74..21a8487 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
@@ -1905,6 +1905,12 @@
 					ConstantPoolEntry2 constantPoolEntry2 = (ConstantPoolEntry2) constantPoolEntry;
 					StringBuilder builder = new StringBuilder(10);
 					switch(constantPoolEntry2.getReferenceKind()) {
+						case IConstantPoolConstant.METHOD_TYPE_REF_GetField:
+							builder.append("REF_getField "); //$NON-NLS-1$
+							constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex());
+							builder.append(Messages.bind("{0}:{1}", fieldDescription(constantPoolEntry))); //$NON-NLS-1$
+							arguments[i] =  builder.toString();
+							break;
 						case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic:
 							builder.append("invokestatic "); //$NON-NLS-1$
 							//$FALL-THROUGH$
@@ -1919,11 +1925,22 @@
 				case IConstantPoolConstant.CONSTANT_MethodType:
 					arguments[i] = new String(((ConstantPoolEntry2) constantPoolEntry).getMethodDescriptor());
 					break;
+				case IConstantPoolConstant.CONSTANT_Class:
+					arguments[i] = new String(constantPoolEntry.getClassInfoName());
+					break;
+				case IConstantPoolConstant.CONSTANT_String:
+					arguments[i] = constantPoolEntry.getStringValue();
+					break;
 			}
 		}
 		return arguments;
 	}
 
+	private String[] fieldDescription(IConstantPoolEntry constantPoolEntry) {
+		return new String[] { new String(constantPoolEntry.getFieldName()),
+				new String(constantPoolEntry.getFieldDescriptor())};
+	}
+
 	private String[] methodDescription(IConstantPoolEntry constantPoolEntry) {
 		return new String[] { new String(constantPoolEntry.getClassName()),
 				new String(constantPoolEntry.getMethodName()),