Skip to content

Commit 71d8c9e

Browse files
Content Assist doesn't work for record type names in some contexts (#4223)
* Fixes #4215
1 parent e859e0c commit 71d8c9e

File tree

3 files changed

+250
-18
lines changed

3 files changed

+250
-18
lines changed

org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests16.java

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package org.eclipse.jdt.core.tests.model;
1515

1616
import junit.framework.Test;
17+
import org.eclipse.core.runtime.NullProgressMonitor;
1718
import org.eclipse.jdt.core.ICompilationUnit;
1819
import org.eclipse.jdt.core.IJavaProject;
1920
import org.eclipse.jdt.core.JavaCore;
@@ -1181,4 +1182,199 @@ public record R(String name, int age) {
11811182
requestor.getResults());
11821183

11831184
}
1185+
1186+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4215
1187+
// Content Assist doesn't work for record type names in some contexts
1188+
public void testIssue4215() throws JavaModelException {
1189+
this.workingCopies = new ICompilationUnit[2];
1190+
1191+
this.workingCopies[1] = getWorkingCopy(
1192+
"/Completion/src/p/Point.java",
1193+
"""
1194+
package p;
1195+
public record Point(int x, int y) {
1196+
void foo() {
1197+
System.out.println(this.x);
1198+
System.out.println(x());
1199+
}
1200+
}
1201+
1202+
class X {
1203+
X x = new X();
1204+
}
1205+
"""
1206+
);
1207+
this.workingCopies[0] = getWorkingCopy(
1208+
"/Completion/src/X.java",
1209+
"""
1210+
public class X {
1211+
public static void main(String[] args) {
1212+
new Poi
1213+
}
1214+
}
1215+
"""
1216+
);
1217+
this.workingCopies[0].getJavaProject(); //assuming single project for all working copies
1218+
CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
1219+
requestor.allowAllRequiredProposals();
1220+
String str = this.workingCopies[0].getSource();
1221+
String completeBehind = "new Poi";
1222+
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
1223+
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor());
1224+
assertResults(
1225+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, (II)V, Point, (x, y), 52}",
1226+
requestor.getResults());
1227+
1228+
}
1229+
1230+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4215
1231+
// Content Assist doesn't work for record type names in some contexts
1232+
public void testIssue4215_2() throws JavaModelException {
1233+
this.workingCopies = new ICompilationUnit[2];
1234+
1235+
this.workingCopies[1] = getWorkingCopy(
1236+
"/Completion/src/p/Point.java",
1237+
"""
1238+
package p;
1239+
public record Point(int x, int y) {
1240+
public Point {
1241+
x = 0;
1242+
y = 0;
1243+
}
1244+
1245+
void foo() {
1246+
System.out.println(this.x);
1247+
System.out.println(x());
1248+
}
1249+
}
1250+
1251+
class X {
1252+
X x = new X();
1253+
}
1254+
"""
1255+
);
1256+
this.workingCopies[0] = getWorkingCopy(
1257+
"/Completion/src/X.java",
1258+
"""
1259+
public class X {
1260+
public static void main(String[] args) {
1261+
new Poi
1262+
}
1263+
}
1264+
"""
1265+
);
1266+
this.workingCopies[0].getJavaProject(); //assuming single project for all working copies
1267+
CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
1268+
requestor.allowAllRequiredProposals();
1269+
String str = this.workingCopies[0].getSource();
1270+
String completeBehind = "new Poi";
1271+
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
1272+
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor());
1273+
assertResults(
1274+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, (II)V, Point, (x, y), 52}",
1275+
requestor.getResults());
1276+
1277+
}
1278+
1279+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4215
1280+
// Content Assist doesn't work for record type names in some contexts
1281+
public void testIssue4215_3() throws JavaModelException {
1282+
this.workingCopies = new ICompilationUnit[2];
1283+
1284+
this.workingCopies[1] = getWorkingCopy(
1285+
"/Completion/src/p/Point.java",
1286+
"""
1287+
package p;
1288+
public record Point(int x, int y) {
1289+
public Point() {
1290+
this(0, 0);
1291+
}
1292+
1293+
void foo() {
1294+
System.out.println(this.x);
1295+
System.out.println(x());
1296+
}
1297+
}
1298+
1299+
class X {
1300+
X x = new X();
1301+
}
1302+
"""
1303+
);
1304+
this.workingCopies[0] = getWorkingCopy(
1305+
"/Completion/src/X.java",
1306+
"""
1307+
public class X {
1308+
public static void main(String[] args) {
1309+
new Poi
1310+
}
1311+
}
1312+
"""
1313+
);
1314+
this.workingCopies[0].getJavaProject(); //assuming single project for all working copies
1315+
CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
1316+
requestor.allowAllRequiredProposals();
1317+
String str = this.workingCopies[0].getSource();
1318+
String completeBehind = "new Poi";
1319+
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
1320+
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor());
1321+
assertResults(
1322+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, ()V, Point, null, 52}\n" +
1323+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, (II)V, Point, (x, y), 52}",
1324+
requestor.getResults());
1325+
1326+
}
1327+
1328+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4215
1329+
// Content Assist doesn't work for record type names in some contexts
1330+
public void testIssue4215_4() throws JavaModelException {
1331+
this.workingCopies = new ICompilationUnit[2];
1332+
1333+
this.workingCopies[1] = getWorkingCopy(
1334+
"/Completion/src/p/Point.java",
1335+
"""
1336+
package p;
1337+
public record Point(int x, int y) {
1338+
public Point() {
1339+
this(0, 0);
1340+
}
1341+
public Point (int x, int y) {
1342+
this.x = x;
1343+
this.y = y;
1344+
}
1345+
void foo() {
1346+
System.out.println(this.x);
1347+
System.out.println(x());
1348+
}
1349+
}
1350+
1351+
class X {
1352+
X x = new X();
1353+
}
1354+
"""
1355+
);
1356+
this.workingCopies[0] = getWorkingCopy(
1357+
"/Completion/src/X.java",
1358+
"""
1359+
public class X {
1360+
public static void main(String[] args) {
1361+
new Poi
1362+
}
1363+
}
1364+
"""
1365+
);
1366+
this.workingCopies[0].getJavaProject(); //assuming single project for all working copies
1367+
CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
1368+
requestor.allowAllRequiredProposals();
1369+
String str = this.workingCopies[0].getSource();
1370+
String completeBehind = "new Poi";
1371+
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
1372+
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor());
1373+
assertResults(
1374+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, ()V, Point, null, 52}\n" +
1375+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, (II)V, Point, (x, y), 52}\n" +
1376+
"Point[CONSTRUCTOR_INVOCATION]{(), Lp.Point;, (II)V, Point, (x, y), 52}", // duplicated: see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4222
1377+
requestor.getResults());
1378+
1379+
}
11841380
}

