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

JEP-445: allow parsing unnamed classes #1487

Closed
wants to merge 3 commits into from
Closed
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
29 changes: 22 additions & 7 deletions org.eclipse.jdt.core.compiler.batch/grammar/java.g
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
--main options
%options ACTION, AN=JavaAction.java, GP=java,
%options FILE-PREFIX=java, ESCAPE=$, PREFIX=TokenName, OUTPUT-SIZE=125 ,
%options NOGOTO-DEFAULT, SINGLE-PRODUCTIONS, LALR=1 , TABLE,
%options ACTION
%options AN=JavaAction.java
%options GP=java,
%options FILE-PREFIX=java
%options ESCAPE=$
%options PREFIX=TokenName
%options OUTPUT-SIZE=125
%options NOGOTO-DEFAULT
%options SINGLE-PRODUCTIONS
%options LALR=1
%options TABLE

--error recovering options.....
%options ERROR_MAPS
Expand Down Expand Up @@ -432,10 +440,6 @@ InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
/.$putCase consumeInternalCompilationUnitWithTypes(); $break ./
InternalCompilationUnit ::= ImportDeclarations ReduceImports
/.$putCase consumeInternalCompilationUnit(); $break ./
InternalCompilationUnit ::= TypeDeclarations
/.$putCase consumeInternalCompilationUnitWithTypes(); $break ./
InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
/.$putCase consumeInternalCompilationUnitWithTypes(); $break ./
InternalCompilationUnit ::= $empty
/.$putCase consumeEmptyInternalCompilationUnit(); $break ./
/:$readableName CompilationUnit:/
Expand All @@ -451,6 +455,12 @@ ModuleDeclaration ::= ModuleHeader ModuleBody
/:$compliance 9:/
/.$putCase consumeModuleDeclaration(); $break ./

-- JEP 445: unnamed class, this may capture type declarations without unnamed class, this case is fixed/reduced upon completioon of parsing
InternalCompilationUnit ::= UnnamedClassBodyDeclarations
/.$putCase consumeInternalCompilationUnitWithPotentialUnnamedClass(); $break ./
InternalCompilationUnit ::= ImportDeclarations ReduceImports UnnamedClassBodyDeclarations
/.$putCase consumeInternalCompilationUnitWithPotentialUnnamedClass(); $break ./

-- to work around shift/reduce conflicts, we allow Modifiersopt in order to support annotations
-- in a module declaration, and then report errors if any modifiers other than annotations are
-- encountered
Expand Down Expand Up @@ -744,6 +754,11 @@ ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration
ClassBodyDeclaration -> ClassMemberDeclaration
ClassBodyDeclaration -> StaticInitializer
ClassBodyDeclaration -> ConstructorDeclaration

