Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental refactoring for Records classes v2.0 #3728

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core.compiler.batch/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Main-Class: org.eclipse.jdt.internal.compiler.batch.Main
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse Compiler for Java(TM)
Bundle-SymbolicName: org.eclipse.jdt.core.compiler.batch
Bundle-Version: 3.41.0.qualifier
Bundle-Version: 3.41.100.qualifier
Bundle-ClassPath: .
Bundle-Vendor: Eclipse.org
Automatic-Module-Name: org.eclipse.jdt.core.compiler.batch
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core.compiler.batch/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<version>4.36.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jdt.core.compiler.batch</artifactId>
<version>3.41.0-SNAPSHOT</version>
<version>3.41.100-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ public void endVisit(ClassLiteralAccess classLiteral, BlockScope scope) {
public void endVisit(Clinit clinit, ClassScope scope) {
// do nothing by default
}
public void endVisit(CompactConstructorDeclaration ccd, ClassScope scope) {
// do nothing by default
}
public void endVisit(
CompilationUnitDeclaration compilationUnitDeclaration,
CompilationUnitScope scope) {
Expand Down Expand Up @@ -607,9 +604,6 @@ public boolean visit(Clinit clinit, ClassScope scope) {
public boolean visit(ModuleDeclaration module, CompilationUnitScope scope) {
return true;
}
public boolean visit(CompactConstructorDeclaration ccd, ClassScope scope) {
return true; // do nothing by default, keep traversing
}
public boolean visit(
CompilationUnitDeclaration compilationUnitDeclaration,
CompilationUnitScope scope) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,6 @@ public boolean visit(ModuleDeclaration module, CompilationUnitScope scope) {
return visitNode(module);
}

@Override
public boolean visit(CompactConstructorDeclaration ccd, ClassScope scope) {
return visitNode(ccd);
}

@Override
public boolean visit(CompilationUnitDeclaration compilationUnitDeclaration, CompilationUnitScope scope) {
return visitNode(compilationUnitDeclaration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,11 @@ public boolean isCanonicalConstructor() {

return false;
}

public boolean isCompactConstructor() {
return false;
}

public boolean isDefaultConstructor() {

return false;
Expand Down Expand Up @@ -606,6 +611,11 @@ public void resolve(ClassScope upperScope) {
this.ignoreFurtherInvestigation = true;
}

if (this.isCompactConstructor() && !upperScope.referenceContext.isRecord()) {
upperScope.problemReporter().compactConstructorsOnlyInRecords(this);
return;
}

try {
bindArguments();
resolveReceiver();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public TypeBinding bind(MethodScope scope, TypeBinding typeBinding, boolean used
if (!this.isUnnamed(scope)) {
if ((this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope()) {
scope.problemReporter().lambdaRedeclaresArgument(this);
} else if (scope.referenceContext instanceof CompactConstructorDeclaration) {
} else if (scope.referenceContext instanceof ConstructorDeclaration cd && cd.isCompactConstructor()) {
// skip error reporting - hidden params - already reported in record components
} else {
scope.problemReporter().redefineArgument(this);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.eclipse.jdt.internal.compiler.codegen.Opcodes;
import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream;
import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
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.impl.CompilerOptions;
Expand Down Expand Up @@ -206,6 +205,14 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
this.bits |= ASTNode.NeedFreeReturn;
}

if (this.isCompactConstructor()) {
for (FieldBinding field : this.binding.declaringClass.fields()) {
if (!field.isStatic()) {
flowInfo.markAsDefinitelyAssigned(field);
}
}
}

// reuse the initial reach mode for diagnosing missing blank finals
// no, we should use the updated reach mode for diagnosing uninitialized blank finals.
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=235781
Expand All @@ -216,7 +223,6 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
&& (this.constructorCall.accessMode != ExplicitConstructorCall.This)) {
flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn);
FieldBinding[] fields = this.binding.declaringClass.fields();
checkAndGenerateFieldAssignment(initializerFlowContext, flowInfo, fields);
doFieldReachAnalysis(flowInfo, fields);
}
// check unreachable catch blocks
Expand Down Expand Up @@ -249,10 +255,6 @@ protected void doFieldReachAnalysis(FlowInfo flowInfo, FieldBinding[] fields) {
}
}
}

protected void checkAndGenerateFieldAssignment(FlowContext flowContext, FlowInfo flowInfo, FieldBinding[] fields) {
return;
}
boolean isValueProvidedUsingAnnotation(FieldDeclaration fieldDecl) {
// a member field annotated with @Inject is considered to be initialized by the injector
if (fieldDecl.annotations != null) {
Expand Down Expand Up @@ -481,6 +483,16 @@ private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
}
if ((this.bits & ASTNode.NeedFreeReturn) != 0) {
if (this.isCompactConstructor()) {
// Note: the body of a compact constructor may not contain a return statement and so will need an injected return
for (RecordComponent rc : classScope.referenceContext.recordComponents) {
LocalVariableBinding parameter = this.scope.findVariable(rc.name);
FieldBinding field = classScope.referenceContext.binding.getField(rc.name, true).original();
codeStream.aload_0();
codeStream.load(parameter);
codeStream.fieldAccess(Opcodes.OPC_putfield, field, classScope.referenceContext.binding);
}
}
codeStream.return_();
}
// See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1796#issuecomment-1933458054
Expand Down Expand Up @@ -602,7 +614,11 @@ public boolean isRecursive(ArrayList visited) {
@Override
public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
//fill up the constructor body with its statements
if (((this.bits & ASTNode.IsDefaultConstructor) != 0) && this.constructorCall == null){
if (this.isCompactConstructor()) {
this.constructorCall = SuperReference.implicitSuperConstructorCall();
this.constructorCall.sourceStart = this.sourceStart;
this.constructorCall.sourceEnd = this.sourceEnd;
} else if (((this.bits & ASTNode.IsDefaultConstructor) != 0) && this.constructorCall == null){
this.constructorCall = SuperReference.implicitSuperConstructorCall();
this.constructorCall.sourceStart = this.sourceStart;
this.constructorCall.sourceEnd = this.sourceEnd;
Expand Down Expand Up @@ -676,7 +692,7 @@ public void resolveStatements() {
}
this.constructorCall = null;
} else if (sourceType.isRecord() &&
!(this instanceof CompactConstructorDeclaration) && // compact constr should be marked as canonical?
!this.isCompactConstructor() && // compact constr should be marked as canonical?
(this.binding != null && !this.binding.isCanonicalConstructor()) &&
this.constructorCall.accessMode != ExplicitConstructorCall.This) {
this.scope.problemReporter().recordMissingExplicitConstructorCallInNonCanonicalConstructor(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ public void resolve(BlockScope scope) {
}
}
if (hasError) {
if (!(methodDeclaration instanceof CompactConstructorDeclaration)) {// already flagged for CCD
if (!methodDeclaration.isCompactConstructor()) {// already flagged for CCD
if (JavaFeature.FLEXIBLE_CONSTRUCTOR_BODIES.isSupported(scope.compilerOptions())) {
boolean isTopLevel = Arrays.stream(methodDeclaration.statements).anyMatch(this::equals);
if (isTopLevel)
Expand Down Expand Up @@ -495,7 +495,7 @@ private boolean checkAndFlagExplicitConstructorCallInCanonicalConstructor(Abstra
if (methodDecl.binding == null || methodDecl.binding.declaringClass == null
|| !methodDecl.binding.declaringClass.isRecord())
return true;
boolean isInsideCCD = methodDecl instanceof CompactConstructorDeclaration;
boolean isInsideCCD = methodDecl.isCompactConstructor();
if (this.accessMode != ExplicitConstructorCall.ImplicitSuper) {
if (isInsideCCD)
scope.problemReporter().recordCompactConstructorHasExplicitConstructorCall(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowConte
&& !(this.receiver instanceof QualifiedThisReference)
&& ((this.receiver.bits & ASTNode.ParenthesizedMASK) == 0) // (this).x is forbidden
&& currentScope.allowBlankFinalFieldAssignment(this.binding)
&& !currentScope.methodScope().isCompactConstructorScope) {
&& (!(currentScope.methodScope().referenceContext instanceof ConstructorDeclaration cd) || !cd.isCompactConstructor())) {
if (flowInfo.isPotentiallyAssigned(this.binding)) {
currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
this.binding,
Expand All @@ -107,7 +107,7 @@ public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowConte
}
flowInfo.markAsDefinitelyAssigned(this.binding);
} else {
if (currentScope.methodScope().isCompactConstructorScope)
if (currentScope.methodScope().referenceContext instanceof ConstructorDeclaration cd && cd.isCompactConstructor())
currentScope.problemReporter().recordIllegalExplicitFinalFieldAssignInCompactConstructor(this.binding, this);
else
// assigning a final field outside an initializer or constructor or wrong reference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void resolve(BlockScope scope) {
*/
public void resolve(BlockScope scope, boolean warn, boolean considerParamRefAsUsage) {

LocalVariableBinding variableBinding = scope.findVariable(this.token, this);
LocalVariableBinding variableBinding = scope.findVariable(this.token);
if (variableBinding != null && variableBinding.isValidBinding() && ((variableBinding.tagBits & TagBits.IsArgument) != 0)) {
this.binding = variableBinding;
if (considerParamRefAsUsage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,7 @@ public ConstructorDeclaration getConstructor(Parser parser) {
this.methods[i] = m;
}
} else {
if (am instanceof CompactConstructorDeclaration) {
CompactConstructorDeclaration ccd = (CompactConstructorDeclaration) am;
ccd.recordDeclaration = this;
if (am instanceof ConstructorDeclaration ccd && ccd.isCompactConstructor()) {
if (ccd.arguments == null)
ccd.arguments = getArgumentsFromComponents(this.recordComponents);
return ccd;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ public LocalDeclaration[] findLocalVariableDeclarations(int position) {
return null;
}
@Override
public LocalVariableBinding findVariable(char[] variableName, InvocationSite invocationSite) {
public LocalVariableBinding findVariable(char[] variableName) {
int varLength = variableName.length;
for (int i = this.localIndex-1; i >= 0; i--) { // lookup backward to reach latest additions first
LocalVariableBinding local = this.locals[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ public class MethodScope extends BlockScope {
// remember suppressed warning re missing 'default:' to give hints on possibly related flow problems
public boolean hasMissingSwitchDefault; // TODO(stephan): combine flags to a bitset?

public boolean isCompactConstructorScope = false;

static {
if (Boolean.getBoolean("jdt.flow.test.extra")) { //$NON-NLS-1$
baseAnalysisIndex = 64;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2052,7 +2052,7 @@ public ReferenceBinding findType(
return typeBinding;
}

public LocalVariableBinding findVariable(char[] variable, InvocationSite invocationSite) {
public LocalVariableBinding findVariable(char[] variable) {
return null;
}

Expand Down Expand Up @@ -2114,7 +2114,7 @@ public Binding getBinding(char[] name, int mask, InvocationSite invocationSite,
case BLOCK_SCOPE :
if (!resolvingGuardExpression)
resolvingGuardExpression = scope.resolvingGuardExpression();
LocalVariableBinding variableBinding = scope.findVariable(name, invocationSite);
LocalVariableBinding variableBinding = scope.findVariable(name);
// looks in this scope only
if (variableBinding != null) {
if (foundField != null && foundField.isValidBinding())
Expand Down
Loading
Loading