Размер выражения в AST неверен для доступа члена - PullRequest
1 голос
/ 11 января 2020

Предположим, у меня есть следующий код:

struct S {
int abcd = 0;
};

int main() {
S s;
return s.abcd;
}

Соответствующая часть AST:

 -FunctionDecl 0x563ddd3a3e20 <line:5:1, line:8:1> line:5:5 main 'int ()'
  `-CompoundStmt 0x563ddd3a4570 <col:12, line:8:1>
    |-DeclStmt 0x563ddd3a44e0 <line:6:1, col:4>
    | `-VarDecl 0x563ddd3a3f40 <col:1, col:3> col:3 used s 'S' callinit
    |   `-CXXConstructExpr 0x563ddd3a44b8 <col:3> 'S' 'void () noexcept'
    `-ReturnStmt 0x563ddd3a4560 <line:7:1, col:10>
      `-ImplicitCastExpr 0x563ddd3a4548 <col:8, col:10> 'int' <LValueToRValue>
        `-MemberExpr 0x563ddd3a4518 <col:8, col:10> 'int' lvalue .abcd 0x563ddd3a3d10
          `-DeclRefExpr 0x563ddd3a44f8 <col:8> 'S' lvalue Var 0x563ddd3a3f40 's' 'S'

Проблема : согласно AST, возврат Оператор охватывает 10 столбцов, в то время как в действительности он охватывает 13.

НО , если мы поставим скобки вокруг доступа к члену, то он дает ожидаемый размер:

int main() {
S s;
return (s.abcd);
}
`-FunctionDecl 0x562842792e20 <line:5:1, line:8:1> line:5:5 main 'int ()'
  `-CompoundStmt 0x562842793590 <col:12, line:8:1>
    |-DeclStmt 0x5628427934e0 <line:6:1, col:4>
    | `-VarDecl 0x562842792f40 <col:1, col:3> col:3 used s 'S' callinit
    |   `-CXXConstructExpr 0x5628427934b8 <col:3> 'S' 'void () noexcept'
    `-ReturnStmt 0x562842793580 <line:7:1, col:15>
      `-ImplicitCastExpr 0x562842793568 <col:8, col:15> 'int' <LValueToRValue>
        `-ParenExpr 0x562842793548 <col:8, col:15> 'int' lvalue
          `-MemberExpr 0x562842793518 <col:9, col:11> 'int' lvalue .abcd 0x562842792d10
            `-DeclRefExpr 0x5628427934f8 <col:9> 'S' lvalue Var 0x562842792f40 's' 'S'

Кроме того, вы можете видеть, что ParenExpr охватывает 8-15 столбцов, а MemberExpr охватывает 9-11 столбцов, что свидетельствует о странности более позднего узла AST.

Я что-то упустил?

Я делаю преобразования источника в источник, и я хотел бы получить правильный размер выражений / операторов. Прямо сейчас я понятия не имею, как это сделать. getEndLoc() для исходного оператора возврата также возвращает местоположение . (оператор точки).

clang version 9.0.1

1 Ответ

1 голос
/ 13 января 2020

Я решил обратиться за помощью к списку рассылки cfe-dev, вот что я узнал.

Похоже, я полностью неправильно понял значение getBeginLoc() / getEndLoc(). getBeginLoc() возвращает местоположение начала первого токена, а getEndLoc() возвращает начало последнего токена.

Чтобы получить конец токена, можно использовать Lexer::getLocForEndOfToken(...).

Документация также может быть полезна: https://clang.llvm.org/docs/InternalsManual.html#sourcerange -and-charsourcerange

...