#clang
#clang
Вопрос:
Я разрабатываю инструмент, который анализирует и проверяет код с помощью clang, и я пытаюсь выяснить, есть ли способ получить нестандартные атрибуты clang из исходного кода. Например, я хотел бы аннотировать цикл инвариантом цикла или выражением с [[not_null]]
. Возможно ли это? Может быть, есть какой-то вариант, который бы говорил
Вот конкретный пример:
struct custom { };
int test() {
int x;
switch (1) {
case 1:
x = 1;
[[fallthrough]] ;
case 2:
x = 2;
break;
}
[[custom()]]
if (1) { return 1; } else { return 0; }
}
Результирующий AST выглядит следующим образом:
`-FunctionDecl 0x55a9780ebba0 <line:2:1, line:14:1> line:2:5 test 'int ()'
`-CompoundStmt 0x55a9780ec060 <col:12, line:14:1>
|-DeclStmt 0x55a9780ebd08 <line:3:3, col:8>
| `-VarDecl 0x55a9780ebca0 <col:3, col:7> col:7 used x 'int'
|-SwitchStmt 0x55a9780ebd40 <line:4:3, line:11:3>
| |-IntegerLiteral 0x55a9780ebd20 <line:4:11> 'int' 1
| `-CompoundStmt 0x55a9780ebf40 <col:14, line:11:3>
| |-CaseStmt 0x55a9780ebda0 <line:5:3, line:6:9>
| | |-ConstantExpr 0x55a9780ebd80 <line:5:8> 'int' Int: 1
| | | `-IntegerLiteral 0x55a9780ebd60 <col:8> 'int' 1
| | `-BinaryOperator 0x55a9780ebe08 <line:6:5, col:9> 'int' lvalue '='
| | |-DeclRefExpr 0x55a9780ebdc8 <col:5> 'int' lvalue Var 0x55a9780ebca0 'x' 'int'
| | `-IntegerLiteral 0x55a9780ebde8 <col:9> 'int' 1
| |-AttributedStmt 0x55a9780ebe58 <line:7:5, col:21> <<<<<<<<<<<<<<<<<<<<<<<<<<< GOT Fallthrough
| | |-FallThroughAttr 0x55a9780ebe30 <col:7>
| | `-NullStmt 0x55a9780ebe28 <col:21>
| |-CaseStmt 0x55a9780ebeb0 <line:8:3, line:9:9>
| | |-ConstantExpr 0x55a9780ebe90 <line:8:8> 'int' Int: 2
| | | `-IntegerLiteral 0x55a9780ebe70 <col:8> 'int' 2
| | `-BinaryOperator 0x55a9780ebf18 <line:9:5, col:9> 'int' lvalue '='
| | |-DeclRefExpr 0x55a9780ebed8 <col:5> 'int' lvalue Var 0x55a9780ebca0 'x' 'int'
| | `-IntegerLiteral 0x55a9780ebef8 <col:9> 'int' 2
| `-BreakStmt 0x55a9780ebf38 <line:10:5>
`-IfStmt 0x55a9780ec038 <line:13:3, col:41> has_else <<<<<<<<<<<<<<<<<<<<<<<<<<< MISSING custom
|-ImplicitCastExpr 0x55a9780ebf90 <col:7> 'bool' <IntegralToBoolean>
| `-IntegerLiteral 0x55a9780ebf70 <col:7> 'int' 1
|-CompoundStmt 0x55a9780ebfd8 <col:10, col:22>
| `-ReturnStmt 0x55a9780ebfc8 <col:12, col:19>
| `-IntegerLiteral 0x55a9780ebfa8 <col:19> 'int' 1
`-CompoundStmt 0x55a9780ec020 <col:29, col:41>
`-ReturnStmt 0x55a9780ec010 <col:31, col:38>
`-IntegerLiteral 0x55a9780ebff0 <col:38> 'int' 0
Ответ №1:
Да, это возможно. есть два способа AFAIK.
Сначала нужно добавить ваше новое определение в Clang. Вы можете изменить исходный код Clang в tools/clang/include/clang/Basic/Attr.td
. Затем Clang узнает ваш новый атрибут. Недостатки могут заключаться в том, что вам нужно каждый раз перестраивать весь исходный код для внесения изменений.
Второе — использовать доступный атрибут annotate
. Например [[clang::annotate("not_null")]]
. Лично я предпочитаю гибкость этого подхода.
Здесь мы предполагаем, что я хочу выполнить поиск функции decl с пользовательским атрибутом:
#define MY_ATTR [[clang::annotate("my_attr")]]
...
// i want to extract this attribute
MY_ATTR void foo(...) { ... }
я могу реализовать функцию посетителя, например:
bool VisitFunctionDecl(FunctionDecl *D) {
if (D->hasAttrs()) {
for (auto attr : D->getAttrs()) {
std::string attr_name(attr->getSpelling());
std::string attr_annotate("annotate");
std::string attr_my("annotate("my_attr")");
if (attr_name == attr_annotate) {
std::string SS; llvm::raw_string_ostream S(SS);
attr->printPretty(S, Policy);
std::string attr_string(S.str());
if (attr_string.find(attr_my) != std::string::npos) {
// found it! do stuff here!
// ...
}
}
}
}
return true;
}
я думаю, вы можете легко адаптировать его к аннотации вашего цикла.
Комментарии:
1. Спасибо! Просматривая документы, похоже, что мне в основном нужно реализовать свой собственный анализатор для аннотации. В приведенном выше примере вы просите clang распечатать его, есть ли какой-либо способ получить представление, из которого он печатается?
2. да, вам нужно реализовать свой собственный анализатор. Извлечение строк, подобных приведенному в ответе, — это всего лишь одна из возможностей, которая сработала для меня. Загляните в ссылку clang::Attr , я не знаю, как отличить два
clang::annotate
атрибута с разными аннотациями. Вот почему я печатаю строки и сравниваю их в анализаторе.