gpt4 book ai didi

scala - 提取 Scala 项目的完整调用图(困难的一个)

转载 作者:行者123 更新时间:2023-12-03 11:02:29 25 4
gpt4 key购买 nike

我想从给定的 Scala 项目中提取所有方法的调用图,这些方法是项目自身源代码的一部分。

据我了解,演示编译器并没有启用它,它需要一直向下到实际的编译器(或编译器插件?)。

您能否建议完整的代码,它可以安全地适用于大多数 scala 项目,但那些使用最古怪的动态语言功能的项目?对于调用图,我的意思是包含 class/trait + method 的有向(可能是循环)图边 A -> B 表示 A 可以调用 B 的顶点。

应避免调用或从库调用或“标记”为项目自身源之外的调用。

编辑:

请参阅我的宏天堂衍生原型(prototype)解决方案,基于@dk14 的领导,作为下面的答案。托管在 github 上,地址为 https://github.com/matanster/sbt-example-paradise .

最佳答案

这是工作原型(prototype),它将必要的基础数据打印到控制台作为概念证明。 http://goo.gl/oeshdx .
这是如何工作的
我已经在 macro paradise 的顶部样板中改编了来自 @dk14 的概念.
Macro paradise允许您定义一个注释,将您的宏应用于源代码中的任何注释对象。从那里您可以访问编译器为源代码生成的 AST,并且可以使用 scala 反射 API 来探索 AST 元素的类型信息。 Quasiquotes(词源来自haskell或其他东西)用于匹配相关元素的AST。
更多关于准报价
通常需要注意的重要一点是,quasiquotes 在 AST 上工作,但它们是一个乍一看很奇怪的 api,而不是 AST 的直接表示(!)。 AST 由天堂的宏注释为您挑选,然后准引号是探索手头的 AST 的工具:您使用准引号匹配、切片和切 block 抽象语法树。
关于 quasiquotes 的实际需要注意的是,有固定的 quasiquote 模板用于匹配每种类型的 scala AST - 用于 scala 类定义的模板,用于 scala 方法定义的模板等。These tempaltes are all provided here ,使得将手头的 AST 与其有趣的成分匹配和解构变得非常简单。虽然这些模板乍一看可能令人望而生畏,但它们大多只是模仿 scala 语法的模板,您可以自由更改 $将它们中的变量名称添加到更符合您口味的名称中。
我仍然需要进一步磨练我使用的准引用匹配,这些匹配目前并不完美。但是,我的代码似乎在许多情况下都能产生所需的结果,并且将匹配精度提高到 95% 可能是可行的。
样本输出

found class B
class B has method doB
found object DefaultExpander
object DefaultExpander has method foo
object DefaultExpander has method apply
which calls Console on object scala of type package scala
which calls foo on object DefaultExpander.this of type object DefaultExpander
which calls <init> on object new A of type class A
which calls doA on object a of type class A
which calls <init> on object new B of type class B
which calls doB on object b of type class B
which calls mkString on object tags.map[String, Seq[String]](((tag: logTag) => "[".+(Util.getObjectName(tag)).+("]")))(collection.this.Seq.canBuildFrom[String]) of type trait Seq
which calls map on object tags of type trait Seq
which calls $plus on object "[".+(Util.getObjectName(tag)) of type class String
which calls $plus on object "[" of type class String
which calls getObjectName on object Util of type object Util
which calls canBuildFrom on object collection.this.Seq of type object Seq
which calls Seq on object collection.this of type package collection
.
.
.
很容易看出调用者和被调用者如何从这些数据中关联起来,以及如何过滤或标记项目源之外的调用目标。这就是 scala 2.11 的全部内容。使用此代码,需要为每个源文件中的每个类/对象/等添加注释。
剩下的挑战主要是:
剩下的挑战:
  • 完成工作后会崩溃。取决于https://github.com/scalamacros/paradise/issues/67
  • 需要找到一种方法最终将魔法应用于整个源文件,而无需使用静态注释手动注释每个类和对象。这在目前来说是相当小的,并且不可否认,能够控制类以包含和忽略无论如何都是有好处的。在(几乎)每个顶级源文件定义之前植入注释的预处理阶段将是一个不错的解决方案。
  • 磨练匹配器,以便匹配所有且仅相关的定义 - 使其超出我简单粗略的测试范围内的通用性和可靠性。

  • 思考的替代方法
    acyclic让我想起了一种完全相反的方法,它仍然坚持 scala 编译器的领域——它检查编译器为源生成的所有符号(就像我从源收集的一样多)。它的作用是检查循环引用(有关详细定义,请参见 repo)。每个符号都应该附有足够的信息,以得出 acyclic 的引用图。需要生成。
    如果可行,受此方法启发的解决方案可能会找到父 "owner" of every symbol而不是像非循环本身那样关注源文件连接图。因此,通过一些努力,它将恢复每个方法的类/对象所有权。不确定这种设计是否不会在计算上爆炸,也不知道如何确定性地获得包含每个符号的类。
    好处是这里不需要宏注释。不利的一面是,这不能像宏天堂那样轻易地允许使用运行时检测,这有时可能很有用。

    关于scala - 提取 Scala 项目的完整调用图(困难的一个),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29785439/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com