18

clangにASTオブジェクトがある場合、その背後にあるコードを取得するにはどうすればよいですか?チュートリアルでコードを編集してみて、次のように追加しました。

clang::SourceLocation _b = d->getLocStart(), _e = d->getLocEnd();
char *b = sourceManager->getCharacterData(_b),
      e = sourceManager->getCharacterData(_E);
llvm:errs() << std::string(b, e-b) << "\n";

しかし残念ながら、typedef宣言全体は出力されず、その約半分しか出力されませんでした。印刷時にも同じ現象が発生しましたExpr

宣言を構成する元の文字列全体を印刷して確認するにはどうすればよいですか?

4

4 に答える 4

19

Lexerモジュールを使用します。

clang::SourceManager *sm;
clang::LangOptions lopt;

std::string decl2str(clang::Decl *d) {
    clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd());
    clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, *sm, lopt));
    return std::string(sm->getCharacterData(b),
        sm->getCharacterData(e)-sm->getCharacterData(b));
}
于 2012-06-22T10:06:37.517 に答える
7

次のコードは私のために働きます。

std::string decl2str(clang::Decl *d, SourceManager &sm) {
    // (T, U) => "T,,"
    string text = Lexer::getSourceText(CharSourceRange::getTokenRange(d->getSourceRange()), sm, LangOptions(), 0);
    if (text.size() > 0 && (text.at(text.size()-1) == ',')) //the text can be ""
        return Lexer::getSourceText(CharSourceRange::getCharRange(d->getSourceRange()), sm, LangOptions(), 0);
    return text;
}
于 2014-04-15T11:02:04.193 に答える
2

回答のコメントで指摘されているように、他のすべての回答には欠陥があるように思われるので、コメントで言及されているすべての欠陥をカバーしているように見える独自のコードを投稿します。

getSourceRange()これは、ステートメントを文字のシーケンスではなく、トークンのシーケンスと見なしていると思います。これは、にclang::Stmt対応するがFOO + BAR、トークンFOOが文字1にあり、トークン+が文字5にあり、トークンBARが文字7にあることを意味します。getSourceRange()したがって、これはSourceRange本質的に「このコードは1のトークンで始まり、終了する」という意味を返します。トークンは7"です。したがって、を使用して、トークンclang::Lexer::getLocForEndOfToken(stmt.getSourceRange().getEnd())の終了文字の実際の文字ごとの場所を取得し、それを終了場所としてに渡す必要があります。そうしないと、おそらく望んでいたのではなく、に戻ります。BARclang::Lexer::getSourceTextclang::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());
}
于 2020-04-29T20:20:56.617 に答える
1

マクロが含まれている場合を除いて、Elazarの方法は私のために機能しました。次の修正で解決しました。

std::string decl2str(clang::Decl *d) {
    clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd());
    if (b.isMacroID())
        b = sm->getSpellingLoc(b);
    if (e.isMacroID())
        e = sm->getSpellingLoc(e);
    clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, *sm, lopt));
    return std::string(sm->getCharacterData(b),
        sm->getCharacterData(e)-sm->getCharacterData(b));
}
于 2016-09-20T16:06:21.340 に答える