org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6340,6 +6340,16 @@ private void findConstructors(
63406340
}
63416341
}
63426342

6343+
private boolean argumentMismatch(AbstractVariableDeclaration[] arguments, char[][] parameterTypes) {
6344+
int argumentsLength = arguments == null ? 0 : arguments.length;
6345+
if (parameterTypes.length != argumentsLength)
6346+
return true;
6347+
for (int j = 0; j < argumentsLength; j++)
6348+
if (!CharOperation.equals(getTypeName(arguments[j].type), parameterTypes[j]))
6349+
return true;
6350+
return false;
6351+
}
6352+
63436353
private char[] getResolvedSignature(char[][] parameterTypes, char[] fullyQualifiedTypeName, int parameterCount, Scope scope) {
63446354
char[][] cn = CharOperation.splitOn('.', fullyQualifiedTypeName);
63456355

@@ -6381,25 +6391,20 @@ private char[] getResolvedSignature(char[][] parameterTypes, char[] fullyQualifi
63816391
return null;
63826392

63836393
next : for (AbstractMethodDeclaration method : methods) {
6384-
if (!method.isConstructor()) continue next;
6385-
6386-
AbstractVariableDeclaration[] arguments = method.arguments(true);
6387-
int argumentsLength = arguments == null ? 0 : arguments.length;
6388-
6389-
if (parameterCount != argumentsLength) continue next;
6390-
6391-
for (int j = 0; j < argumentsLength; j++) {
6392-
char[] argumentTypeName = getTypeName(arguments[j].type);
6393-
6394-
if (!CharOperation.equals(argumentTypeName, parameterTypes[j])) {
6395-
continue next;
6396-
}
6397-
}
6398-
6394+
if (!method.isConstructor() || argumentMismatch(method.arguments(true), parameterTypes))
6395+
continue next;
63996396
refBinding.resolveTypesFor(method.binding); // force resolution
64006397
if (method.binding == null) continue next;
64016398
return getSignature(method.binding);
64026399
}
6400+
if (typeDeclaration.isRecord() && !argumentMismatch(typeDeclaration.recordComponents, parameterTypes)) {
6401+
MethodBinding [] constructors = refBinding.getMethods(TypeConstants.INIT, parameterTypes.length);
6402+
if (constructors != null) {
6403+
for (MethodBinding constructor : constructors)
6404+
if (constructor instanceof SyntheticMethodBinding)
6405+
return getSignature(constructor);
6406+
}
6407+
}
64036408
}
64046409
}
64056410
} finally {

org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
import org.eclipse.jdt.internal.core.JavaElement;
6161
import org.eclipse.jdt.internal.core.JavaModelManager;
6262
import org.eclipse.jdt.internal.core.JavaProject;
63+
import org.eclipse.jdt.internal.core.SourceMethod;
64+
import org.eclipse.jdt.internal.core.SourceMethodElementInfo;
6365
import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
6466
import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
6567
import org.eclipse.jdt.internal.core.search.matching.*;
@@ -802,12 +804,19 @@ public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord,
802804

803805
int extraFlags = ExtraFlags.getExtraFlags(type);
804806

805-
boolean hasConstructor = false;
807+
boolean needDefaultConstructor = !type.isRecord();
808+
boolean needCanonicalConstructor = type.isRecord();
806809

807810
IMethod[] methods = type.getMethods();
808811
for (IMethod method : methods) {
809812
if (method.isConstructor()) {
810-
hasConstructor = true;
813+
needDefaultConstructor = false;
814+
if (needCanonicalConstructor) {
815+
if (method instanceof SourceMethod sourceMethod && sourceMethod.getElementInfo() instanceof SourceMethodElementInfo info) {
816+
if (info.isCanonicalConstructor()) // not totally reliable, see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4222
817+
needCanonicalConstructor = false;
818+
}
819+
}
811820

812821
String[] stringParameterNames = method.getParameterNames();
813822
String[] stringParameterTypes = method.getParameterTypes();
@@ -834,7 +843,7 @@ public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord,
834843
}
835844
}
836845

837-
if (!hasConstructor) {
846+
if (needDefaultConstructor) {
838847
nameRequestor.acceptConstructor(
839848
Flags.AccPublic,
840849
simpleName,
@@ -847,6 +856,28 @@ public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord,
847856
extraFlags,
848857
path,
849858
null);
859+
} else if (needCanonicalConstructor) {
860+
IField[] components = type.getRecordComponents();
861+
int length = components == null ? 0 : components.length;
862+
863+
char[][] parameterNames = new char[length][];
864+
char[][] parameterTypes = new char[length][];
865+
for (int l = 0; l < length; l++) {
866+
parameterNames[l] = components[l].getElementName().toCharArray();
867+
parameterTypes[l] = Signature.toCharArray(Signature.getTypeErasure(components[l].getTypeSignature()).toCharArray());
868+
}
869+
nameRequestor.acceptConstructor(
870+
Flags.AccPublic,
871+
simpleName,
872+
length,
873+
null, // signature is not used for source type
874+
parameterTypes,
875+
parameterNames,
876+
type.getFlags(),
877+
packageDeclaration,
878+
extraFlags,
879+
path,
880+
null);
850881
}
851882
}
852883
}

0 commit comments

Comments
 (0)