Как сопоставить строковые литералы в макросах TEXT и получить правильные начальные / конечные местоположения? - PullRequest
0 голосов
/ 16 октября 2019

Мне нужно заменить строковые литералы, расположенные в макросах TEXT, на libtooling. Например, в приведенном ниже фрагменте кода:

fd_ = CreateFile(TEXT("\\\\.\\") TEXT(PMEM_DEVICE_NAME),
        // Write is needed for IOCTL.
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

Если я сопоставлю все строки с ASTMatcher, getBeginLoc () будет указывать на первый T из TEXT, но getEndLoc () будет указывать на последний T из TEXT.

Как мне получить исходные местоположения контента между кавычками?

В libTooling есть много API-интерфейсов, которые задают местоположение чего-либо, но слишком мало документации об их различиях.

Я уже пробовал:

clang::SourceRange LiteralRange = clang::SourceRange(
            ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getBeginLoc()),
            ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getEndLoc())
    );

А также:

bool isMacro = ASTRewriter->getSourceMgr().isMacroBodyExpansion(pLiteral->getBeginLoc());
    bool ReplaceResult;
    std::string Replacement("test");

    if (isMacro) {
        StringRef OrigText = clang::Lexer::getSourceText(CharSourceRange(pLiteral->getSourceRange(), true),
                                                         pContext->getSourceManager(), pContext->getLangOpts());


        if (OrigText.find("TEXT") != std::string::npos) {

            auto EndLoc = clang::Lexer::findLocationAfterToken(LiteralRange.getBegin(), tok::r_paren,
                                                               pContext->getSourceManager(), ASTRewriter->getLangOpts(),
                                                               true);
            LiteralRange.setEnd(ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getEndLoc().getLocWithOffset(-1)));
            LiteralRange.setEnd(EndLoc);
            ASTRewriter->RemoveText(LiteralRange);

            ReplaceResult = ASTRewriter->ReplaceText(LiteralRange, Replacement);

Фрагмент, приведенный выше, работает хорошо в некоторых случаях, но в большинстве случаев яполучите следующее:

TEXT("something") => test("something"), тогда как я ожидаю TEXT("something") или просто "test".

Любая помощь с благодарностью!

...