Skip to content

Commit

Permalink
Merge branch 'eclipse-jdt:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
carstenartur authored Jan 14, 2025
2 parents 75b5d51 + 7ddead3 commit 3f3d4c5
Show file tree
Hide file tree
Showing 53 changed files with 1,353 additions and 1,132 deletions.

This file was deleted.

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 @@ -2526,9 +2526,8 @@ public interface IProblem {
*/
int PatternVariableRedefined = Internal + 1781;
/** @since 3.26
* @deprecated
*/
int PatternSubtypeOfExpression = Internal + 1782;
int PatternSubtypeOfExpression = Internal + 1782; // ass backwards naming of API constant :-( It should read ExpressionSubtypeOfPattern
/** @since 3.26
*/
int IllegalModifierForPatternVariable = Internal + 1783;
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 @@ -277,15 +277,16 @@ public TypeBinding resolveType(BlockScope scope) {
if (expressionType == null || checkedType == null)
return null;

CompilerOptions options = scope.compilerOptions();
if (this.pattern != null) {
if (this.pattern.isApplicable(expressionType, scope, this)) {
if (this.pattern.isApplicable(expressionType, scope, this))
checkForPrimitives(scope, checkedType, expressionType);
}
if (options.complianceLevel < ClassFileConstants.JDK21 && expressionType.isSubtypeOf(checkedType, false))
scope.problemReporter().expressionTypeCannotBeSubtypeOfPatternType(this.expression);
return this.resolvedType = TypeBinding.BOOLEAN;
}

if (!checkedType.isReifiable()) {
CompilerOptions options = scope.compilerOptions();
// Report same as before for older compliances
if (options.complianceLevel < ClassFileConstants.JDK16) {
scope.problemReporter().illegalInstanceOfGenericType(checkedType, this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,8 @@ public void resolve(BlockScope upperScope) {
// special scope for secret locals optimization.
this.scope = new BlockScope(upperScope);

if (enclosingSwitchExpression(upperScope) instanceof SwitchExpression swich) {
SwitchExpression swich;
if ((swich = enclosingSwitchExpression(upperScope)) != null) {
swich.jvmStackVolatile = true; // ought to prepare for any raised exception blowing up the the operand stack to smithereens
}
BlockScope finallyScope = null;
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 @@ -434,7 +434,17 @@ public MethodBinding[] availableMethods() {
return availableMethods;
}

void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
final void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
try {
cachePartsFrom2(binaryType, needFieldsAndMethods);
} catch (AbortCompilation e) {
throw e;
} catch (RuntimeException e) {
throw new RuntimeException("RuntimeException loading " + new String(binaryType.getFileName()), e); //$NON-NLS-1$
}
}

private void cachePartsFrom2(IBinaryType binaryType, boolean needFieldsAndMethods) {
if (!isPrototype()) throw new IllegalStateException();
ReferenceBinding previousRequester = this.environment.requestingType;
this.environment.requestingType = this;
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 @@ -728,7 +728,8 @@ public boolean isRecord() {
}

public boolean isRecordWithComponents() { // do records without components make sense ??!
return isRecord() && components() instanceof RecordComponentBinding [] components && components.length > 0;
RecordComponentBinding [] components;
return isRecord() && (components = components()) != null && components.length > 0;
}

/* Answer true if the receiver type can be assigned to the argument type (right)
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 3f3d4c5

Please sign in to comment.