24

是否有 JavaScript 的调用图和/或控制流图生成器?

调用图 - http://en.wikipedia.org/wiki/Call_graph

控制流图 - http://en.wikipedia.org/wiki/Control_flow_graph

编辑:我正在寻找一个静态工具,让我可以使用一些 API/代码访问图表

4

8 回答 8

11

为此,您需要:

  • 解析,
  • 名称解析(处理范围)
  • 类型分析(虽然 JavaScript 可以说是“动态类型的”,但有各种类型的常量,包括这里特别感兴趣的函数常量)
  • 控制流分析(在方法中建立控制流图的结构)
  • 数据流分析(跟踪这些类型的生成/使用位置)
  • 什么相当于全局指向分析(跟踪函数之间作为值传递到应用点的函数常量)。

如何做到这一点在编译器文献中有很好的记录。然而,实现这件事情需要大量的汗水,所以“你可以使用解析器结果来获得你想要的东西”形式的答案却没有抓住重点。

如果您可以应用所有这些机制,您将得到的实际结果是一个保守的答案,例如,“A 可能会调用 B”。这就是你所知道的一切,考虑一下

 void A(int x,y) { if (x>y) foo.B(); }

因为工具有时根本无法推理复杂的逻辑,所以即使应用程序设计人员知道这是不可能的,您也可能会得到“A 可能调用 B”:

 void A(int x) // programmer asserts x<4
   { if (x>5) foo.B(); }

eval使问题变得更糟,因为您需要跟踪到达 eval 命令的字符串值结果并解析它们以获得某种线索,以了解正在评估的代码以及 eval'd 代码可能调用的函数。如果有人将字符串中的“eval”传递给 eval,事情会变得非常糟糕:-{ 您还可能需要对程序执行上下文进行建模;我怀疑有很多包含回调的浏览器 API。

如果有人为您提供工具,该工具具有完全配置的所有必要机器,可以开箱即用地解决您的问题,那显然很棒。我怀疑你不会得到这样的提议,因为这样的工具不存在。原因是所需的所有基础设施;它很难构建,几乎没有人可以证明它只是一种工具。即使是“优化 JavaScript 编译器”,如果你能找到一个可能不会拥有所有这些机制,尤其是全局分析,并且它所拥有的内容不太可能以易于使用的形式打包为您的目的。

自从我 1969 年开始编程以来,我一直在努力解决这个问题(当时我的一些程序是编译器,我想要所有这些东西)。实现这一目标的唯一方法是将所有这些机器的成本分摊到许多工具上。

我的公司提供DMS Software Reengineering Toolkit,这是一个通用编译器分析和转换机器包,具有各种工业级计算机语言前端(包括 C、C++、COBOL 和 JavaScript)。DMS 提供 API 以支持在其通用基础上构建自定义工具。

消息顶部列出的通用机制都存在于 DMS 中,包括可通过干净的文档化 API 获得的控制流图和数据流分析。该流程分析必须与特定的语言前端相关联。这也需要一些工作,所以我们还没有为所有语言完成它。我们已经为 C [在 18,000 个编译单元的系统上作为一个整体进行了测试,包括计算现有 250,000 个函数的调用图,包括间接函数调用!]、COBOL 和 Java,我们正在研究 C++。

DMS 与该线程中的其他答案具有相同的“JavaScript”解析器答案,并且从这个角度来看,DMS 并不比其他“在解析器之上构建它”的答案更好。区别应该很清楚:机器已经存在于 DMS 中,因此工作不是实现机器并绑定到解析器;它只是将它绑定到解析器。这仍然需要一些工作,但比从解析器开始要少得多。

于 2011-04-01T22:53:52.180 回答
5

一般来说,这是不可能做到的。原因是函数是一流的并且是动态类型的,例如:

var xs = some_function();
var each = another_function();
xs.map(each);

有两个未知数。一个是调用的'map'版本(因为一般情况下Javascript多态性不能静态解析),另一个是分配给'each'的值,同样不能静态解析。这段代码唯一的静态属性是在我们从“another_function”获得的某个函数上调用了一些“map”方法。

但是,如果这些信息足够多,那么有两个资源可能会有所帮助。一个是通用的 Javascript 解析器,特别是使用解析器组合器构建的(Chris Double 的 jsparse 是一个很好的)。这将允许您在构建解析树时对其进行注释,并且您可以将自定义规则添加到调用节点以记录图形边缘。

您可能会发现有用的另一个工具(无耻插件)是我编写的一个 Javascript 到 Javascript 编译器,称为 Caterwaul。它使您可以对语法树进行模式匹配,并知道如何遍历它们,这在您的情况下可能很有用。如果您想从短期执行中构建动态跟踪,它也会有所帮助(如果您想要准确和详细的结果,这可能是您的最佳选择)。

于 2011-03-29T20:50:04.237 回答
5

WALA 是一个开源程序分析框架,可以为 JavaScript 构建静态调用图和控制流图:

