Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into BETA_JAVA24
Browse files Browse the repository at this point in the history
  • Loading branch information
mpalat committed Jan 9, 2025
2 parents bbf305d + 0c3986b commit 6b031f2
Show file tree
Hide file tree
Showing 33 changed files with 921 additions and 258 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
Expand All @@ -45,6 +50,7 @@
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
import org.eclipse.jdt.internal.compiler.tool.EclipseFileManager;

public class CompilerToolTests extends TestCase {
private static final boolean DEBUG = false;
Expand Down Expand Up @@ -1430,6 +1436,133 @@ public void testSupportedCompilerVersions() throws IOException {
+ "by compiler " + compiler.getClass().getName(), sourceVersions.contains(sourceVersion));
}
}

/**
* Compiles a class featuring a possible name collision with another one being present in classpath. This can only
* happen on case insensitive file systems.
* @throws IOException If I/O failure
*/
public void testCompilerOneClassWithPackageCollision() throws IOException {

final String tempDir = System.getProperty("java.io.tmpdir");
final String sep = File.separator;
final String classes = "clazzes";
Path targetDir = Paths.get(tempDir, sep, classes, sep, "de", sep, "tk", sep, "foo");
Files.createDirectories(targetDir);

// ********************************************************************************
// Compile first source file
// ********************************************************************************

String source1 = """
package de.tk.foo;
public class Test {
}""";

Path sourceFile1 = createSourceFile(targetDir, "Test.java", source1);
List<File> sourceFiles = Collections.singletonList(sourceFile1.toFile());
EclipseFileManager fileManager = new EclipseFileManager(null, null);
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFiles);
List<String> optionList = List.of("-verbose", "-17");

CompilationTask task1 =
new EclipseCompiler().getTask(
new PrintWriter(System.out),
fileManager, // using 'fileManager' directly works
null,
optionList,
null,
compilationUnits
);

assertTrue("Compilation 1 failed", task1.call());

// ********************************************************************************
// Compile second source file with classpath
// ********************************************************************************

String source2 = """
package de.tk.foo.test;
import de.tk.foo.Test;
// This class might cause false-positive collision with package "de.tk.foo.test" present in classpath
// on case insensitive file systems.
public class Foo {
private Test test = new Test();
@Override
public String toString() {
return test.toString();
}
}""";

Path tempPath = Paths.get(tempDir);
Path sourceFile2 = createSourceFile(tempPath, "Foo.java", source2);
Path clsDir = tempPath.resolve(classes);

sourceFiles = Collections.singletonList(sourceFile2.toFile());
compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFiles);

optionList = new ArrayList<>(optionList); // Create a mutable list
optionList.add("-classpath");
optionList.add(clsDir.toString());

CompilationTask task2 =
new EclipseCompiler().getTask(
new PrintWriter(System.out),
new MyFileManager(fileManager), // using 'fileManager' directly works, but MyFileManager does not
null,
optionList,
null,
compilationUnits
);

assertTrue("Compilation 2 failed", task2.call());

// ********************************************************************************
// Cleanup
// ********************************************************************************

Files.walk(clsDir)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);

assertTrue("Delete failed", Files.deleteIfExists(tempPath.resolve("Foo.class")));
assertFalse("Delete failed", Files.exists(sourceFile1));
assertTrue("Delete failed", Files.deleteIfExists(sourceFile2));
}

/**
* Creates a (source) file in the given directory with content.
* @param dir Target directory
* @param fileName Name of new file
* @param content Content of the file
* @return Created file
* @throws IOException If I/O failure
*/
private Path createSourceFile(Path dir, String fileName, String content) throws IOException {
Path file = dir.resolve(fileName);

try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
writer.write(content);
writer.flush();
}
return file;
}

/**
* This class is used for the test {@link #testCompilerOneClassWithPackageCollision()
* testCompilerOneClassWithPackageCollision}.
*/
class MyFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
protected MyFileManager(StandardJavaFileManager fileManager) {
super(fileManager);
}
}

