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

[Bug]: VariableAccessFilter does not find all accesses of a generic variable #5391

Closed
Luro02 opened this issue Aug 24, 2023 · 1 comment
Closed
Labels

Comments

@Luro02
Copy link
Contributor

Luro02 commented Aug 24, 2023

Describe the bug

The VariableAccessFilter should match all accesses to a variable:

This simple filter matches all the accesses to a given field.

(from the docs)

This is not the case for the below code. The implementation looks like this:

boolean matches(CtVariableAccess<?> ctVariableAccess) {
     return ctVariableAccess.getVariable().equals(this.variableReference);
}

In the below code, this.variableReference is a reference to T field and ctVariableAccess would be a reference to String field. That is why even though they access the same field, they do not match.

A potential fix for this would be to check if they are refering to the same field:

record BetterVariableAccessFilter<T extends CtVariableAccess<?>>(CtVariable<?> ctVariable) implements Filter<T> {
    @Override
    public boolean matches(T element) {
        return element.getVariable().equals(this.ctVariable.getReference())
            || (element.getVariable().getDeclaration() != null && element.getVariable().getDeclaration().equals(this.ctVariable));
    }
}

Source code you are trying to analyze/transform

public class Example<T> {
    T field;

    public static void main(String[] args) {
        Example<String> example = new Example<>();

        example.field = "Hello"; // write access to Example#field
        System.out.println(example.field); // read access to Example#field
    }
}

Source code for your Spoon processing

import org.junit.jupiter.api.Test;
import spoon.Launcher;
import spoon.reflect.code.CtVariableAccess;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.visitor.filter.VariableAccessFilter;

import java.util.List;

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

class TestVariableAccessFilter {
    @Test
    void testGenericFieldAccess() {
        CtClass<?> ctClass = Launcher.parseClass("""
            public class Example<T> {
                T field;

                public static void main(String[] args) {
                    Example<String> example = new Example<>();
                    
                    example.field = "Hello"; // write access to Example#field
                    System.out.println(example.field); // read access to Example#field
                }
            }
            """);

        List<CtVariableAccess<?>> accesses = ctClass.getElements(
            new VariableAccessFilter<>(ctClass.getField("field").getReference())
        );

        assertEquals(2, accesses.size());
    }
}

Actual output

org.opentest4j.AssertionFailedError: 
Expected :2
Actual   :0
<Click to see difference>

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

@Luro02 Luro02 added the bug label Aug 24, 2023
@MartinWitt
Copy link
Collaborator

Looks reasonable, can you make a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants