Esegui uno specifico controllo del clangore sull'intera base di codice

Esegui uno specifico controllo del clangore sull'intera base di codice

Recentemente ho fatto un importante refactoring su un pezzo di codice che coinvolgeva migliaia di righe di codice che erano in un modo o nell'altro legate alla gestione delle stringhe. Tutto il codice gestiva char* (array di puntatori di caratteri in stile C) e il concetto di const o la proprietà era letteralmente sconosciuta in quella parte della codebase. Il codice rifattorizzato utilizza std::string 's, ma a causa della natura ereditaria, un gran numero di metodi ha restituito nullptr 's invece di emptystrings (come "" ). Capisco perché è stato fatto, ma trovare tutte quelle istanze e il fatto che dia solo un errore di runtime è stato un po' un peccato.

Fortunatamente clang-tidy è qui per salvare la giornata. Nel mio IDE, CLion, dà un avviso quando restituisci un nullptr . Tuttavia, lo fa solo nel file che stai attualmente modificando e, poiché stiamo parlando di milioni di file, non li avrei aperti manualmente. Puoi eseguire clang-tidy facilmente su un file, e non è difficile eseguirlo anche su un'intera codebase, usando lo scriptrun-clang-tidy.py , forniti nei loro pacchetti.

Questo frammento mostra come eseguire uno specifico clang-tidy controlla, nel mio caso, bugprone-string-constructor , su una base di codice (cmake e C++).

Ecco il messaggio ordinato in CLion:

Esempio di codice con comportamento non definito

Questo è un esempio di codice che dimostra il comportamento:

#include <string>
#include <iostream>

class Example {
public:
    std::string getName() { return nullptr; }
};

int main() {
    Example ex;
    std::cout << "Example: " << ex.getName() << std::endl;
    return 0;
}

Se provi a eseguire l'esempio di codice sopra, riceverai un errore di runtime:

terminate called after throwing an instance of 'std::logic_error'
    what():  basic_string::_M_construct null not valid

Opinioni su nullptr e std::string differiscono a seconda di chi lo chiedi, ma al momento non è possibile costruire un std::string con un nullptr .

Esegui clang-tidy su tutta la tua base di codice

Assicurati di avere clang-tidy installato:

apt install clang-tidy

Naviga nella cartella del tuo progetto:

cd my/cpp/project

Se non l'hai già fatto, crea una cartella build (mkdir build; cd build ) ed esegui cmake con un flag in più per creare il database di compilazione per clang-tidy :

cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug 

Nella cartella build, esegui run-clang-tidy . Potrebbe essere un comando diverso(run-clang-tidy.py o run-clang-tidy-VERSIONNUMBER ) a seconda delle preferenze di confezionamento della tua distribuzione.

run-clang-tidy -extra-arg=-Wno-unknown-warning-option -checks='-*,bugprone-string-constructor' 2>&1 | tee -a clang-tidy-result

Ci vorrà un po', quando il comando è finito, puoi guardare i risultati, o nel file clang-tidy-result . Nel mio caso ha fornito nomi di file e numeri di riga specifici in cui ha trovato il comportamento non definito.

Il -extra-arg era richiesto a causa di qualche altro flag di estensione del compilatore per il nostro codice, probabilmente puoi ometterlo.

Il -checks='-*' disabilita tutti i controlli, il prossimo,bugprone-string-constructor abilita solo il controllo di stringa specifico che voglio eseguire. Puoi aggiungere controlli più specifici, separandoli con una virgola. Un esempio con solo 2 controlli abilitati:

-checks='-*,bugprone-string-constructor,bugprone-string-integer-assignment'

Un elenco aggiornato di clang-tidy i controlli possono essere trovati sul sito Web di LLVM.


No