eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
158 stars 126 forks source link

"Regression" in 3.39.0 #3064

Open I-Al-Istannen opened 4 hours ago

I-Al-Istannen commented 4 hours ago

Hey,

feel free to close this issue if it is too ludicrous :D It is a bit of a long shot, but I find the behaviour a bit odd. Consider the following code (this is all JDT gets):

public class Action<Request extends BroadcastRequest<Request>, ShardRequest> {
    private final Request request;

    protected ShardRequest newShardRequest(Request request) {return null;} // can also be omitted

    protected void performOperation(final int shardIndex) {
        ShardRequest shardRequest = newShardRequest(request);
        shardRequest.setParentTask(foobar);
    }
}

There are a few things to consider here, namely:

In 3.38.0 and older versions of JDT, JDT was able to associate the receiver of the shardRequest.setParentTask MessageSend with the shardRequest variable (notice the binding there):

grafik

In 3.39.0 JDT instead produces the following (notice there no longer is a binding):

grafik

It is a bit weird that JDT is no longer able to associate the method call with the variable defined above it. Is this something you are willing to look at or fix? Everything works correctly when all dependencies exist and JDT can resolve the correct methods. It only breaks with an incomplete classpath.


This is a reduction from https://github.com/INRIA/spoon/pull/5977, but we would also be fine with adjusting the test.

iloveeclipse commented 4 hours ago

Could you please provide a simple self contained test showing the problem?

I-Al-Istannen commented 4 hours ago

Am I allowed to show a 3 line spoon program or do I have to peel out the relatively complicated JDT scaffolding? The relevant breakpoint would be spoon/support/compiler/jdt/JDTTreeBuilder.java:1443. The assertions are mostly flavour, it is how the problem manifests itself in spoon. But the JDT part is already done by the line above in JDTTreeBuilder.

import org.junit.jupiter.api.Test;
import spoon.Launcher;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtTypeParameterReference;
import spoon.reflect.visitor.filter.TypeFilter;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;

public class Test {

    @Test
    public void testMWE() {
        CtClass<?> ctClass = Launcher.parseClass("""
            public class Action<Request extends BroadcastRequest<Request>, ShardRequest> {
                private final Request request;

                protected ShardRequest newShardRequest(Request request) {return null;} // can also be omitted

                protected void performOperation(final int shardIndex) {
                    ShardRequest shardRequest = newShardRequest(request);
                    shardRequest.setParentTask(foobar);
                }
            }
            """);
        for (var ref : ctClass.getElements(new TypeFilter<>(CtExecutableReference.class))) {
            if(ref.getSimpleName().equals("setParentTask")) {
                var typeRef = ref.getDeclaringType();
                assertInstanceOf(CtTypeParameterReference.class, typeRef);
                assertEquals("ShardRequest", typeRef.getSimpleName());
            }
        }
    }
}
iloveeclipse commented 3 hours ago

Ideally it would be self contained test that uses no extra dependencies except JDT and JUnit :) This would increase a chance that this bug would be investigated & fixed.

I-Al-Istannen commented 3 hours ago

Then I am out, I think. There is not really a chance I can rebuild the scaffolding for extracting JDTs internal API in a readable test case (and I have absolutely zero clue how it works).

ETA: (Yes, I tried to do that for the last 40 minutes and failed miserably)