Skip to content

Commit 11acaf5

Browse files
[Records 2.0] ECJ has two parallel mechanisms for canonical constructor generation (#3928)
* Fixes #1090 * Fixes #3927
1 parent fd96d57 commit 11acaf5

File tree

41 files changed

+1056
-824
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1056
-824
lines changed

org.eclipse.jdt.apt.tests/forceQualifierUpdate.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ Bug 420446 - APT tests don't run
44
Bug 566471 - I20200828-0150 - Comparator Errors Found
55
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1184
66
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1659
7-
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1923
7+
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1923
8+
https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1090
0 Bytes
Binary file not shown.

org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/records/mod.records/records/R4.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import java.lang.annotation.Target;
77
import java.lang.annotation.Repeatable;
88

9-
record R4(@Marker4 int... i) {}
9+
record R4(@Marker4 int... i) {
10+
public R4 {}
11+
}
1012
// record R4(@Marker4 @Marker5() @Marker5() int... i) {} // This will cause failures in RecordElementProcessor#testRecords10
1113

1214
@Retention(RetentionPolicy.RUNTIME)

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
6464
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
6565
import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
66+
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
6667
import org.eclipse.jdt.internal.compiler.util.Messages;
6768
import org.eclipse.jdt.internal.compiler.util.Util;
6869

@@ -549,6 +550,13 @@ private RecordComponent getRecordComponent(ReferenceBinding declaringClass, char
549550
}
550551
return null;
551552
}
553+
private RecordComponent[] getRecordComponents(ReferenceBinding declaringClass) {
554+
RecordComponentBinding [] rcbs = declaringClass.components();
555+
RecordComponent [] recordComponents = new RecordComponent[rcbs.length];
556+
for (int i = 0, length = rcbs.length; i < length; i++)
557+
recordComponents[i] = rcbs[i].sourceRecordComponent();
558+
return recordComponents;
559+
}
552560
private int addComponentAttributes(RecordComponentBinding recordComponentBinding, int componetAttributeOffset) {
553561
// See JVMS 14 Table 4.7-C - Record Preview for allowed attributes
554562
int attributesNumber = 0;
@@ -1115,9 +1123,7 @@ private void addSyntheticRecordCanonicalConstructor(TypeDeclaration typeDecl, Sy
11151123
.referenceCompilationUnit()
11161124
.compilationResult
11171125
.getLineSeparatorPositions());
1118-
// update the number of attributes
1119-
this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
1120-
this.contents[methodAttributeOffset] = (byte) attributeNumber;
1126+
completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber);
11211127
}
11221128

11231129
private void addSyntheticRecordOverrideMethods(TypeDeclaration typeDecl, SyntheticMethodBinding methodBinding, int purpose) {
@@ -2313,9 +2319,9 @@ public void completeCodeAttributeForSyntheticMethod(
23132319
((SourceTypeBinding) binding.declaringClass).scope);
23142320
}
23152321

