ClangAST基础


前言

有一说一看这个项目没咋看懂,clang很多api非常奇妙,所以在这里记录一下一些基本的东西

clang::ASTConsumer

对自定义AST处理的统一接口

clang::ASTConsumer 定义了一个纯虚函数 HandleTranslationUnit,用于处理整个翻译单元(Translation Unit)的 AST。在此函数中,可以通过遍历 AST 来执行各种操作,例如查找特定的语法结构、进行静态分析、进行代码转换等。

项目里六中变异类型就是六个继承了clang::ASTConsumer的类,格式都差不多

class VarUseSemantic : public CustomASTConsumer {
public:
  explicit VarUseSemantic(
      std::vector<std::function<void(clang::Rewriter &)>> &all);

  void HandleTranslationUnit(clang::ASTContext &Context) override;

  std::string name() const override;
};

MatchFinder::MatchCallback

处理AST匹配结果的类,当中的run函数可以被视为回调函数

MatchFinder::MatchCallback 类定义了一个纯虚函数 run,用于执行与匹配结果相关的操作。每当匹配器匹配到一个符合条件的 AST 节点时,就会调用对应 MatchCallback 对象的 run 函数,并将匹配结果传递给它。run 函数则可以根据匹配结果进行相应的处理,例如修改节点、输出信息等。

所以我们错误类型类的格式基本都是这样的:

//首先是namespace,存放这个类的描述
namespace {
//两个常量,描述和id
const string desc =
    "This bug is a syntax error caused by incomplete brackets in the code";
const string id = "parentheses";
//callback类,存放对应run方法
class ParenCallback : public MatchFinder::MatchCallback {
public:
	//
};

} 

ParenSyntax::ParenSyntax(vector<function<void(Rewriter &)>> &all) {
	//构造函数,实例化一个存放返回值类型为void,参数为Rewriter引用的函数,的,vector的引用,名字叫all
}

void ParenSyntax::HandleTranslationUnit(clang::ASTContext &context) {
  finder.matchAST(context);//这个都一样
}

string ParenSyntax::name() const { return "ParenSyntax"; }//名字

MatchFinder::MatchResult

存放匹配到的AST节点的相关信息

在 AST Matchers 中,当匹配器匹配到符合条件的节点时,会调用相应的回调函数(即 MatchCallback 对象)并将匹配结果传递给它。这个匹配结果就是一个 MatchResult 对象,包含了匹配到的节点、源码位置等信息。

项目里的用1

result.Nodes.getNodeAs<Stmt>(id);

result.Nodes:存储了所有通过匹配规则成功匹配到的节点

getNodeAs<Stmt>(id):获取名称为id的节点,并且视为Stmt类型。Stmt(Statement)代表了语句,是语法树中的一个重要节点。Stmt 可以是任何有效的 C++ 语句,比如赋值语句、函数调用、条件语句等。

当然还会有别的类型,比如

result.Nodes.getNodeAs<ForStmt>(id);//for语句
const DeclRefExpr *bo = result.Nodes.getNodeAs<DeclRefExpr>(id);//变量或者函数声明

项目里的用法2

const SourceManager *sm = result.SourceManager;

SourceManager 负责管理源码文件的位置信息,包括文件名、行号、列号等。在 AST Matchers 中,可以使用 SourceManager 来获取匹配节点的源码位置信息,比如获取节点所在文件、行号、列号等。

StatementMatcher

StatementMatcher 是 Clang AST Matchers 提供的一种匹配模式,用于匹配语句(statements)的模式。它允许你定义特定的语法结构或语句模式,并在 AST 中查找匹配这些模式的语句。

我们通过这个来寻找我们想要找到的格式并对他们赋予自定义的id

比如

StatementMatcher m = forStmt(isExpansionInMainFile()).bind(id);

创建了一个 StatementMatcher 对象 m,用于匹配位于主文件中的 for 循环语句,并将匹配到的语句绑定到名称为 id 的变量上。

dyn_cast

dyn_cast 是 Clang AST 中的一个工具函数,用于安全地将 AST 节点指针转换为指定的派生类指针。它会在运行时检查指针指向的对象是否实际上是目标类型或其派生类的实例。如果是,则返回转换后的指针;如果不是,则返回空指针。

用法:

const CallExpr *callExpr = dyn_cast<CallExpr>(bo)//将普通语句类型(bo)转为函数调用类型
const NamedDecl *nd = dyn_cast<NamedDecl>(bo->getDecl());//将声明类型转换为名称类型

Lexer

词法分析器(lexer)用于将源代码转换为标记(tokens)序列。标记是编程语言中的基本单元,例如关键字、标识符、操作符、常量等。词法分析器扫描源代码,并将其分解为标记序列,以便进一步的语法分析或处理。

LexFromRawLexer

LexFromRawLexerLexer 类的一个成员函数,用于从原始字符流中解析下一个 token,并将其存储在提供的 Token 对象中。这个函数从给定的位置开始向前解析字符,识别并返回下一个 token。

bo的一些方法

  • getDecl()//得到变量声明的指针

  目录