Search code examples
rascal

M3 Java: How to check that a class implements a function from an interface


I'm trying to write an analysis that checks that a class implements Comparable.compareTo |java+method:///java/lang/Comparable/compareTo(T)|.

I tried playing with M3.methodOverrides, and in some cases it works. But with the code below, methodOverrides does not contain compareTo at all.

//Geometric.java
public interface Geometric extends Comparable<Geometric> {
    public double area();
}
//Circle.java
public class Circle implements Geometric {

    private double r;
    private double x;
    private double y;

    public Circle(double x, double y, double r) {
        this.x = x;
        this.y = y;
        this.r = r;
    }

    @Override
    public double area() {
        return Math.PI * Math.pow(r, 2);
    }

    @Override
    public int compareTo(Geometric o) {
        return (int) (area() - o.area());
    }

    @Override
    public String toString() {
        return "Circle...";
    }

}

When loading these files using createM3FromDirectory, M3.methodOverrides contains only a single entry:

<|java+method:///Circle/area()|,|java+method:///Geometric/area()|>

Is there a way to take some transitive closures of some relations in M3 to conclude that |java+method:///Circle/compareTo(Geometric)| overrides |java+method:///java/lang/Comparable/compareTo(T)|?


Solution

  • I can't believe my eyes. I just tried it again, and now it works.

    //Main.rsc
    module Main
    
    import IO;
    import lang::java::m3::Core;
    
    void main(list[str] args)
    {
        loc projectDir = |file:///| + args[0];
        M3 model = createM3FromDirectory(projectDir);
    
        for( ov <- model.methodOverrides ) { println(ov); }
    }
    

    Inside eclipse rascal console:

    rascal>main(["/home/mkl/radboud/src/java-feedback/java-feedback-rascal/test-data/assignment03-override-not-detected"]);
    Reloading module Main
    <|java+method:///Circle/toString()|,|java+method:///java/lang/Object/toString()|>
    <|java+method:///Circle/area()|,|java+method:///Geometric/area()|>
    <|java+method:///Circle/compareTo(Geometric)|,|java+method:///java/lang/Comparable/compareTo(T)|>
    

    There it is: Circle actually implements Comparable.compareTo. <|java+method:///Circle/compareTo(Geometric)|,|java+method:///java/lang/Comparable/compareTo(T)|>

    I think the problem was that I'm using two different versions of rascal. Rascal shell, which seems to be an older version, gives different results.

    Using rascal-shell:

    $ java -Xmx1G -Xss32m -jar ~/tmp/rascal-shell-stable.jar Main.rsc /home/mkl/radboud/src/java-feedback/java-feedback-rascal/test-data/assignment03-override-not-detected
    Version: unknown
    <|java+method:///Circle/area()|,|java+method:///Geometric/area()|>
    

    I think I was only running rascal-shell. When running from inside eclipse, it gives the correct results.

    As far as I'm concerned it works as expected.

    P.S. I understand that M3 only records immediate facts, and that I have to calculate transitive closures myself when needed.