使用 clang llvm 检查变量在任意源位置的作用域是否具有范围



我是 clang libtool 的新手,正在努力解决以下问题。

我想对给定的c/c ++程序执行源到源的转换,以便"转换"程序在不同程序点打印所有"范围内"变量值。

例如,在下面的程序中,我想打印范围位于各种 SourceLocation 的变量值(例如,在编号为 8 和 10 的行尾)。 为此,我需要知道变量 c 在第 8 行末尾没有作用域,同样变量 i 和 c 在第 10 行末尾没有作用域。

是否有任何 API 可以帮助查找变量在给定的源位置是否具有范围?如何检查变量是否在程序中的特定源位置具有作用域?

 1:void f(){
 2:    int a=10;
 3:    for(int i=0; i<10;i++){
 4:        if(a>10){
 5:            int b = a+20;
 6:            {
 7:                int c = b+10;
 8:            }
 9:        }
10:    }
11:}

转换后的程序(对于此示例)将如下所示:

 1:void f(){
 2:    int a=10;
 3:    for(int i=0; i<10;i++){
 4:        if(a>10){
 5:            int b = a+20;
 6:            {
 7:                int c = b+10;
 8:            };printf("%d %d %dn", a, b, i);
 9:        }
10:    };printf("%dn", a);
11:}

我想过实现它,但是像 clang 这样的大工具应该已经实现了这个 API!! 或者应该有一些有效/简单的方法来做到这一点。

使用clang-libtooling执行此操作的最佳策略是什么?

谢谢。

Clang提供了一个名为AST Matcher(参考)的API。

使用 clang -Xclang -ast-dump -fsyntax-only test.c 编译代码会转储 AST。

`-FunctionDecl 0x3b0a750 <test_ast.cpp:1:1, line:9:1> line:1:6 f 'void (void)'
  `-CompoundStmt 0x3b51958 <col:10, line:9:1>
    |-DeclStmt 0x3b0a8c8 <line:2:3, col:13>
    | `-VarDecl 0x3b0a848 <col:3, col:11> col:7 used a 'int' cinit
    |   `-IntegerLiteral 0x3b0a8a8 <col:11> 'int' 10
    `-ForStmt 0x3b51920 <line:3:3, line:8:3>
      |-DeclStmt 0x3b0a970 <line:3:8, col:17>
      | `-VarDecl 0x3b0a8f0 <col:8, col:16> col:12 used i 'int' cinit
      |   `-IntegerLiteral 0x3b0a950 <col:16> 'int' 0
      |-<<<NULL>>>
      |-BinaryOperator 0x3b0a9e8 <col:19, col:23> '_Bool' '<'
      | |-ImplicitCastExpr 0x3b0a9d0 <col:19> 'int' <LValueToRValue>
      | | `-DeclRefExpr 0x3b0a988 <col:19> 'int' lvalue Var 0x3b0a8f0 'i' 'int'
      | `-IntegerLiteral 0x3b0a9b0 <col:23> 'int' 10
      |-UnaryOperator 0x3b0aa38 <col:27, col:28> 'int' postfix '++'
      | `-DeclRefExpr 0x3b0aa10 <col:27> 'int' lvalue Var 0x3b0a8f0 'i' 'int'
      `-CompoundStmt 0x3b51900 <col:32, line:8:3>
        `-IfStmt 0x3b518d0 <line:4:5, line:7:5>
          |-<<<NULL>>>
          |-BinaryOperator 0x3b51640 <line:4:9, col:13> '_Bool' '>'
          | |-ImplicitCastExpr 0x3b51628 <col:9> 'int' <LValueToRValue>
          | | `-DeclRefExpr 0x3b515e0 <col:9> 'int' lvalue Var 0x3b0a848 'a' 'int'
          | `-IntegerLiteral 0x3b51608 <col:13> 'int' 10
          |-CompoundStmt 0x3b518a8 <col:17, line:7:5>
          | |-DeclStmt 0x3b51760 <line:5:7, col:21>
          | | `-VarDecl 0x3b51678 <col:7, col:19> col:11 used b 'int' cinit
          | |   `-BinaryOperator 0x3b51738 <col:15, col:19> 'int' '+'
          | |     |-ImplicitCastExpr 0x3b51720 <col:15> 'int' <LValueToRValue>
          | |     | `-DeclRefExpr 0x3b516d8 <col:15> 'int' lvalue Var 0x3b0a848 'a' 'int'
          | |     `-IntegerLiteral 0x3b51700 <col:19> 'int' 20
          | `-CompoundStmt 0x3b51888 <line:6:7, col:25>
          |   `-DeclStmt 0x3b51870 <col:9, col:23>
          |     `-VarDecl 0x3b51788 <col:9, col:21> col:13 c 'int' cinit
          |       `-BinaryOperator 0x3b51848 <col:17, col:21> 'int' '+'
          |         |-ImplicitCastExpr 0x3b51830 <col:17> 'int' <LValueToRValue>
          |         | `-DeclRefExpr 0x3b517e8 <col:17> 'int' lvalue Var 0x3b51678 'b' 'int'
          |         `-IntegerLiteral 0x3b51810 <col:21> 'int' 10
          `-<<<NULL>>>

您可以使用 AST 匹配器遍历 AST 并与CompoundStmt匹配,这将为你提供与 C/C++ 中的作用域对应的 AST 节点。从这里,您可以开始跟踪所有VarDecl以查找作用域内的变量声明。对于您想要的东西,没有开箱即用的解决方案,但 Clang 为您提供了实现它的工具。

你也可以阅读Eli Bendersky的这篇博文(链接)。他演示了如何使用 AST Matchers 和 Clang 的重写工具来编写您想要的工具。

最新更新