如何使用 clang 从行号获取源文本?

The*_*ger 7 clang llvm-clang clang-ast-matchers

我正在使用 clang matcher 来获取结果节点。从结果节点中,我能够获取行号,假设为 17。现在,我想获取该行中的整个源代码。请帮忙。

让我详细解释一下。我有一个 clang 匹配器,可以在源代码中查找浮动文字。例如,第17行sr = 2.0 * rt_urand_Upu32_Yd_f_pw_snf(u);是源代码,那么它匹配2.0。这是我的匹配器:

const auto PA = floatLiteral(
                                isExpansionInMainFile(), 
                                unless(hasAncestor(arraySubscriptExpr()))
                            ).bind("pa");
            MatchFinder MatchFinder;
            MatchFinder.addMatcher(PA, &Handler);
            MatchFinder.matchAST(Context);
Run Code Online (Sandbox Code Playgroud)

从匹配器中,我可以获得匹配的节点。我能够检索行号(第 17 行)和列号(6)。请在下面找到我的代码:

const clang::FloatingLiteral* Variable = Result.Nodes.getNodeAs<clang::FloatingLiteral>("pa");
clang::SourceRange loc = Variable16->getSourceRange();
locStart = srcMgr.getPresumedLoc(loc.getBegin());
locEnd = srcMgr.getPresumedLoc(loc.getEnd());
std::cout << locStart.getLine()<< ":" << locEnd.getLine() << std::endl;
std::cout << locStart.getColumn() <<":" << locEnd.getColumn() << std::endl;
Run Code Online (Sandbox Code Playgroud)

现在,如果我尝试检索源代码,我只能得到部分数据。在网上做了一些研究后,我尝试通过两种方式检索源代码。第一种方法是使用词法分析器,请找到下面的代码:

llvm::StringRef ref = Lexer::getSourceText(CharSourceRange::getCharRange(statement->getSourceRange()), srcMgr, LangOptions());
cout << ref.str() << endl;
Run Code Online (Sandbox Code Playgroud)

第二种方法是使用重写器,请找到下面的代码:

clang::Rewriter rewriter;
rewriter.setSourceMgr(Result.Context->getSourceManager(),Result.Context->getLangOpts());
cout<<rewriter.getRewrittenText (loc)<<endl;
Run Code Online (Sandbox Code Playgroud)

据我了解,我似乎需要从第 17 行第 0 列开始到第 17 行列末尾的源范围。AST 匹配器仅匹配特定节点,所以我的问题是:

1)是否可以获得第17行的最终列号?

2)还有其他方法可以从行号获取源代码吗?

3)还有其他方法可以从matcher获取源代码吗?

谢谢您的帮助。

小智 0

  1. 没有直接的方法来获取一行的最后一列,但是有一个解决方案来获取该行的开头。我假设您有SourceManager ( SM) 和SourceLocation ( SL)
SM.translateLineCol(SM.getMainFileID(),SM.getSpellingLineNumber(SL),1);
Run Code Online (Sandbox Code Playgroud)

如果您确实想要获得特定行的结尾,您可以将列号设置为一个令人难以置信的数字,例如 1000。如果该行少于 1000 个字符,它将卡在最后一个字符,但如果该行超过 1000 个字符,它将不会出现在行尾,因此该解决方案不稳定。该示例获取第 17 行的结束位置。

SM.translateLineCol(SM.getMainFileID(),17,1000);
Run Code Online (Sandbox Code Playgroud)
  1. 通过使用上面的解决方案,您可以使用Rewriter ( Rw) 来获取源代码。例如,如果您想获取第17行的代码,并将其存储在字符串结果中
SourceLocation thisline=SM.translateLineCol(SM.getMainFileID(),17,1); // get the beginning of line 17
SourceLocation nextline=SM.translateLineCol(SM.getMainFileID(),18,1); // get the beginning of line 18
string result = Rw.getRewrittenText(SourceRange(thisline,nextline));
Run Code Online (Sandbox Code Playgroud)
  1. 是的,如果您有适当的 SourceRange 和 Rewriter,您可以使用getRewrittenText()匹配结果。