我正在访问以下代码的 AST:
int x = 123;
在
VisitVarDecl( VarDecl *d )
中,我想要整个表达式的源范围。我期待一些直观的东西,如 d->print()
打印:int x = 123
。
d->getSourceRange()
以“1”结尾。也就是说,它仅由类型组成(请参阅 clang 源代码)。
如果我想要整个事情,我需要做类似的事情:
auto end_loc = Lexer::getLocForEndOfToken( d->getTypeSourceInfo()->getTypeLoc().getEndLoc(), 0, sm, LangOptions() );
auto src_range = SourceRange( d->getSourceRange().getBegin(), end_loc );
有人可以详细说明一下吗?我希望有一个简单的声明方法能够给我一个“直观”的源范围。
这是一个简单的示例,适用于其他声明,例如 TypeAliasDecl。
通常,Clang AST 节点将“结束”位置记录为被视为该节点子树一部分的最后一个标记的起始字符。 Clang 编译器前端 (CFE) 内部手册有一个关于此主题的简短部分:
SourceRange 和 CharSourceRange
Clang 用 [first, last] 表示大多数源范围,其中“first”和“last”分别指向各自标记的开头。例如,考虑以下语句的
:SourceRange
x = foo + bar; ^first ^last
要从此表示映射到基于字符的表示,需要调整“最后”位置以指向(或过去)带有
或Lexer::MeasureTokenLength()
的标记的末尾。对于需要字符级源范围信息的极少数情况,我们使用Lexer::getLocForEndOfToken()
类。CharSourceRange
因此,您问题中概述的方法确实是找到 AST 节点的范围必须采取的方法。
DurationDivisionCheck.cpp
:
<< FixItHint::CreateInsertion(
Lexer::getLocForEndOfToken(
Result.SourceManager->getSpellingLoc(OpCall->getEndLoc()), 0,
*Result.SourceManager, Result.Context->getLangOpts()),
")");
上面是针对运算符表达式而不是声明,但对于两个构造的结束位置使用相同的方法。
最后一点,语句 AST 节点的“结束”通常不包括终止分号;相反,它以分号之前的标记结尾(当有分号时)。 请参阅 Q+A 为什么对于以分号结尾的语句,源位置会以两个字符结尾? 了解更多信息。