http://wala.sourceforge.net/wiki/index.php/Main_Page

一个警告是,在存在 、 和其他难以分析的结构时,调用图可能会丢失一些evalwith。此外,我们仍在致力于可扩展性;WALA 还不能在合理的时间内分析 jquery,但可以分析其他一些框架。此外,我们用于构建 JavaScript 调用图的文档目前也不是很好(改进它在我的 TODO 列表中)。

我们正在积极处理此代码,因此如果您尝试并遇到问题,您可以通过电子邮件发送 WALA 邮件列表 ( https://lists.sourceforge.net/lists/listinfo/wala-wala ) 或联系我。

于 2012-03-17T02:26:34.453 回答
2

以下是我可以看到的一些解决方案:

  1. 使用 Aptana调用图视图
    Aptana 是一个基于 Eclipse 的 IDE,允许您编辑和调试 Javascript 代码。

  2. 使用Dynatrace
    Dynatrace 是一个有用的工具,可让您实时跟踪代码并查看调用图和热点。

  3. 使用Firebug
    火狐上著名的开发者插件

此处生成的大多数调用图都是动态的,即您将看到给定操作集的调用图。如果您正在寻找静态调用图,请先检查 Aptana。静态调用图可能不会让您看到动态调用(通过 eval() 运行的代码)。

于 2011-03-25T11:19:31.693 回答
2

我认为http://doctorjs.org/可能适合您的需求。它有一个很好的 JSON API,在 github 上可用,由 mozilla 支持。它是用 JS 本身编写的,并且通常做得很好(包括处理多态性等)。

于 2011-04-02T02:04:49.157 回答
1

对于 js 方法,请查看arguments.callee.caller. 它为您提供调用您所在函数的函数,您可以递归调用堆栈。此线程中有一个示例http://bytes.com/topic/javascript/answers/470251-recursive-functions-arguments-callee-caller

请注意,这可能不适用于所有浏览器,当您到达“调用堆栈”或本机函数的顶部时,您可能会遇到一些意想不到的事情,因此使用风险自负。

我自己的示例适用于 IE9 和 Chrome 10(未测试任何其他浏览器)。

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body onload="Function1()">
<form id="form1" runat="server">
<div>

</div>
</form>
</body>

<script type="text/javascript">

function Function1()
{
    Function2();
}

function Function2()
{
Function3();
}
function Function3()
{
Function4();
}
function Function4()
{
    var caller = arguments.callee.caller;
    var stack = [];
    while (caller != null)
    {
        stack.push(caller);//this is the text of the function.  You can probably write some code to parse out the name and parameters.
        var args = caller.arguments; //this is the arguments for that function.  You can get the actual values here and do something with them if you want.
        caller = caller.caller;
    }
    alert(stack);
}


</script>
</html>
于 2011-03-29T14:26:18.407 回答
0

最接近调用图的方法是操作完整的 Javascript AST。Rhino 可以做到这一点,看看这篇文章:http ://tagneto.blogspot.com/2010/03/requirejs-kicking-some-ast.html

帖子中的示例:

//Set up shortcut to long Java package name,
//and create a Compiler instance.
var jscomp = Packages.com.google.javascript.jscomp,
  compiler = new jscomp.Compiler(),

  //The parse method returns an AST.
  //astRoot is a kind of Node for the AST.
  //Comments are not present as nodes in the AST.
  astRoot = compiler.parse(jsSourceFile),
  node = astRoot.getChildAtIndex(0);

//Use Node methods to get child nodes, and their types.
if (node.getChildAtIndex(1).getFirstChild().getType() === CALL) {
  //Convert this call node and its children to JS source.
  //This generated source does not have comments and
  //may not be space-formatted exactly the same as the input
  //source
  var codeBuilder = new jscomp.Compiler.CodeBuilder();
  compiler.toSource(codeBuilder, 1, node);

  //Return the JavaScript source.
  //Need to use String() to convert the Java String
  //to a JavaScript String.
  return String(codeBuilder.toString());
}

在 Javascript 或 Java 中,您可以通过 AST 构建您想要的任何类型的调用图或依赖链。

于 2011-03-31T17:58:12.977 回答
0

与 NodeJS 没有直接关系,但通常与 JavaScript 相关,SAP 发布了一个与 HANA 相关的 Web IDE(但也可以从 HANA 云免费访问 - 在这里查看更多详细信息http://scn.sap.com/community/developer-center/云平台/博客/2014/04/15/sap-hana-web-ide-online-tutorial)。

在这个 Web IDE 中,有一个基于 REST 的服务来分析 JavaScript 内容,主要关注(但不仅是)创建调用图。该服务有很多消费者,例如代码导航。

这里有更多信息(参见功能流程部分): http ://scn.sap.com/community/developer-center/hana/blog/2014/12/02/sap-hana-sps-09-new-developer-功能-sap-hana-web-based-development-workbench

注意:我是该服务的主要开发者。

于 2014-12-19T14:55:43.487 回答