INRIA / INRIA/spoon

[Bug]: `CtVariableRead` has wrong type when a formal type parameter is set to a concrete type (`T = Integer`)

Open
#5,414 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Java
Stars
2k
Forks
392
Avg merge
11h 24m
Merged PRs (30d)
36

Description

### Describe the bug

Given the below code, two problems occur:
1. The type of the variable read should be `Integer` and not `T`
2. If one were to assume that `T` is the correct type, the code crashes when calling `isSubtypeOf`, because the `declaringType` is not set

### Source code you are trying to analyze/transform

```Java
class Command {
protected final T value;

protected Command(T value) {
this.value = value;
}
}

class ResultsInCrash extends Command {
ResultsInCrash(Integer value) {
super(value);
}

public String execute() {
return value.toString();
}
}
```

### Source code for your Spoon processing

```Java
import org.junit.jupiter.api.Test;
import spoon.Launcher;
import spoon.reflect.CtModel;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtNewArray;
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtVariableRead;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.reference.CtArrayTypeReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.support.compiler.VirtualFile;

import static org.junit.jupiter.api.Assertions.*;

class TestSpoon {
@Test
void testFormalTypeParameterType() {
CtClass ctClass = Launcher.parseClass(
"public class Example {\n" +
" class Command {\n" +
" protected final T value;\n" +
"\n" +
" protected Command(T value) {\n" +
" this.value = value;\n" +
" }\n" +
" }\n" +
"\n" +
" class ResultsInCrash extends Command {\n" +
" ResultsInCrash(Integer value) {\n" +
" super(value);\n" +
" }\n" +
"\n" +
" public String execute() {\n" +
" return value.toString();\n" +
" }\n" +
" }\n" +
"}\n"
);

CtMethod execute = ctClass.getNestedType("ResultsInCrash").getMethod("execute");
CtReturn ctReturn = execute.getBody().getLastStatement();

// the `value.toString()` expression:
CtInvocation ctInvocation = (CtInvocation) ctReturn.getReturnedExpression();
CtVariableRead ctVariableRead = (CtVariableRead) ctInvocation.getTarget();

assertEquals(ctVariableRead.getFactory().Type().INTEGER, ctVariableRead.getType());
}
}
```

### Actual output

```Java
org.opentest4j.AssertionFailedError:
Expected :Integer
Actual :T

at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1142)
at org.example.playground.TestSpoon.testFormalTypeParameterType(TestSpoon.java:84)
....
```

### Expected output

_No response_

### Spoon Version

10.4.0

### JVM Version

openjdk version "17.0.1" 2021-10-19 OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)

### What operating system are you using?

Windows 10

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.