2316-
private void completeArgumentAnnotationInfo(Argument[] arguments, List<AnnotationContext> allAnnotationContexts) {
2322+
private void completeArgumentAnnotationInfo(AbstractVariableDeclaration[] arguments, List<AnnotationContext> allAnnotationContexts) {
23172323
for (int i = 0, max = arguments.length; i < max; i++) {
2318-
Argument argument = arguments[i];
2324+
AbstractVariableDeclaration argument = arguments[i];
23192325
if ((argument.bits & ASTNode.HasTypeAnnotations) != 0) {
23202326
argument.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER, i, allAnnotationContexts);
23212327
}
@@ -2376,6 +2382,9 @@ public void completeMethodInfo(
23762382
}
23772383
}
23782384
}
2385+
} else if (binding instanceof SyntheticMethodBinding syntheticMethod && syntheticMethod.isCanonicalConstructor()) {
2386+
AbstractVariableDeclaration[] parameters = getRecordComponents(syntheticMethod.declaringClass);
2387+
completeArgumentAnnotationInfo(parameters, allTypeAnnotationContexts);
23792388
} else if (binding.sourceLambda() != null) { // SyntheticMethodBinding, purpose : LambdaMethod.
23802389
LambdaExpression lambda = binding.sourceLambda();
23812390
if ((lambda.bits & ASTNode.HasTypeAnnotations) != 0) {
@@ -4173,7 +4182,7 @@ private int generateLocalVariableTableAttribute(int code_length, boolean methodD
41734182
LocalVariableBinding localVariable = this.codeStream.locals[i];
41744183
int initializationCount = localVariable.initializationCount;
41754184
if (initializationCount == 0) continue;
4176-
if (localVariable.declaration == null) continue;
4185+
if (localVariable.declaration == null && !(localVariable.declaringScope != null && localVariable.declaringScope.referenceContext() instanceof ConstructorDeclaration cd && cd.isCompactConstructor())) continue;
41774186
final TypeBinding localVariableTypeBinding = localVariable.type;
41784187
boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
41794188
if (isParameterizedType) {
@@ -4335,15 +4344,13 @@ public int generateMethodInfoAttributes(MethodBinding methodBinding) {
43354344
attributesNumber += generateSignatureAttribute(genericSignature);
43364345
}
43374346
AbstractMethodDeclaration methodDeclaration = methodBinding.sourceMethod();
4338-
if (methodBinding instanceof SyntheticMethodBinding) {
4339-
SyntheticMethodBinding syntheticMethod = (SyntheticMethodBinding) methodBinding;
4347+
if (methodBinding instanceof SyntheticMethodBinding syntheticMethod) {
43404348
if (syntheticMethod.purpose == SyntheticMethodBinding.BridgeMethod
43414349
|| (syntheticMethod.purpose == SyntheticMethodBinding.SuperMethodAccess
43424350
&& CharOperation.equals(syntheticMethod.selector, syntheticMethod.targetMethod.selector))) {
43434351
methodDeclaration = ((SyntheticMethodBinding) methodBinding).targetMethod.sourceMethod();
43444352
}
43454353
if (syntheticMethod.recordComponentBinding != null) {
4346-
assert methodDeclaration == null;
43474354
long rcMask = TagBits.AnnotationForMethod | TagBits.AnnotationForTypeUse;
43484355
// record component (field) accessor method
43494356
ReferenceBinding declaringClass = methodBinding.declaringClass;
@@ -4370,6 +4377,9 @@ public int generateMethodInfoAttributes(MethodBinding methodBinding) {
43704377
() -> allTypeAnnotationContexts);
43714378
}
43724379
}
4380+
} else if (syntheticMethod.isCanonicalConstructor()) {
4381+
AbstractVariableDeclaration[] parameters = getRecordComponents(syntheticMethod.declaringClass);
4382+
attributesNumber += generateRuntimeAnnotationsForParameters(parameters);
43734383
}
43744384
}
43754385
if (methodDeclaration != null) {
@@ -4378,9 +4388,9 @@ public int generateMethodInfoAttributes(MethodBinding methodBinding) {
43784388
attributesNumber += generateRuntimeAnnotations(annotations, methodBinding.isConstructor() ? TagBits.AnnotationForConstructor : TagBits.AnnotationForMethod);
43794389
}
43804390
if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) {
4381-
Argument[] arguments = methodDeclaration.arguments;
4391+
AbstractVariableDeclaration[] arguments = methodBinding.isCompactConstructor() ?
4392+
getRecordComponents(methodBinding.declaringClass) : methodDeclaration.arguments;
43824393
if (arguments != null) {
4383-
propagateRecordComponentArguments(methodDeclaration);
43844394
attributesNumber += generateRuntimeAnnotationsForParameters(arguments);
43854395
}
43864396
}
@@ -4434,26 +4444,6 @@ private int completeRuntimeTypeAnnotations(int attributesNumber,
44344444
}
44354445
return attributesNumber;
44364446
}
4437-
private void propagateRecordComponentArguments(AbstractMethodDeclaration methodDeclaration) {
4438-
if ((methodDeclaration.bits & ASTNode.IsImplicit) == 0)
4439-
return;
4440-
ReferenceBinding declaringClass = methodDeclaration.binding.declaringClass;
4441-
if (declaringClass instanceof SourceTypeBinding) {
4442-
assert declaringClass.isRecord();
4443-
RecordComponentBinding[] rcbs = ((SourceTypeBinding) declaringClass).components();
4444-
Argument[] arguments = methodDeclaration.arguments;
4445-
for (int i = 0, length = rcbs.length; i < length; i++) {
4446-
RecordComponentBinding rcb = rcbs[i];
4447-
RecordComponent recordComponent = rcb.sourceRecordComponent();
4448-
if ((recordComponent.bits & ASTNode.HasTypeAnnotations) != 0) {
4449-
methodDeclaration.bits |= ASTNode.HasTypeAnnotations;
4450-
arguments[i].bits |= ASTNode.HasTypeAnnotations;
4451-
}
4452-
long rcMask = TagBits.AnnotationForParameter | TagBits.AnnotationForTypeUse;
4453-
arguments[i].annotations = ASTNode.getRelevantAnnotations(recordComponent.annotations, rcMask, null);
4454-
}
4455-
}
4456-
}
44574447

44584448
public int generateMethodInfoAttributes(MethodBinding methodBinding, AnnotationMethodDeclaration declaration) {
44594449
int attributesNumber = generateMethodInfoAttributes(methodBinding);
@@ -4769,15 +4759,15 @@ private int generateRuntimeAnnotations(final Annotation[] annotations, final lon
47694759
return attributesNumber;
47704760
}
47714761

4772-
private int generateRuntimeAnnotationsForParameters(Argument[] arguments) {
4762+
private int generateRuntimeAnnotationsForParameters(AbstractVariableDeclaration[] arguments) {
47734763
final int argumentsLength = arguments.length;
47744764
final int VISIBLE_INDEX = 0;
47754765
final int INVISIBLE_INDEX = 1;
47764766
int invisibleParametersAnnotationsCounter = 0;
47774767
int visibleParametersAnnotationsCounter = 0;
47784768
int[][] annotationsCounters = new int[argumentsLength][2];
47794769
for (int i = 0; i < argumentsLength; i++) {
4780-
Argument argument = arguments[i];
4770+
AbstractVariableDeclaration argument = arguments[i];
47814771
Annotation[] annotations = argument.annotations;
47824772
if (annotations != null) {
47834773
for (Annotation a : annotations) {
@@ -4824,7 +4814,7 @@ private int generateRuntimeAnnotationsForParameters(Argument[] arguments) {
48244814
this.contentsOffset += 2;
48254815
int counter = 0;
48264816
if (numberOfInvisibleAnnotations != 0) {
4827-
Argument argument = arguments[i];
4817+
AbstractVariableDeclaration argument = arguments[i];
48284818
Annotation[] annotations = argument.annotations;
48294819
for (Annotation a : annotations) {
48304820
Annotation annotation;
@@ -4885,7 +4875,7 @@ private int generateRuntimeAnnotationsForParameters(Argument[] arguments) {
48854875
this.contentsOffset += 2;
48864876
int counter = 0;
48874877
if (numberOfVisibleAnnotations != 0) {
4888-
Argument argument = arguments[i];
4878+
AbstractVariableDeclaration argument = arguments[i];
48894879
Annotation[] annotations = argument.annotations;
48904880
for (Annotation a : annotations) {
48914881
Annotation annotation;
@@ -5039,6 +5029,7 @@ private int generateMethodParameters(final MethodBinding binding) {
50395029
AbstractMethodDeclaration methodDeclaration = binding.sourceMethod();
50405030

50415031
boolean isConstructor = binding.isConstructor();
5032+
boolean isCanonicalConstructor = binding.isCanonicalConstructor();
50425033
TypeBinding[] targetParameters = binding.parameters;
50435034
ReferenceBinding declaringClass = binding.declaringClass;
50445035

@@ -5053,7 +5044,8 @@ private int generateMethodParameters(final MethodBinding binding) {
50535044
}
50545045
}
50555046

5056-
boolean needSynthetics = isConstructor && declaringClass.isNestedType();
5047+
boolean needSynthetics = isCanonicalConstructor ? false : // WYSIWYG
5048+
isConstructor && !isCanonicalConstructor && declaringClass.isNestedType();
50575049
if (needSynthetics) {
50585050
// Take into account the synthetic argument names
50595051
// This tracks JLS8, paragraph 8.8.9
@@ -5081,19 +5073,31 @@ private int generateMethodParameters(final MethodBinding binding) {
50815073
}
50825074
}
50835075
if (targetParameters != Binding.NO_PARAMETERS) {
5084-
Argument[] arguments = null;
5085-
if (methodDeclaration != null && methodDeclaration.arguments != null) {
5086-
arguments = methodDeclaration.arguments;
5087-
}
5088-
for (int i = 0, max = targetParameters.length, argumentsLength = arguments != null ? arguments.length : 0; i < max; i++) {
5089-
if (argumentsLength > i && arguments[i] != null) {
5090-
Argument argument = arguments[i];
5091-
int modifiers = argument.binding.modifiers;
5092-
if (binding.isCompactConstructor())
5093-
modifiers |= ClassFileConstants.AccMandated;
5094-
length = writeArgumentName(argument.name, modifiers, length);
5095-
} else {
5096-
length = writeArgumentName(null, ClassFileConstants.AccSynthetic, length);
5076+
if (binding.isCompactConstructor()) {
5077+
LocalVariableBinding [] locals = binding.sourceMethod().scope.locals;
5078+
for (LocalVariableBinding local : locals) {
5079+
if (local == null || !local.isParameter())
5080+
continue;
5081+
int modifiers = local.modifiers | ClassFileConstants.AccMandated;
5082+
length = writeArgumentName(local.name, modifiers, length);
5083+
}
5084+
} else if (binding.isCanonicalConstructor() && methodDeclaration == null) { // synthetic
5085+
for (RecordComponentBinding component : binding.declaringClass.components()) {
5086+
length = writeArgumentName(component.name, ClassFileConstants.AccDefault, length);
5087+
}
5088+
} else {
5089+
Argument[] arguments = null;
5090+
if (methodDeclaration != null && methodDeclaration.arguments != null) {
5091+
arguments = methodDeclaration.arguments;
5092+
}
5093+
for (int i = 0, max = targetParameters.length, argumentsLength = arguments != null ? arguments.length : 0; i < max; i++) {
5094+
if (argumentsLength > i && arguments[i] != null) {
5095+
Argument argument = arguments[i];
5096+
int modifiers = argument.binding.modifiers;
5097+
length = writeArgumentName(argument.name, modifiers, length);
5098+
} else {
5099+
throw EclipseCompiler.UNEXPECTED_CONTROL_FLOW;
5100+
}
50975101
}
50985102
}
50995103
}

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import javax.lang.model.type.TypeMirror;
2323
import org.eclipse.jdt.core.compiler.CharOperation;
2424
import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
25+
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
2526
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
2627
import org.eclipse.jdt.internal.compiler.ast.Argument;
28+
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
2729
import org.eclipse.jdt.internal.compiler.lookup.*;
2830

2931
public class ExecutableElementImpl extends ElementImpl implements
@@ -119,9 +121,25 @@ public List<? extends VariableElement> getParameters() {
119121
AbstractMethodDeclaration methodDeclaration = binding.sourceMethod();
120122
List<VariableElement> params = new ArrayList<>(length);
121123
if (methodDeclaration != null) {
122-
for (Argument argument : methodDeclaration.arguments) {
123-
VariableElement param = new VariableElementImpl(this._env, argument.binding);
124-
params.add(param);
124+
if (methodDeclaration.arguments != null) {
125+
for (Argument argument : methodDeclaration.arguments) {
126+
VariableElement param = new VariableElementImpl(this._env, argument.binding);
127+
params.add(param);
128+
}
129+
} else if (methodDeclaration.isCompactConstructor()) {
130+
RecordComponentBinding[] components = binding.declaringClass.components();
131+
for (int i = 0; i < length; i++) {
132+
List<AnnotationBinding> relevantAnnotations = new ArrayList<>();
133+
ASTNode.getRelevantAnnotations(components[i].sourceRecordComponent().annotations, TagBits.AnnotationForParameter, relevantAnnotations);
134+
LocalVariableBinding pi = new LocalVariableBinding(binding.parameterNames[i], binding.parameters[i], ClassFileConstants.AccDefault, true) {
135+
@Override
136+
public AnnotationBinding[] getAnnotations() {
137+
return relevantAnnotations.toArray(new AnnotationBinding[0]);
138+
}
139+
};
140+
VariableElement param = new VariableElementImpl(this._env, pi);
141+
params.add(param);
142+
}
125143
}
126144
} else {
127145
// binary method

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ASTNode.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
7676
public final static int Bit7 = 0x40; // depth (name ref, msg) | need runtime checkcast (cast expression) | label used (labelStatement) | needFreeReturn (AbstractMethodDeclaration) | Used in Pattern Guard expression (NameReference)
7777
public final static int Bit8 = 0x80; // depth (name ref, msg) | unsafe cast (cast expression) | is default constructor (constructor declaration) | isElseStatementUnreachable (if statement)
7878
public final static int Bit9 = 0x100; // depth (name ref, msg) | operator (operator) | is local type (type decl) | isThenStatementUnreachable (if statement) | can be static
79-
public final static int Bit10= 0x200; // depth (name ref, msg) | operator (operator) | is anonymous type (type decl) | is implicit constructor (constructor)
79+
public final static int Bit10= 0x200; // depth (name ref, msg) | operator (operator) | is anonymous type (type decl)
8080
public final static int Bit11 = 0x400; // depth (name ref, msg) | operator (operator) | is member type (type decl)
8181
public final static int Bit12 = 0x800; // depth (name ref, msg) | operator (operator) | has abstract methods (type decl)
8282
public final static int Bit13 = 0x1000; // depth (name ref, msg) | operator (operator) | is secondary type (type decl)
@@ -177,7 +177,6 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
177177
public static final int IsSecretYieldValueUsage = Bit5;
178178

179179
// for statements
180-
// public static final int IsImplicit = Bit11; // record declaration
181180
public static final int IsReachable = Bit32;
182181
public static final int LabelUsed = Bit7;
183182
public static final int DocumentedFallthrough = Bit30; // switch statement
@@ -237,7 +236,6 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
237236
// for constructor declaration
238237
public static final int IsDefaultConstructor = Bit8;
239238
public static final int IsCanonicalConstructor = Bit10; // record declaration
240-
public static final int IsImplicit = Bit11; // record declaration / generated statements in compact constructor
241239

242240
// for compilation unit
243241
public static final int HasAllMethodBodies = Bit5;
@@ -311,7 +309,6 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
311309
public static final int InsideExpressionStatement = Bit21;
312310

313311
// for annotation reference, signal if annotation was created from a default:
314-
// also used for implicit method creation of records Java 14
315312
public static final int IsSynthetic = ASTNode.Bit7;
316313

317314
// for all reference context entries.
@@ -322,6 +319,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
322319
public static final RecordComponent [] NO_RECORD_COMPONENTS = new RecordComponent [0];
323320
public static final TypePattern[] NO_TYPE_PATTERNS = new TypePattern[0];
324321
public static final LocalVariableBinding[] NO_VARIABLES = new LocalVariableBinding[0];
322+
public static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
325323

326324
public ASTNode() {
327325

0 commit comments

Comments
 (0)