/*
* Clean up the compiler
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@
import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.StringConstant;
import org.eclipse.jdt.internal.compiler.lookup.*;

@SuppressWarnings({"rawtypes", "unchecked"})
Expand Down Expand Up @@ -501,8 +499,6 @@ public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope, int f
// inside same unit - no report
if (scope.isDefinedInSameUnit(field.declaringClass)) return false;

if (sinceValueUnreached(field, scope)) return false;

// if context is deprecated, may avoid reporting
if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
return true;
Expand Down Expand Up @@ -553,8 +549,6 @@ public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope,
// inside same unit - no report
if (scope.isDefinedInSameUnit(method.declaringClass)) return false;

if (sinceValueUnreached(method, scope)) return false;

// non explicit use and non explicitly deprecated - no report
if (!isExplicitUse &&
(method.modifiers & ClassFileConstants.AccDeprecated) == 0) {
Expand All @@ -566,37 +560,6 @@ public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope,
return true;
}

private boolean sinceValueUnreached(Binding binding, Scope scope) {
if (binding instanceof TypeBinding typeBinding) {
if (!typeBinding.isReadyForAnnotations()) {
return false;
}
}
AnnotationBinding[] annotations = binding.getAnnotations();
for (AnnotationBinding annotation : annotations) {
if (annotation != null && annotation.getAnnotationType().id == TypeIds.T_JavaLangDeprecated) {
ElementValuePair[] pairs = annotation.getElementValuePairs();
for (ElementValuePair pair : pairs) {
if (CharOperation.equals(pair.getName(), TypeConstants.SINCE)) {
if (pair.getValue() instanceof StringConstant strConstant) {
try {
String value = strConstant.stringValue();
long sinceLevel = CompilerOptions.versionToJdkLevel(value);
long complianceLevel = scope.compilerOptions().complianceLevel;
if (complianceLevel < sinceLevel) {
return true;
}
} catch (NumberFormatException e) {
// do nothing and fall through
}
}
}
}
}
}
return false;
}

public boolean isSuper() {

return false;
Expand Down Expand Up @@ -657,8 +620,6 @@ public final boolean isTypeUseDeprecated(TypeBinding type, Scope scope) {
// inside same unit - no report
if (scope.isDefinedInSameUnit(refType)) return false;

if (sinceValueUnreached(refType, scope)) return false;

// if context is deprecated, may avoid reporting
if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ public void generateImplicitLambda(BlockScope currentScope, CodeStream codeStrea
implicitLambda.setBody(arrayAllocationExpression);
} else {
AllocationExpression allocation = new AllocationExpression();
allocation.sourceStart = this.sourceStart;
allocation.sourceEnd = this.sourceEnd;
if (this.lhs instanceof TypeReference) {
allocation.type = (TypeReference) this.lhs;
} else if (this.lhs instanceof SingleNameReference) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,12 @@ public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageN
char[] answerModule = this.module != null ? this.module.name() : null;
if (jfo.getKind() == Kind.CLASS) {
ClassFileReader reader = readJavaClass(jfo, qualifiedBinaryFileName);
if (reader != null) {
return new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), answerModule);
}
// To avoid false compiler errors "package collides with type" on case insensitive file systems
// (e. g. Windows), make a case sensitive comparison of class name and type name from reader. The
// reader contains the CASE SENSITIVE type name.
return reader != null && className.equals(new String(reader.getName()))
? new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), answerModule)
: null;
} else {
if (this.initialJavaFileObjects != null && this.initialJavaFileObjects.contains(jfo))
return null; // refuse to re-add an initial file (possibly via a wrong module?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
// by index are tweaked to have their value in inst vars, this minor cost at read-time makes
// all subsequent uses of the constant pool element faster.
super(classFileBytes, null, 0);
if (classFileBytes == null || classFileBytes.length == 0) {
throw new ClassFormatException(ClassFormatException.ErrBadMagic);
}

this.classFileName = fileName;
int readOffset = 10;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,8 @@ private boolean addConstraintsToC_OneExpr(Expression expri, Set<ConstraintFormul
MethodBinding innerMethod = invocation.binding();
if (innerMethod == null)
return true; // -> proceed with no new C set elements.
if (innerMethod instanceof PolyParameterizedGenericMethodBinding poly && poly.hasOverloads)
return true; // don't let ambiguous inner method influence outer inference

Expression[] arguments = invocation.arguments();
TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

public class PolyParameterizedGenericMethodBinding extends ParameterizedGenericMethodBinding { // confused citizen.

public boolean hasOverloads;

private final ParameterizedGenericMethodBinding wrappedBinding;
public PolyParameterizedGenericMethodBinding(ParameterizedGenericMethodBinding applicableMethod) {
super(applicableMethod.originalMethod, applicableMethod.typeArguments, applicableMethod.environment, applicableMethod.inferredWithUncheckedConversion, false, applicableMethod.targetType);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
* Copyright (c) 2000, 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -38,14 +38,19 @@ public ProblemMethodBinding(char[] selector, TypeBinding[] args, ReferenceBindin
public ProblemMethodBinding(MethodBinding closestMatch, char[] selector, TypeBinding[] args, int problemReason) {
this(selector, args, problemReason);
this.closestMatch = closestMatch;
if (closestMatch != null && problemReason != ProblemReasons.Ambiguous) {
this.declaringClass = closestMatch.declaringClass;
this.returnType = closestMatch.returnType;
if (problemReason == ProblemReasons.InvocationTypeInferenceFailure || problemReason == ProblemReasons.ContradictoryNullAnnotations) {
this.thrownExceptions = closestMatch.thrownExceptions;
this.typeVariables = closestMatch.typeVariables;
this.modifiers = closestMatch.modifiers;
this.tagBits = closestMatch.tagBits;
if (problemReason == ProblemReasons.Ambiguous) {
if (closestMatch instanceof PolyParameterizedGenericMethodBinding poly)
poly.hasOverloads = true;
} else {
if (closestMatch != null) {
this.declaringClass = closestMatch.declaringClass;
this.returnType = closestMatch.returnType;
if (problemReason == ProblemReasons.InvocationTypeInferenceFailure || problemReason == ProblemReasons.ContradictoryNullAnnotations) {
this.thrownExceptions = closestMatch.thrownExceptions;
this.typeVariables = closestMatch.typeVariables;
this.modifiers = closestMatch.modifiers;
this.tagBits = closestMatch.tagBits;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,10 @@ public static boolean notEquals(TypeBinding that, TypeBinding other) {
return true;
if (that.id != TypeIds.NoId && that.id == other.id)
return false;
if (that instanceof LocalTypeBinding && other instanceof LocalTypeBinding) {
// while a lambda is being resolved, consider a local type as equal to its variant from another lambda copy
return ((LocalTypeBinding) that).sourceStart != ((LocalTypeBinding) other).sourceStart;
}
return true;
}
/** Return the primordial type from which the receiver was cloned. Not all types track a prototype, only {@link SourceTypeBinding},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2024 IBM Corporation and others.
* Copyright (c) 2000, 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -3477,6 +3477,9 @@ private boolean isAFieldDeclarationInRecord() {
continue;
nestingTypeAndMethod = this.recordNestedMethodLevels.get(node);
if (nestingTypeAndMethod != null) { // record declaration is done yet
if (nestingTypeAndMethod[0] != this.nestedType
|| nestingTypeAndMethod[1] != this.nestedMethod[this.nestedType])
return false;
recordIndex = i;
break;
}
Expand Down
Loading

0 comments on commit 6b031f2

Please sign in to comment.