Как найти SourceLocation запятых между аргументами функции с помощью libtooling? - PullRequest
1 голос
/ 20 июня 2019

Моя главная цель - попытаться получить макросы (или даже просто текст) перед параметрами функции. Например:

void Foo(_In_ void* p, _Out_ int* x, _Out_cap_(2) int* y);

Мне нужно изящно обрабатывать такие вещи, как макросы, которые объявляют параметры (игнорируя их).

#define Example _In_ int x void Foo(Example);

Я посмотрел на объекты записей препроцессора и использовал Lexer :: getSourceText для получения имен макросов В , Вне и т. Д., Но я не вижу чистого способа сопоставьте их с параметрами функции.

Мое текущее решение состоит в том, чтобы записать все расширения макросов в файле, а затем сравнить их SourceLocation с ParamVarDecl SourceLocation. В основном это работает, за исключением того, что я не знаю, как пропустить что-то после параметра.

void Foo(_In_ void* p _Other_, _In_ int y);

Получение SourceLocation запятой будет работать, но я не могу найти это нигде.

1 Ответ

1 голос
/ 21 июня 2019

В заголовке вопросов запрашивается libclang, но при использовании Lexer::getSourceText я предполагаю, что это libTooling.Остальная часть моего ответа жизнеспособна только с точки зрения libTooling.

Решение 1

Lexer работает на уровне токенов. Запятая также является токеном, так что вы можете взять конечное местоположение параметра и получить следующий токен, используя Lexer :: findNextToken .

Вот это ParmVarDecl (для параметров функции) и CallExpr (для аргументов функции) посещают функции, которые показывают, как его использовать:

template <class T> void printNextTokenLocation(T *Node) {
  auto NodeEndLocation = Node->getSourceRange().getEnd();

  auto &SM = Context->getSourceManager();
  auto &LO = Context->getLangOpts();

  auto NextToken = Lexer::findNextToken(NodeEndLocation, SM, LO);
  if (!NextToken) {
    return;
  }
  auto NextTokenLocation = NextToken->getLocation();

  llvm::errs() << NextTokenLocation.printToString(SM) << "\n";
}

bool VisitParmVarDecl(ParmVarDecl *Param) {
  printNextTokenLocation(Param);
  return true;
}

bool VisitCallExpr(CallExpr *Call) {
  for (auto *Arg : Call->arguments()) {
    printNextTokenLocation(Arg);
  }
  return true;
}

Для следующего фрагмента кода:

#define FOO(x) int x
#define BAR float d
#define MINUS -
#define BLANK

void foo(int a, double b     ,
         FOO(c)   , BAR) {}

int main() {
  foo(   42     ,
      36.6 ,   MINUS 10    ,   BLANK 0.0  );
  return 0;
}

создаетследующий вывод (шесть мест для запятых и два для круглых скобок):

test.cpp:6:15
test.cpp:6:30
test.cpp:7:19
test.cpp:7:24
test.cpp:10:17
test.cpp:11:12
test.cpp:11:28
test.cpp:11:43

Это довольно низкоуровневый и подверженный ошибкам подход.Тем не менее, вы можете изменить способ решения исходной проблемы.

Решение 2

Clang хранит информацию о расширенных макросах в своих исходных местоположениях.Вы можете найти соответствующие методы в SourceManager (например, isMacroArgExpansion или isMacroBodyExpansion ).В результате вы можете посещать ParmVarDecl узлы и проверять их расположение на предмет расширения макросов.

Я бы настоятельно рекомендовал двигаться во втором направлении.

Я надеюсь, что эта информация будет полезна.Удачного взлома с Clang!

UPD если говорить об атрибутах, к сожалению, у вас не будет большого выбора.Clang игнорирует любой неизвестный атрибут, и это поведение не настраивается .Если вы не хотите исправлять сам Clang и добавлять свои атрибуты в Attrs.td , тогда вы действительно ограничены токенами и первым подходом.

...