M3 Java: 如何检查 class 是否从接口实现了一个函数

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

我正在尝试编写一个分析来检查 class 是否实现了 Comparable.compareTo |java+method:///java/lang/Comparable/compareTo(T)|.

我试过 M3.methodOverrides,在某些情况下它有效。但是对于下面的代码,methodOverrides 根本不包含 compareTo。

//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...";
    }

}

使用 createM3FromDirectory 加载这些文件时,M3.methodOverrides 仅包含一个条目:

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

有没有办法对 M3 中的某些关系采取一些传递闭包来得出结论 |java+method:///Circle/compareTo(Geometric)| 覆盖 |java+method:///java/lang/Comparable/compareTo(T)|?

目前,M3 仅存储与直接超类和接口相关的方法覆盖。如果在您的项目中声明了传递接口和超类型,您可以使用 implementsextends 关系的传递闭包,然后对照 declarations 和 [=13= 交叉检查结果] 关系。但是,您需要注意,在外部依赖项(例如 Comparable<T>)的情况下,您的 M3 中不会包含所有需要的信息。因此,这不是解决所有情况的通用解决方法。如果您仍想检查项目实体的方法覆盖,请考虑以下步骤(这只是一种可能的解决方案):

  1. 计算 implements 关系的传递闭包。
  2. 计算 extends 关系的传递闭包。
  3. 根据您正在检查的类型订阅这两个关系并聚合这两个集合(即 transImpl[|java+class://main/MyClass|] + transExt[|java+class://main/MyClass|])。
  4. 考虑 containment 关系中与 MyClass 类型及其传递父类型相关的方法。
  5. MyClass 方法的签名与传递父类型方法进行比较(注意每个方法的可见性;仅应考虑 protectedpublic 方法)。

无论如何,我们在 Rascal 存储库中打开了一个新的 issue 以进一步分析您的查询。感谢您报告。

我简直不敢相信自己的眼睛。我刚刚又试了一次,现在可以了。

//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); }
}

eclipse rascal 控制台内部:

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)|>

就是这样:Circle 实际上实现了 Comparable.compareTo。 <|java+method:///Circle/compareTo(Geometric)|,|java+method:///java/lang/Comparable/compareTo(T)|>

我认为问题在于我使用了两个不同版本的 rascal。 Rascal shell,似乎是旧版本,给出不同的结果。

使用流氓-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()|>

我想我只是运行流氓-shell。当 运行 来自 eclipse 内部时,它会给出正确的结果。

就我而言,它按预期工作。

P.S。我明白M3只记录即时事实,需要时我必须自己计算传递闭包。