1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
/*******************************************************************************
* Copyright (c) 2019 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.parser.Parser;
public class CompactConstructorDeclaration extends ConstructorDeclaration {
public TypeDeclaration recordDeclaration;
public CompactConstructorDeclaration(CompilationResult compilationResult) {
super(compilationResult);
}
@Override
public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
parser.parse(this, unit, false);
this.containsSwitchWithTry = parser.switchWithTry;
}
@Override
public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo, int initialReachMode) {
try {
this.scope.isCompactConstructorScope = true;
super.analyseCode(classScope, initializerFlowContext, flowInfo, initialReachMode);
} finally {
this.scope.isCompactConstructorScope = false;
}
}
@Override
protected void doFieldReachAnalysis(FlowInfo flowInfo, FieldBinding[] fields) {
// do nothing
}
@Override
protected void checkAndGenerateFieldAssignment(FlowContext flowContext, FlowInfo flowInfo, FieldBinding[] fields) {
this.scope.isCompactConstructorScope = false;
if (fields == null)
return;
/* JLS 15 Record addendum Sec 8.10.4 All fields corresponding to the record components of the
* record class are implicitly initialized to the value of the corresponding formal
* parameter after the body of the compact constructor.
* These fields are implicitly initialized in the order that they are declared
* in the record component list.
*/
List<Statement> fieldAssignments = new ArrayList<>();
for (FieldBinding field : fields) {
if (field.isStatic())
continue;
assert field.isFinal();
FieldReference lhs = new FieldReference(field.name,0);
lhs.receiver = new ThisReference(0, 0);
//TODO: Check whether anything has to be done for null analysis.
Assignment assignment = new Assignment(lhs, new SingleNameReference(field.name, 0), 0);
assignment.resolveType(this.scope);
assignment.analyseCode(this.scope, flowContext, flowInfo);
assignment.bits |= ASTNode.IsImplicit;
assert flowInfo.isDefinitelyAssigned(field);
fieldAssignments.add(assignment);
}
if (fieldAssignments.isEmpty())
return;
Statement[] fa = fieldAssignments.toArray(new Statement[0]);
if (this.statements == null) {
this.statements = fa;
return;
}
int len = this.statements.length;
int fLen = fa.length;
Statement[] stmts = new Statement[len + fLen];
System.arraycopy(this.statements, 0, stmts, 0, len);
System.arraycopy(fa, 0, stmts, len, fLen);
this.statements = stmts;
}
}
|