Как вы правильно заметили, исходный код уже предварительно обработан и в нем развернуты все макросы.Таким образом, AST будет просто иметь целочисленное выражение в качестве размера массива.
Немного информации о расположении источника
ПРИМЕЧАНИЕ : вы можете пропуститьи перейдем непосредственно к решению, приведенному ниже
Информация о расширенных макросах содержится в исходных местоположениях узлов AST и обычно может быть получена с использованием Lexer (лексер и препроцессор Кланга оченьтесно связаны и могут даже рассматриваться как одно целое).Это минимум и не очень очевидно для работы, но это то, что есть.
Поскольку вы ищете способ получить оригинальное имя макроса для замены, вам нужно только получить орфография (то есть, как это было написано в оригинальном исходном коде), и вам не нужно много рассказывать об определениях макросов, макросах в стиле функций и их аргументах и т. д.
У Clang есть дватипы различных местоположений: SourceLocation и CharSourceLocation .Первый может быть найден почти везде через AST.Это относится к позиции с точки зрения токенов .Это объясняет, почему позиции начало и конец могут быть несколько нелогичными:
// clang::DeclRefExpr
//
// ┌─ begin location
foo(VeryLongButDescriptiveVariableName);
// └─ end location
// clang::BinaryOperator
//
// ┌─ begin location
int Result = LHS + RHS;
// └─ end location
Как вы можете видеть, этот тип местоположения источника указывает на началосоответствующего токена. CharSourceLocation , с другой стороны, указывает непосредственно на символов .
Итак, чтобы получить исходный текст выражения, нам нужно преобразовать SourceLocation до CharSourceLocation и получите соответствующий текст из источника.
Решение
Я изменил ваш пример, чтобы показать другие случаитакже расширения макросов:
#define STR_MAX 2049
#define BAR(X) X
int main() {
char inStrDef[STR_MAX];
char inStrFunc[BAR(2049)];
char inStrFuncNested[BAR(BAR(STR_MAX))];
}
Следующий код:
// clang::VarDecl *VD;
// clang::ASTContext *Context;
auto &SM = Context->getSourceManager();
auto &LO = Context->getLangOpts();
auto DeclarationType = VD->getTypeSourceInfo()->getTypeLoc();
if (auto ArrayType = DeclarationType.getAs<ConstantArrayTypeLoc>()) {
auto *Size = ArrayType.getSizeExpr();
auto CharRange = Lexer::getAsCharRange(Size->getSourceRange(), SM, LO);
// Lexer gets text for [start, end) and we want him to grab the end as well
CharRange.setEnd(CharRange.getEnd().getLocWithOffset(1));
auto StringRep = Lexer::getSourceText(CharRange, SM, LO);
llvm::errs() << StringRep << "\n";
}
создает этот вывод для фрагмента:
STR_MAX
BAR(2049)
BAR(BAR(STR_MAX))
Надеюсь, эта информация полезна.Счастливого взлома с Clang!