UnnamedClassBodyDeclarations -> ClassMemberDeclaration
UnnamedClassBodyDeclarations -> ClassMemberDeclaration UnnamedClassBodyDeclarations
/.$putCase consumeUnnamedClassBodyDeclarations(); $break ./
/:$readableName UnnamedClassBodyDeclarations:/
--1.1 feature
ClassBodyDeclaration ::= Diet NestedMethod CreateInitializer Block
/.$putCase consumeClassBodyDeclaration(); $break ./
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2553,11 +2553,22 @@ public interface IProblem {
* @noreference preview feature
*/
int CannotInferRecordPatternTypes = PreviewRelated + 1940;

/**
* @since 3.36
* @noreference preview feature
*/
int unnamedIsMissingMainMethod = PreviewRelated + 1950;
/**
* @since 3.36
* @noreference preview feature
*/
int topLevelWithUnnamed = PreviewRelated + 1951;

/**
* @since 3.36
*/
int IllegalRecordPattern = TypeRelated + 1941;
int IllegalRecordPattern = TypeRelated + 1952;


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
Expand Down Expand Up @@ -133,6 +134,10 @@ public void analyseCode() {
return;
try {
if (this.types != null) {
if (this.types.length > 1 &&
Stream.of(this.types).anyMatch(UnnamedClass.class::isInstance)) {
this.problemReporter.cannotDefineTopLevelTypesWithUnnamed();
}
for (int i = 0, count = this.types.length; i < count; i++) {
this.types[i].analyseCode(this.scope);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;

import java.util.Arrays;
import java.util.List;
import java.util.function.BiPredicate;

Expand Down Expand Up @@ -443,4 +444,13 @@ public void traverse(
public TypeParameter[] typeParameters() {
return this.typeParameters;
}

public boolean isMainMethodCandidate() {
return "main".equals(new String(this.selector)) && //$NON-NLS-1$
(this.arguments == null || this.arguments.length == 0 ||
(this.arguments.length == 1 &&
this.arguments[0].type.getTypeBinding(this.scope) instanceof ReferenceBinding typeRef &&
typeRef.dimensions() == 1 &&
Arrays.deepEquals(TypeConstants.JAVA_LANG_STRING, typeRef.compoundName)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;

import java.util.Arrays;

import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;

/**
* Represents an unnamed class as defined in JEP 445
*/
public class UnnamedClass extends TypeDeclaration {

public UnnamedClass(CompilationResult result) {
super(result);
this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccFinal;
this.name = "<unnamed class>".toCharArray(); //$NON-NLS-1$
}


@Override
public void analyseCode(CompilationUnitScope unitScope) {
super.analyseCode(unitScope);
if (this.ignoreFurtherInvestigation)
return;
if (Arrays.stream(this.methods)
.filter(MethodDeclaration.class::isInstance)
.map(MethodDeclaration.class::cast)
.noneMatch(MethodDeclaration::isMainMethodCandidate)) {
unitScope.problemReporter().unnamedClassMustHaveMainMethod();
this.ignoreFurtherInvestigation = true;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2042,6 +2042,9 @@ public ReferenceBinding findType(
if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage))
return new ProblemReferenceBinding(new char[][]{typeName}, typeBinding, ProblemReasons.NotVisible);
}
if (typeBinding instanceof SourceTypeBinding sourceType && sourceType.scope != null && sourceType.scope.referenceContext instanceof UnnamedClass) {
return null; // make unnamed not resolvable by name
}
return typeBinding;
}

Expand Down Expand Up @@ -3529,9 +3532,10 @@ final Binding getTypeOrPackage(char[] name, int mask, boolean needResolve) {
PackageBinding currentPackage = unitScope.fPackage;
unitScope.recordReference(currentPackage.compoundName, name);
Binding binding = currentPackage.getTypeOrPackage(name, module(), false);
if (binding instanceof ReferenceBinding) {
ReferenceBinding referenceType = (ReferenceBinding) binding;
if ((referenceType.tagBits & TagBits.HasMissingType) == 0) {
if (binding instanceof ReferenceBinding referenceType) {
if (referenceType instanceof SourceTypeBinding sourceType && sourceType.unnamedClass) {
return new ProblemReferenceBinding(new char[][] {name}, null, ProblemReasons.NotAccessible);
} else if ((referenceType.tagBits & TagBits.HasMissingType) == 0) {
if (typeOrPackageCache != null)
typeOrPackageCache.put(name, referenceType);
return referenceType; // type is always visible to its own package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.UnnamedClass;
import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
Expand Down Expand Up @@ -138,9 +139,13 @@ public class SourceTypeBinding extends ReferenceBinding {
public boolean isVarArgs = false; // for record declaration
private FieldBinding[] implicitComponentFields; // cache
private MethodBinding[] recordComponentAccessors = null; // hash maybe an overkill
public final boolean unnamedClass;

public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) {
this.compoundName = compoundName;
this.unnamedClass = scope.referenceContext instanceof UnnamedClass;
this.compoundName = scope.referenceContext instanceof UnnamedClass unnamed
? new char[][] { unnamed.getCompilationUnitDeclaration().getMainTypeName() }
: compoundName;
this.fPackage = fPackage;
this.fileName = scope.referenceCompilationUnit().getFileName();
this.modifiers = scope.referenceContext.modifiers;
Expand All @@ -163,6 +168,7 @@ public SourceTypeBinding(SourceTypeBinding prototype) {
this.prototype = prototype.prototype;
this.prototype.tagBits |= TagBits.HasAnnotatedVariants;
this.tagBits &= ~TagBits.HasAnnotatedVariants;
this.unnamedClass = prototype.unnamedClass;

this.superclass = prototype.superclass;
this.superInterfaces = prototype.superInterfaces;
Expand Down
Loading