回答のコメントで指摘されているように、他のすべての回答には欠陥があるように思われるので、コメントで言及されているすべての欠陥をカバーしているように見える独自のコードを投稿します。
getSourceRange()
これは、ステートメントを文字のシーケンスではなく、トークンのシーケンスと見なしていると思います。これは、にclang::Stmt
対応するがFOO + BAR
、トークンFOO
が文字1にあり、トークン+
が文字5にあり、トークンBAR
が文字7にあることを意味します。getSourceRange()
したがって、これはSourceRange
本質的に「このコードは1のトークンで始まり、終了する」という意味を返します。トークンは7"です。したがって、を使用して、トークンclang::Lexer::getLocForEndOfToken(stmt.getSourceRange().getEnd())
の終了文字の実際の文字ごとの場所を取得し、それを終了場所としてに渡す必要があります。そうしないと、おそらく望んでいたのではなく、に戻ります。BAR
clang::Lexer::getSourceText
clang::Lexer::getSourceText
"FOO + "
"FOO + BAR"
このコードは、 Clangのソースドキュメントによると、範囲からソーステキストを取得するように特別に設計されたclang::Lexer::getSourceText
関数を使用しているため、私の実装にはコメントで言及されている@StevenLuの問題はないと思います。
この実装では、@RaminHalavatiの発言も考慮されています。いくつかのコードでテストしましたが、実際にマクロ展開された文字列が返されました。
これが私の実装です:
/**
* Gets the portion of the code that corresponds to given SourceRange, including the
* last token. Returns expanded macros.
*
* @see get_source_text_raw()
*/
std::string get_source_text(clang::SourceRange range, const clang::SourceManager& sm) {
clang::LangOptions lo;
// NOTE: sm.getSpellingLoc() used in case the range corresponds to a macro/preprocessed source.
auto start_loc = sm.getSpellingLoc(range.getBegin());
auto last_token_loc = sm.getSpellingLoc(range.getEnd());
auto end_loc = clang::Lexer::getLocForEndOfToken(last_token_loc, 0, sm, lo);
auto printable_range = clang::SourceRange{start_loc, end_loc};
return get_source_text_raw(printable_range, sm);
}
/**
* Gets the portion of the code that corresponds to given SourceRange exactly as
* the range is given.
*
* @warning The end location of the SourceRange returned by some Clang functions
* (such as clang::Expr::getSourceRange) might actually point to the first character
* (the "location") of the last token of the expression, rather than the character
* past-the-end of the expression like clang::Lexer::getSourceText expects.
* get_source_text_raw() does not take this into account. Use get_source_text()
* instead if you want to get the source text including the last token.
*
* @warning This function does not obtain the source of a macro/preprocessor expansion.
* Use get_source_text() for that.
*/
std::string get_source_text_raw(clang::SourceRange range, const clang::SourceManager& sm) {
return clang::Lexer::getSourceText(clang::CharSourceRange::getCharRange(range), sm, clang::LangOptions());
}