Clazy and LibClang for the Rescue

After my last post I downloaded clang, compiled clazy and got in contact with Sergio Martins – the main Clazy developer asking for some tips on how to start, as everyone should know LLVM is a compiler infrastructure that’s changing the world with quite a few projects, like Emscripten, Cling LLDB and the most well known tool: Clang

Every c++ developer of today’s world should praise Clang as it’s library and server mode are being used in Qt Creator, CLion and others for correctly parsing C++ code. I have *never* touched this kind of code, and I’m fearfull for my life. But knowing that Appending to temporaries is a worse solution than creating a static std::initializer_list gives me no other option, also, I’m bored.

Following Sergio’s advice I dumped the AST of the offending code and the AST of the good code:

clang++ -fsyntax-only -Xclang -ast-dump -fno-color-diagnostics qt_test_good.cpp > good.tree
clang++ -fsyntax-only -Xclang -ast-dump -fno-color-diagnostics qt_test_bad.cpp > bad.tree

The codes this time are a bit different than the ones I’v showed all yesterday as I’m only interested in The offending line, so I removed all for loops and all possible distraction that I had.

// bad code
int main() {
    QVector<int>() << 1 << 2 << 3 << 4 << 5;
}

// good code
int main() {
    QVector<int> {1, 2, 3, 4, 5};
}

And started to analyze the AST – For those who are not techically savy, AST stands for Abstract Syntax Tree and it describes what the program should do. and the good code, the small, one liner, good code dumped an AST of about 70.000 lines. *OH NOES!* I screamed, it’s impossible to actually understand that, that’s soo much stuff going on that I don’t even know where to start.

Then I looked at the function main and managed to strip out around 69.950 lines of code, Now this is actually userfull:

`-CompoundStmt 0x55dec0933910 <col:12, line:6:1> |-ExprWithCleanups 0x55dec09338c0 <line:4:5, col:47> 'QVector':'QVector'
| `-CXXBindTemporaryExpr 0x55dec09338a0 <col:5, col:47> 'QVector':'QVector' (CXXTemporary 0x55dec0933898)
| `-CXXTemporaryObjectExpr 0x55dec0933858 <col:5, col:47> 'QVector':'QVector' 'void (std::initializer_list)' list std::initializer_list
| `-CXXStdInitializerListExpr 0x55dec0933750 <col:17, col:47> 'std::initializer_list':'std::initializer_list'
| `-MaterializeTemporaryExpr 0x55dec0933738 <col:17, col:47> 'const int [10]' xvalue
| `-InitListExpr 0x55dec09336a8 <col:17, col:47> 'const int [10]'
| |-IntegerLiteral 0x55dec09239a8  'int' 1
| |-IntegerLiteral 0x55dec09239c8  'int' 2
| |-IntegerLiteral 0x55dec09239e8  'int' 3
| |-IntegerLiteral 0x55dec0923a08  'int' 4
| |-IntegerLiteral 0x55dec0923a28  'int' 5
`-ReturnStmt 0x55dec09338f8 <line:5:5, /usr/include/stdlib.h:92:22> `-IntegerLiteral 0x55dec09338d8  'int' 0

This is Tiny, and somewhat simple to understand what’s going on. I have no idea about the CompoundStmt, CXXTemporaryObjectExpr, InitListExpr and so on but I don’t care about that now, I’m only interested in trying to figure out the tree.

And here the Bad code: see something strange?

 

`-FunctionDecl 0x55c00766a5f8 <main.cpp:3:1, line:6:1> line:3:5 main 'int ()'
`-CompoundStmt 0x55c00767a098 <col:12, line:6:1>
|-ExprWithCleanups 0x55c00767a048 <line:4:5, col:68> 'QVector<int>':'QVector<int>' lvalue
| `-CXXOperatorCallExpr 0x55c00767a000 <col:5, col:68> 'QVector<int>':'QVector<int>' lvalue
| |-ImplicitCastExpr 0x55c007679fe8 <col:65> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x55c007679fc0 <col:65> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| |-CXXOperatorCallExpr 0x55c007679f40 <col:5, col:63> 'QVector<int>':'QVector<int>' lvalue
| | |-ImplicitCastExpr 0x55c007679f28 <col:60> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | `-DeclRefExpr 0x55c007679f00 <col:60> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | |-CXXOperatorCallExpr 0x55c007679e80 <col:5, col:58> 'QVector<int>':'QVector<int>' lvalue
| | | |-ImplicitCastExpr 0x55c007679e68 <col:55> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | `-DeclRefExpr 0x55c007679e40 <col:55> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | |-CXXOperatorCallExpr 0x55c007679dc0 <col:5, col:53> 'QVector<int>':'QVector<int>' lvalue
| | | | |-ImplicitCastExpr 0x55c007679da8 <col:50> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | `-DeclRefExpr 0x55c007679d80 <col:50> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | |-CXXOperatorCallExpr 0x55c007679d00 <col:5, col:48> 'QVector<int>':'QVector<int>' lvalue
| | | | | |-ImplicitCastExpr 0x55c007679ce8 <col:45> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | | `-DeclRefExpr 0x55c007679cc0 <col:45> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | | |-CXXOperatorCallExpr 0x55c007679c40 <col:5, col:43> 'QVector<int>':'QVector<int>' lvalue
| | | | | | |-ImplicitCastExpr 0x55c007679c28 <col:40> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | | | `-DeclRefExpr 0x55c007679c00 <col:40> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | | | |-CXXOperatorCallExpr 0x55c007679b80 <col:5, col:38> 'QVector<int>':'QVector<int>' lvalue
| | | | | | | |-ImplicitCastExpr 0x55c007679b68 <col:35> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | | | | `-DeclRefExpr 0x55c007679b40 <col:35> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | | | | |-CXXOperatorCallExpr 0x55c007679ac0 <col:5, col:33> 'QVector<int>':'QVector<int>' lvalue
| | | | | | | | |-ImplicitCastExpr 0x55c007679aa8 <col:30> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | | | | | `-DeclRefExpr 0x55c007679a80 <col:30> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | | | | | |-CXXOperatorCallExpr 0x55c007679a00 <col:5, col:28> 'QVector<int>':'QVector<int>' lvalue
| | | | | | | | | |-ImplicitCastExpr 0x55c0076799e8 <col:25> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | | | | | | `-DeclRefExpr 0x55c0076799c0 <col:25> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | | | | | | |-CXXOperatorCallExpr 0x55c007679940 <col:5, col:23> 'QVector<int>':'QVector<int>' lvalue
| | | | | | | | | | |-ImplicitCastExpr 0x55c007679928 <col:20> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | | | | | | | | | | `-DeclRefExpr 0x55c0076798a8 <col:20> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'
| | | | | | | | | | |-CXXBindTemporaryExpr 0x55c007679828 <col:5, col:18> 'QVector<int>':'QVector<int>' (CXXTemporary 0x55c007679820)
| | | | | | | | | | | `-CXXTemporaryObjectExpr 0x55c0076797e8 <col:5, col:18> 'QVector<int>':'QVector<int>' 'void () noexcept'
| | | | | | | | | | `-MaterializeTemporaryExpr 0x55c007679868 <col:23> 'int':'int' xvalue
| | | | | | | | | | `-IntegerLiteral 0x55c007679848 <col:23> 'int' 1
| | | | | | | | | `-MaterializeTemporaryExpr 0x55c0076799a8 <col:28> 'int':'int' xvalue
| | | | | | | | | `-IntegerLiteral 0x55c007679988 <col:28> 'int' 2
| | | | | | | | `-MaterializeTemporaryExpr 0x55c007679a68 <col:33> 'int':'int' xvalue
| | | | | | | | `-IntegerLiteral 0x55c007679a48 <col:33> 'int' 3
| | | | | | | `-MaterializeTemporaryExpr 0x55c007679b28 <col:38> 'int':'int' xvalue
| | | | | | | `-IntegerLiteral 0x55c007679b08 <col:38> 'int' 4
| | | | | | `-MaterializeTemporaryExpr 0x55c007679be8 <col:43> 'int':'int' xvalue
| | | | | | `-IntegerLiteral 0x55c007679bc8 <col:43> 'int' 5
| | | | | `-MaterializeTemporaryExpr 0x55c007679ca8 <col:48> 'int':'int' xvalue
| | | | | `-IntegerLiteral 0x55c007679c88 <col:48> 'int' 6
| | | | `-MaterializeTemporaryExpr 0x55c007679d68 <col:53> 'int':'int' xvalue
| | | | `-IntegerLiteral 0x55c007679d48 <col:53> 'int' 7
| | | `-MaterializeTemporaryExpr 0x55c007679e28 <col:58> 'int':'int' xvalue
| | | `-IntegerLiteral 0x55c007679e08 <col:58> 'int' 8
| | `-MaterializeTemporaryExpr 0x55c007679ee8 <col:63> 'int':'int' xvalue
| | `-IntegerLiteral 0x55c007679ec8 <col:63> 'int' 9
| `-MaterializeTemporaryExpr 0x55c007679fa8 <col:68> 'int':'int' xvalue
| `-IntegerLiteral 0x55c007679f88 <col:68> 'int' 10
`-ReturnStmt 0x55c00767a080 <line:5:5, /usr/include/stdlib.h:92:22>
`-IntegerLiteral 0x55c00767a060 <col:22> 'int' 0
g++ -Wl,-O1 -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -o testeQt main.o -lQt5Gui -lQt5Core -lGL -lpthread

I mean, I’m no genious but I can clearly see the difference (that’s different than understand, I’m still trying that second part.)

but I can see that those lines

| `-CXXOperatorCallExpr 0x55c00767a000 <col:5, col:68> 'QVector<int>':'QVector<int>' lvalue
| |-ImplicitCastExpr 0x55c007679fe8 <col:65> 'QVector<int> &(*)(int &&)' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x55c007679fc0 <col:65> 'QVector<int> &(int &&)' lvalue CXXMethod 0x55c007677858 'operator<<' 'QVector<int> &(int &&)'

repeat for each number that I append into the vector untill I find a

-CXXBindTemporaryExpr 0x55c007679828 <col:5, col:18> ‘QVector<int>’:’QVector<int>’ (CXXTemporary 0x55c007679820)

Hours reading the documentation, talking to Sergio, crying and hacking into clazy I have a (somewhat buggy and experimental) check that will warn you if you are appending to a temporary using operator-shift-left. I plan to send this to review this week and as soon as it’s 100% I’ll run in the entire KDE codebase.

Leave a Reply

Your email address will not be published. Required fields are marked *