SlideShare a Scribd company logo
1 of 44
Download to read offline
Uno studio sull’efficacia di checker automatici
per la modernizzazione di codice C++
Idriss Riouak
Universit`a degli studi di Parma
Corso di laurea in Informatica
22 Dicembre 2016
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Problema: la modernizzazione del codice
E’ difficile mantenere i software aggiornati alle pi`u recenti
convenzioni stabilite dagli standard.
Modernizzare il software rappresenta un costo. Nasce cos`ı
l’esigenza d’avere strumenti che automatizzino (almeno in parte)
tale processo.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Clang Tidy
Clang Tidy `e un uno dei progetti principali della Clang & LLVM
Community
E’ uno strumento utilizzato per individuare i pi`u frequenti errori di
programmazione.
Aiuta lo sviluppatore a seguire i pattern di programmazione e i
nuovi costrutti dello standard C++11/C++14.
.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Clang Tidy Modernize
Clang Tidy Modernize supporta 17 check tra cui:
Keyword nullptr
Keyword default per funzioni speciali
Keyword auto (Deduzione automatica dei tipi)
Keyword override
shared ptr & unique ptr
Utilizzo di lambda funzioni anzich´e std::bind
Riferimenti RValue (move semantic)
Utilizzo di Range-based for loop
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Abstract Sintax Tree
Dal codice sorgente da modernizzare viene creato un Albero di
Sintassi Astratta, d’ora in avanti AST.
Definition (Albero di Sintassi Astratta)
L’AST `e una rappresentazione pi`u ad alto livello del codice
sorgente, utilizzata dal compilatore per ottenerne informazioni.
L’AST di Clang `e composto da quattro macro classi:
Decl
Decl: dichiarazioni di variabili, campi di struct/union/class e tipi.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Abstract Sintax Tree
Dal codice sorgente da modernizzare viene creato un Albero di
Sintassi Astratta, d’ora in avanti AST.
Definition (Albero di Sintassi Astratta)
L’AST `e una rappresentazione pi`u ad alto livello del codice
sorgente, utilizzata dal compilatore per ottenerne informazioni.
L’AST di Clang `e composto da quattro macro classi:
Decl Type
Type: Tipi del C++ e i relativi qualificatori.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Abstract Sintax Tree
Dal codice sorgente da modernizzare viene creato un Albero di
Sintassi Astratta, d’ora in avanti AST.
Definition (Albero di Sintassi Astratta)
L’AST `e una rappresentazione pi`u ad alto livello del codice
sorgente, utilizzata dal compilatore per ottenerne informazioni.
L’AST di Clang `e composto da quattro macro classi:
Decl Type Stmt
Stmt: Statement del C++.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Abstract Sintax Tree
Dal codice sorgente da modernizzare viene creato un Albero di
Sintassi Astratta, d’ora in avanti AST.
Definition (Albero di Sintassi Astratta)
L’AST `e una rappresentazione pi`u ad alto livello del codice
sorgente, utilizzata dal compilatore per ottenerne informazioni.
L’AST di Clang `e composto da quattro macro classi:
Decl Type Stmt Expr
Expr: classe derivata di Stmt. Espressione del C++.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Esempio
Consideriamo il seguente esempio:
void SetStream(int);
int main(int argc , char *argv []) {
int StreamNumber = 1;
SetStream(StreamNumber);
return 0;
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
FunctionDecl
‘void (int, char**)’ main
ParamValDecl
‘int’ argc
ParamValDecl
‘char **’:‘char**’ argv
CompoundStmt DeclStmt
CallExpr
‘void’
ReturnStmt
VarDecl
‘int’ StreamNumber
IntegerLiteral
‘int’ 1
ImplicitCastExpr
‘void (*)()’
DeclRefExpr
‘void()’ ‘SetStream’
ImplicitCastExpr
‘int’
DeclRefExpr
‘int’ ‘StreamNumber’
IntegerLiteral
‘int’ 0
LEGENDA:
Espressione
Statement
Declaration
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Flessibilit`a dell’infrastruttura
Obiettivo
Oltre a valutare l’efficacia dei check esistenti nel modulo
modernize, uno degli obiettivi era di mettere alla prova la
flessibilit`a e la modularit`a dell’infrastruttura di Clang Tidy.
Sono stati presi in considerazione tre casistiche:
La correzione di errori in check esistenti.
La definizione di nuovi check.
L’estensione delle funzionalit`a di check esistenti.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Struttura di un check
Per ogni check presente in Clang Tidy, esiste una classe che ne
descrive il comportamento ed `e cos`ı strutturata:
#include "../ ClangTidy.h"
namespace clang {
namespace tidy {
namespace some_module {
class MyCheck : public ClangTidyCheck {
public:
MyCheck(StringRef Name , ClangTidyContext *Context)
: ClangTidyCheck(Name , Context) {}
// Other Methods ...
};
} // namespace some_module
} // namespace tidy
} // namespace clang
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Definizione del comportamento del check
AST Matcher: metodo che permette di etichettare alcuni nodi
dell’AST senza doverlo visitare nella sua completezza
void registerMatchers (ast_matchers ::
MatchFinder *Finder) override;
Utilizzo dei nodi: effettuando l’overriding del seguente metodo `e
possibile utilizzare i nodi etichettati.
void check(const
ast_matchers :: MatchFinder :: MatchResult
&Result) override;
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Correzione di errori in check esistenti:
modernize-avoid-bind
Studiano il check modernize-avoid-bind, si `e riscontrato un caso in
cui proponesse un fix errato. In particolare il check non
considerava in alcun modo l’operatore di risoluzione dello scope.
Consideriamo tale porzione di codice:
namespace A {
int add(int x, int y);
}
int main(int argc , const char * argv []) {
auto clj = std:: bind(A::add , 1, 1);
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Correzione di errori in check esistenti:
modernize-avoid-bind
Dopo avere applicato il fix con Clang Tidy:
int main(int argc , const char * argv []) {
auto clj = [=]( auto && arg1) {
return add(x, arg1);
};
}
Che `e completamente diverso da
int main(int argc , const char * argv []) {
auto clj = [=]( auto && arg1) {
return A::add(x, arg1);
};
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Correzione di errori in check esistenti:
modernize-avoid-bind
E’ stato modificato il metodo registerMatcher in maniera tale da
etichettare il riferimento della dichiarazione della funzione.
void AvoidBindCheck :: registerMatchers (MatchFinder
*Finder) {
if (! getLangOpts ().CPlusPlus14) // Need C++14 for
generic lambdas.
return;
Finder ->addMatcher(
callExpr(callee(namedDecl(hasName("::std:: bind"))),
declRefExpr(to(functionDecl ().bind("f")))
.(bind("ref")))).bind("bind"),
this);
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Dopo di che `e stato modificato il metodo che sfrutta tali nodi:
void AvoidBindCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto *MatchedDecl =
Result.Nodes.getNodeAs <CallExpr >("bind");
auto Diag = diag(MatchedDecl ->getLocStart (),
"prefer a lambda to std:: bind");
// Some Code ...
const auto *F =
Result.Nodes.getNodeAs <FunctionDecl >("f");
std:: string Buffer;
llvm :: raw_string_ostream Stream(Buffer);
// Some Code ...
const auto *ref = Result.Nodes.getNodeAs<DeclRefExpr>("ref");
Stream << "[" << ( HasCapturedArgument ? "=" : "")
<< "]";
addPlaceholderArgs (Args , Stream);
Stream << " return ";
ref->printPretty(Stream, nullptr,
Result.Context->getPrintingPolicy());
Stream << "(";
addFunctionCallArgs (Args , Stream);
Stream << "); };";
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Dopo di che `e stato modificato il metodo che sfrutta tali nodi:
void AvoidBindCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto *MatchedDecl =
Result.Nodes.getNodeAs <CallExpr >("bind");
auto Diag = diag(MatchedDecl ->getLocStart (),
"prefer a lambda to std:: bind");
// Some Code ...
const auto *F =
Result.Nodes.getNodeAs <FunctionDecl >("f");
std:: string Buffer;
llvm :: raw_string_ostream Stream(Buffer);
// Some Code ...
const auto *ref = Result.Nodes.getNodeAs<DeclRefExpr>("ref");
Stream << "[" << ( HasCapturedArgument ? "=" : "")
<< "]";
addPlaceholderArgs (Args , Stream);
Stream << " return ";
ref->printPretty(Stream, nullptr,
Result.Context->getPrintingPolicy());
Stream << "(";
addFunctionCallArgs (Args , Stream);
Stream << "); };";
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Correzione di errori in check esistenti:
modernize-avoid-bind
Compilando e rilanciando otteniamo la modifica corretta:
int main(int argc , const char * argv []) {
auto clj = [=]( auto && arg1) {
return A::add(x, arg1);
};
}
Per evitare la regressione delle modifiche effettuate sono stati
creati dei test.
La patch `e stata sottoposta agli sviluppatori di Clang che l’hanno
testata e accettata.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Creazione di un check: modernize-use-delete
Prima dell’avvento dello standard del C++11, per non permettere
l’utilizzo di costruttori/distruttori di una classe, li si definiva privati
e non implementati.
class MyClass{
private:
MyClass(const MyClass &);
MyClass& operator =( const MyClass &);
};
Con il C++11 `e stata introdotta la keyword delete.
class MyClass{
public:
MyClass(const MyClass &) = delete;
MyClass& operator =( const MyClass &) = delete;
};
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: registerMatchers (MatchFinder
*Finder) {
if (getLangOpts ().CPlusPlus) {
// Distruttore
Finder ->addMatcher( cxxDestructorDecl
(isPrivate ()).bind( SpecialFunction ),this);
Finder ->addMatcher(
cxxConstructorDecl (
anyOf(// Costruttore di default
allOf(isPrivate (), unless(
hasAnyConstructorInitializer (anything ())),
parameterCountIs (0)),
allOf(// Costruttore di copia
isPrivate (),isCopyConstructor (),
parameterCountIs (1))))
.bind( SpecialFunction ),
this);
Finder ->addMatcher(// Operator=
cxxMethodDecl(isPrivate (),
isCopyAssignmentOperator (),
hasParameter (0, hasType( lValueReferenceType ())))
.bind( SpecialFunction ),
this);
}
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: registerMatchers (MatchFinder
*Finder) {
if (getLangOpts().CPlusPlus) {
// Distruttore
Finder ->addMatcher( cxxDestructorDecl
(isPrivate ()).bind( SpecialFunction ),this);
Finder ->addMatcher(
cxxConstructorDecl (
anyOf(// Costruttore di default
allOf(isPrivate (), unless(
hasAnyConstructorInitializer (anything ())),
parameterCountIs (0)),
allOf(// Costruttore di copia
isPrivate (),isCopyConstructor (),
parameterCountIs (1))))
.bind( SpecialFunction ),
this);
Finder ->addMatcher(// Operator=
cxxMethodDecl(isPrivate (),
isCopyAssignmentOperator (),
hasParameter (0, hasType( lValueReferenceType ())))
.bind( SpecialFunction ),
this);
}
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: registerMatchers (MatchFinder
*Finder) {
if (getLangOpts().CPlusPlus) {
// Distruttore
Finder ->addMatcher(cxxDestructorDecl
(isPrivate()).bind( SpecialFunction ),this);
Finder ->addMatcher(
cxxConstructorDecl (
anyOf(// Costruttore di default
allOf(isPrivate (), unless(
hasAnyConstructorInitializer (anything ())),
parameterCountIs (0)),
allOf(// Costruttore di copia
isPrivate (),isCopyConstructor (),
parameterCountIs (1))))
.bind( SpecialFunction ),
this);
Finder ->addMatcher(// Operator=
cxxMethodDecl(isPrivate (),
isCopyAssignmentOperator (),
hasParameter (0, hasType( lValueReferenceType ())))
.bind( SpecialFunction ),
this);
}
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: registerMatchers (MatchFinder
*Finder) {
if (getLangOpts().CPlusPlus) {
// Distruttore
Finder ->addMatcher(cxxDestructorDecl
(isPrivate()).bind( SpecialFunction ),this);
Finder ->addMatcher(
cxxConstructorDecl(
anyOf(// Costruttore di default
allOf(isPrivate(), unless(
hasAnyConstructorInitializer (anything ())),
parameterCountIs (0)),
allOf(// Costruttore di copia
isPrivate (),isCopyConstructor (),
parameterCountIs (1))))
.bind( SpecialFunction ),
this);
Finder ->addMatcher(// Operator=
cxxMethodDecl(isPrivate (),
isCopyAssignmentOperator (),
hasParameter (0, hasType( lValueReferenceType ())))
.bind( SpecialFunction ),
this);
}
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: registerMatchers (MatchFinder
*Finder) {
if (getLangOpts().CPlusPlus) {
// Distruttore
Finder ->addMatcher(cxxDestructorDecl
(isPrivate()).bind( SpecialFunction ),this);
Finder ->addMatcher(
cxxConstructorDecl(
anyOf(// Costruttore di default
allOf(isPrivate(), unless(
hasAnyConstructorInitializer (anything ())),
parameterCountIs (0)),
allOf(// Costruttore di copia
isPrivate(),isCopyConstructor(),
parameterCountIs (1))))
.bind( SpecialFunction ),
this);
Finder ->addMatcher(// Operator=
cxxMethodDecl(isPrivate (),
isCopyAssignmentOperator (),
hasParameter (0, hasType( lValueReferenceType ())))
.bind( SpecialFunction ),
this);
}
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: registerMatchers (MatchFinder
*Finder) {
if (getLangOpts().CPlusPlus) {
// Distruttore
Finder ->addMatcher(cxxDestructorDecl
(isPrivate()).bind( SpecialFunction ),this);
Finder ->addMatcher(
cxxConstructorDecl(
anyOf(// Costruttore di default
allOf(isPrivate(), unless(
hasAnyConstructorInitializer (anything ())),
parameterCountIs (0)),
allOf(// Costruttore di copia
isPrivate(),isCopyConstructor(),
parameterCountIs (1))))
.bind( SpecialFunction ),
this);
Finder ->addMatcher(// Operator=
cxxMethodDecl(isPrivate(),
isCopyAssignmentOperator (),
hasParameter (0, hasType( lValueReferenceType ())))
.bind( SpecialFunction ),
this);
}
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined () ||
SpecialFunctionDecl ->isDeleted () ||
SpecialFunctionDecl -> isExplicitlyDefaulted () ||
SpecialFunctionDecl -> isLateTemplateParsed () ||
!SpecialFunctionDecl -> isUserProvided () )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint :: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined() ||
SpecialFunctionDecl ->isDeleted () ||
SpecialFunctionDecl -> isExplicitlyDefaulted () ||
SpecialFunctionDecl -> isLateTemplateParsed () ||
!SpecialFunctionDecl -> isUserProvided () )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint :: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined() ||
SpecialFunctionDecl ->isDeleted() ||
SpecialFunctionDecl -> isExplicitlyDefaulted () ||
SpecialFunctionDecl -> isLateTemplateParsed () ||
!SpecialFunctionDecl -> isUserProvided () )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint :: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined() ||
SpecialFunctionDecl ->isDeleted() ||
SpecialFunctionDecl ->isExplicitlyDefaulted() ||
SpecialFunctionDecl -> isLateTemplateParsed () ||
!SpecialFunctionDecl -> isUserProvided () )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint :: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined() ||
SpecialFunctionDecl ->isDeleted() ||
SpecialFunctionDecl ->isExplicitlyDefaulted() ||
SpecialFunctionDecl ->isLateTemplateParsed() ||
!SpecialFunctionDecl -> isUserProvided () )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint :: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined() ||
SpecialFunctionDecl ->isDeleted() ||
SpecialFunctionDecl ->isExplicitlyDefaulted() ||
SpecialFunctionDecl ->isLateTemplateParsed() ||
!SpecialFunctionDecl ->isUserProvided() )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint :: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
void UseDeleteCheck :: check(const
MatchFinder :: MatchResult &Result) {
const auto * SpecialFunctionDecl = Result.Nodes.
getNodeAs <CXXMethodDecl >( SpecialFunction );
if (SpecialFunctionDecl ->isDefined() ||
SpecialFunctionDecl ->isDeleted() ||
SpecialFunctionDecl ->isExplicitlyDefaulted() ||
SpecialFunctionDecl ->isLateTemplateParsed() ||
!SpecialFunctionDecl ->isUserProvided() )
return;
// Porzione di codice dove ottengo il nome della
funzione speciale
PresumedLoc PLoc = Result.SourceManager ->
getPresumedLoc (SpecialFunctionDecl ->getLocEnd ());
auto NewLocation = Result.SourceManager ->
translateLineCol (Result.SourceManager ->
getFileID(SpecialFunctionDecl ->getLocEnd ()),
PLoc.getLine (), PLoc.getColumn ()+1);
diag(NewLocation ,"Use ’= delete ’ to disable the " +
SpecialFunctionName )<<
FixItHint:: CreateInsertion (NewLocation , " =
delete");
}
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Diagnostica e Fix: modernize-use-delete
Quello che otteniamo eseguendo il check modernize-use-delete
sulla seguente porzione di codice:
class MyClass{
private:
MyClass(const MyClass &);
MyClass& operator =( const MyClass &);
};
quello che otteniamo `e il seguente messaggio diagnostico::
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Testing di efficacia sulla Parma Polyhedra Library
Parma Polyhedra Library (PPL)
Libreria di astrazioni numeriche concepita per le applicazioni nel
campo dell’analisi e verifica di sistemi complessi.
La PPL `e composta da:
78 file d’implementazione (.cc)
linee di codice 28·
646 (senza commenti)
366 header file (.hh)
linee di codice 129·
602 (senza commenti)
Numero totale di righe: 158·248
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Risultati ottenuti
Check Name Fix Corretti Fix Errati
modernize-use-nullptr 247 0
modernize-use-auto 224 0
modernize-use-override 114 0
modernize-use-default 58 0
modernize-pass-by-value 19 2
modernize-use-delete 28 0
modernize-use-emplace 15 0
modernize-replace-auto-ptr 2 0
modernize-redundant-void-arg 2 0
modernize-deprecated-headers 1 0
Clang Tidy agisce su porzioni di codice relativamente semplici.
Mentre la PPL per questioni di ottimizzazioni utilizza costrutti
complessi.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Conclusioni
Il lavoro di tesi ha permesso di studiare le problematiche relative
alla modernizzazione del codice mediante checker automatici.
Clang Tidy si `e presentato come un interessante progetto open
source la cui propriet`a fondamentale `e la modularit`a.
Un ottimo strumento di supporto al programmatore nell’attivit`a di
modernizzazione del codice C++, anche se ad oggi non `e efficace
ed affidabile per essere utilizzato in maniera automatica come
software gi`a esistenti.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Sviluppi futuri
Nel futuro continuer`o a contribuire allo sviluppo di Clang Tidy,
proponendo nuovi check e risolvendo errori nel checker, come nel
caso di modernize-pass-by-value.
Considerata la difficolt`a iniziale riscontrata nell’utilizzo di Clang
Tidy, `e ragionevole pensare allo sviluppo di un’interfaccia grafica
che ne semplifichi l’utilizzo.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
GRAZIE PER L’ATTENZIONE !
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Errore: modernize-pass-by-value
Nel testare modernize-pass-by-value si `e riscontrato il seguente
errore:
//! File iterator_to_const_defs .hh :135
template <typename Container >
class
Parma_Polyhedra_Library :: const_iterator_to_const {
private:
//! Constructs from the lower -level const_iterator .
const_iterator_to_const (const Base& b);
};
Correttamente diventa
//! File iterator_to_const_defs .hh :135
template <typename Container >
class
Parma_Polyhedra_Library :: const_iterator_to_const {
private:
//! Constructs from the lower -level const_iterator .
const_iterator_to_const (Base b);
};
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Errore: modernize-pass-by-value
Lasciando per`o invariata la testata della definizione.
//! File iterator_to_const_inline .hh :119
template <typename Container >
inline
const_iterator_to_const <Container >::
const_iterator_to_const (const Base& b)
: base(std:: move(b)) {
}
Ricompilando tutta la PPL ci accorgiamo che abbiamo degli errori
di compilazione.
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Commit LLVM Community
Figure: Link della revisione: https://reviews.llvm.org/D25649
logo.png
Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
Commit LLVM Community
Prima di rilasciare la patch, `e stato necessario testare che le
modifiche apportate al Check, non abbiano aggiunto ulteriori errori
e che il checker nel suo insieme fosse ancora stabile.
LLVM dispone di una suite di test. In particolari quelli del
pacchetto modernize sono locati nella directory
/llvm/tools/clang/tools/extra/test/clang-tidy.
Nel file modernize-avoid-bind.cpp sono state aggiunte le seguenti
istruzioni:
namespace C {
int add(int x, int y){ return x + y; }
}
void n(){
auto clj = std:: bind(C::add , 1, 1);
// CHECK -MESSAGES: :[[ @LINE -1]]:16: warning: prefer a
lambda to std:: bind
// CHECK -FIXES: auto clj = [] { return C::add(1, 1);
};
}

More Related Content

Similar to Presentazione: uno studio sull'efficacia di checker automatici per la modernizzazione di codice C++

Building infrastructure as code with typescript and aws cdk
Building infrastructure as code with typescript and aws cdkBuilding infrastructure as code with typescript and aws cdk
Building infrastructure as code with typescript and aws cdkAndrea Valentini
 
Infrastructure as Code e metodologia DevOps
Infrastructure as Code e metodologia DevOpsInfrastructure as Code e metodologia DevOps
Infrastructure as Code e metodologia DevOpsPietro Ciotola
 
Presentazione understand
Presentazione understandPresentazione understand
Presentazione understandLuigi La Torre
 
ASP.NET MVC 6 - uno sguardo al futuro
ASP.NET MVC 6 - uno sguardo al futuroASP.NET MVC 6 - uno sguardo al futuro
ASP.NET MVC 6 - uno sguardo al futuroAndrea Dottor
 
Analizzatori di programmi in C
Analizzatori di programmi in CAnalizzatori di programmi in C
Analizzatori di programmi in CBoymix81
 
Continous Delivery & HQ Code
Continous Delivery & HQ CodeContinous Delivery & HQ Code
Continous Delivery & HQ CodeDaniele Mondello
 
Effective Code Transformations in C++
Effective Code Transformations in C++Effective Code Transformations in C++
Effective Code Transformations in C++Marco Arena
 
Android Test Driven Development
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Developmentsazilla
 
Android Test Driven Development
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Developmentsazilla
 
MongoDB User Group Padova - Overviews iniziale su MongoDB
MongoDB User Group Padova - Overviews iniziale su MongoDBMongoDB User Group Padova - Overviews iniziale su MongoDB
MongoDB User Group Padova - Overviews iniziale su MongoDBStefano Dindo
 
05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...
05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...
05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...IBM Italia Web Team
 
Deep diving C# 4 (Raffaele Rialdi)
Deep diving C# 4 (Raffaele Rialdi)Deep diving C# 4 (Raffaele Rialdi)
Deep diving C# 4 (Raffaele Rialdi)DotNetMarche
 
Piattaforma Accelerated Antivirus Da Freescale & Kaspersky
Piattaforma Accelerated Antivirus Da Freescale & KasperskyPiattaforma Accelerated Antivirus Da Freescale & Kaspersky
Piattaforma Accelerated Antivirus Da Freescale & KasperskyIonela
 

Similar to Presentazione: uno studio sull'efficacia di checker automatici per la modernizzazione di codice C++ (20)

Building infrastructure as code with typescript and aws cdk
Building infrastructure as code with typescript and aws cdkBuilding infrastructure as code with typescript and aws cdk
Building infrastructure as code with typescript and aws cdk
 
3DD 1e Reconfig
3DD 1e Reconfig3DD 1e Reconfig
3DD 1e Reconfig
 
Infrastructure as Code e metodologia DevOps
Infrastructure as Code e metodologia DevOpsInfrastructure as Code e metodologia DevOps
Infrastructure as Code e metodologia DevOps
 
Presentazione understand
Presentazione understandPresentazione understand
Presentazione understand
 
Thesis Amicucci Slides IT
Thesis Amicucci Slides ITThesis Amicucci Slides IT
Thesis Amicucci Slides IT
 
ASP.NET MVC 6 - uno sguardo al futuro
ASP.NET MVC 6 - uno sguardo al futuroASP.NET MVC 6 - uno sguardo al futuro
ASP.NET MVC 6 - uno sguardo al futuro
 
Analizzatori di programmi in C
Analizzatori di programmi in CAnalizzatori di programmi in C
Analizzatori di programmi in C
 
XPages Tips & Tricks, #dd13
XPages Tips & Tricks, #dd13XPages Tips & Tricks, #dd13
XPages Tips & Tricks, #dd13
 
Logging
LoggingLogging
Logging
 
Continous Delivery & HQ Code
Continous Delivery & HQ CodeContinous Delivery & HQ Code
Continous Delivery & HQ Code
 
Effective Code Transformations in C++
Effective Code Transformations in C++Effective Code Transformations in C++
Effective Code Transformations in C++
 
Novità di Asp.Net 4.0
Novità di Asp.Net 4.0Novità di Asp.Net 4.0
Novità di Asp.Net 4.0
 
Android Test Driven Development
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Development
 
Android Test Driven Development
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Development
 
MongoDB User Group Padova - Overviews iniziale su MongoDB
MongoDB User Group Padova - Overviews iniziale su MongoDBMongoDB User Group Padova - Overviews iniziale su MongoDB
MongoDB User Group Padova - Overviews iniziale su MongoDB
 
Java per as400
Java per as400Java per as400
Java per as400
 
05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...
05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...
05 sicurezza delle applicazioni per le aziende nel settore della pubblica uti...
 
Deep diving C# 4 (Raffaele Rialdi)
Deep diving C# 4 (Raffaele Rialdi)Deep diving C# 4 (Raffaele Rialdi)
Deep diving C# 4 (Raffaele Rialdi)
 
Hadoop analyzerJR
Hadoop analyzerJRHadoop analyzerJR
Hadoop analyzerJR
 
Piattaforma Accelerated Antivirus Da Freescale & Kaspersky
Piattaforma Accelerated Antivirus Da Freescale & KasperskyPiattaforma Accelerated Antivirus Da Freescale & Kaspersky
Piattaforma Accelerated Antivirus Da Freescale & Kaspersky
 

Presentazione: uno studio sull'efficacia di checker automatici per la modernizzazione di codice C++

  • 1. Uno studio sull’efficacia di checker automatici per la modernizzazione di codice C++ Idriss Riouak Universit`a degli studi di Parma Corso di laurea in Informatica 22 Dicembre 2016
  • 2. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Problema: la modernizzazione del codice E’ difficile mantenere i software aggiornati alle pi`u recenti convenzioni stabilite dagli standard. Modernizzare il software rappresenta un costo. Nasce cos`ı l’esigenza d’avere strumenti che automatizzino (almeno in parte) tale processo.
  • 3. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Clang Tidy Clang Tidy `e un uno dei progetti principali della Clang & LLVM Community E’ uno strumento utilizzato per individuare i pi`u frequenti errori di programmazione. Aiuta lo sviluppatore a seguire i pattern di programmazione e i nuovi costrutti dello standard C++11/C++14. .
  • 4. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Clang Tidy Modernize Clang Tidy Modernize supporta 17 check tra cui: Keyword nullptr Keyword default per funzioni speciali Keyword auto (Deduzione automatica dei tipi) Keyword override shared ptr & unique ptr Utilizzo di lambda funzioni anzich´e std::bind Riferimenti RValue (move semantic) Utilizzo di Range-based for loop
  • 5. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Abstract Sintax Tree Dal codice sorgente da modernizzare viene creato un Albero di Sintassi Astratta, d’ora in avanti AST. Definition (Albero di Sintassi Astratta) L’AST `e una rappresentazione pi`u ad alto livello del codice sorgente, utilizzata dal compilatore per ottenerne informazioni. L’AST di Clang `e composto da quattro macro classi: Decl Decl: dichiarazioni di variabili, campi di struct/union/class e tipi.
  • 6. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Abstract Sintax Tree Dal codice sorgente da modernizzare viene creato un Albero di Sintassi Astratta, d’ora in avanti AST. Definition (Albero di Sintassi Astratta) L’AST `e una rappresentazione pi`u ad alto livello del codice sorgente, utilizzata dal compilatore per ottenerne informazioni. L’AST di Clang `e composto da quattro macro classi: Decl Type Type: Tipi del C++ e i relativi qualificatori.
  • 7. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Abstract Sintax Tree Dal codice sorgente da modernizzare viene creato un Albero di Sintassi Astratta, d’ora in avanti AST. Definition (Albero di Sintassi Astratta) L’AST `e una rappresentazione pi`u ad alto livello del codice sorgente, utilizzata dal compilatore per ottenerne informazioni. L’AST di Clang `e composto da quattro macro classi: Decl Type Stmt Stmt: Statement del C++.
  • 8. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Abstract Sintax Tree Dal codice sorgente da modernizzare viene creato un Albero di Sintassi Astratta, d’ora in avanti AST. Definition (Albero di Sintassi Astratta) L’AST `e una rappresentazione pi`u ad alto livello del codice sorgente, utilizzata dal compilatore per ottenerne informazioni. L’AST di Clang `e composto da quattro macro classi: Decl Type Stmt Expr Expr: classe derivata di Stmt. Espressione del C++.
  • 9. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Esempio Consideriamo il seguente esempio: void SetStream(int); int main(int argc , char *argv []) { int StreamNumber = 1; SetStream(StreamNumber); return 0; }
  • 10. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni FunctionDecl ‘void (int, char**)’ main ParamValDecl ‘int’ argc ParamValDecl ‘char **’:‘char**’ argv CompoundStmt DeclStmt CallExpr ‘void’ ReturnStmt VarDecl ‘int’ StreamNumber IntegerLiteral ‘int’ 1 ImplicitCastExpr ‘void (*)()’ DeclRefExpr ‘void()’ ‘SetStream’ ImplicitCastExpr ‘int’ DeclRefExpr ‘int’ ‘StreamNumber’ IntegerLiteral ‘int’ 0 LEGENDA: Espressione Statement Declaration
  • 11. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Flessibilit`a dell’infrastruttura Obiettivo Oltre a valutare l’efficacia dei check esistenti nel modulo modernize, uno degli obiettivi era di mettere alla prova la flessibilit`a e la modularit`a dell’infrastruttura di Clang Tidy. Sono stati presi in considerazione tre casistiche: La correzione di errori in check esistenti. La definizione di nuovi check. L’estensione delle funzionalit`a di check esistenti.
  • 12. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Struttura di un check Per ogni check presente in Clang Tidy, esiste una classe che ne descrive il comportamento ed `e cos`ı strutturata: #include "../ ClangTidy.h" namespace clang { namespace tidy { namespace some_module { class MyCheck : public ClangTidyCheck { public: MyCheck(StringRef Name , ClangTidyContext *Context) : ClangTidyCheck(Name , Context) {} // Other Methods ... }; } // namespace some_module } // namespace tidy } // namespace clang
  • 13. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Definizione del comportamento del check AST Matcher: metodo che permette di etichettare alcuni nodi dell’AST senza doverlo visitare nella sua completezza void registerMatchers (ast_matchers :: MatchFinder *Finder) override; Utilizzo dei nodi: effettuando l’overriding del seguente metodo `e possibile utilizzare i nodi etichettati. void check(const ast_matchers :: MatchFinder :: MatchResult &Result) override;
  • 14. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Correzione di errori in check esistenti: modernize-avoid-bind Studiano il check modernize-avoid-bind, si `e riscontrato un caso in cui proponesse un fix errato. In particolare il check non considerava in alcun modo l’operatore di risoluzione dello scope. Consideriamo tale porzione di codice: namespace A { int add(int x, int y); } int main(int argc , const char * argv []) { auto clj = std:: bind(A::add , 1, 1); }
  • 15. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Correzione di errori in check esistenti: modernize-avoid-bind Dopo avere applicato il fix con Clang Tidy: int main(int argc , const char * argv []) { auto clj = [=]( auto && arg1) { return add(x, arg1); }; } Che `e completamente diverso da int main(int argc , const char * argv []) { auto clj = [=]( auto && arg1) { return A::add(x, arg1); }; }
  • 16. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Correzione di errori in check esistenti: modernize-avoid-bind E’ stato modificato il metodo registerMatcher in maniera tale da etichettare il riferimento della dichiarazione della funzione. void AvoidBindCheck :: registerMatchers (MatchFinder *Finder) { if (! getLangOpts ().CPlusPlus14) // Need C++14 for generic lambdas. return; Finder ->addMatcher( callExpr(callee(namedDecl(hasName("::std:: bind"))), declRefExpr(to(functionDecl ().bind("f"))) .(bind("ref")))).bind("bind"), this); }
  • 17. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Dopo di che `e stato modificato il metodo che sfrutta tali nodi: void AvoidBindCheck :: check(const MatchFinder :: MatchResult &Result) { const auto *MatchedDecl = Result.Nodes.getNodeAs <CallExpr >("bind"); auto Diag = diag(MatchedDecl ->getLocStart (), "prefer a lambda to std:: bind"); // Some Code ... const auto *F = Result.Nodes.getNodeAs <FunctionDecl >("f"); std:: string Buffer; llvm :: raw_string_ostream Stream(Buffer); // Some Code ... const auto *ref = Result.Nodes.getNodeAs<DeclRefExpr>("ref"); Stream << "[" << ( HasCapturedArgument ? "=" : "") << "]"; addPlaceholderArgs (Args , Stream); Stream << " return "; ref->printPretty(Stream, nullptr, Result.Context->getPrintingPolicy()); Stream << "("; addFunctionCallArgs (Args , Stream); Stream << "); };"; }
  • 18. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Dopo di che `e stato modificato il metodo che sfrutta tali nodi: void AvoidBindCheck :: check(const MatchFinder :: MatchResult &Result) { const auto *MatchedDecl = Result.Nodes.getNodeAs <CallExpr >("bind"); auto Diag = diag(MatchedDecl ->getLocStart (), "prefer a lambda to std:: bind"); // Some Code ... const auto *F = Result.Nodes.getNodeAs <FunctionDecl >("f"); std:: string Buffer; llvm :: raw_string_ostream Stream(Buffer); // Some Code ... const auto *ref = Result.Nodes.getNodeAs<DeclRefExpr>("ref"); Stream << "[" << ( HasCapturedArgument ? "=" : "") << "]"; addPlaceholderArgs (Args , Stream); Stream << " return "; ref->printPretty(Stream, nullptr, Result.Context->getPrintingPolicy()); Stream << "("; addFunctionCallArgs (Args , Stream); Stream << "); };"; }
  • 19. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Correzione di errori in check esistenti: modernize-avoid-bind Compilando e rilanciando otteniamo la modifica corretta: int main(int argc , const char * argv []) { auto clj = [=]( auto && arg1) { return A::add(x, arg1); }; } Per evitare la regressione delle modifiche effettuate sono stati creati dei test. La patch `e stata sottoposta agli sviluppatori di Clang che l’hanno testata e accettata.
  • 20. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Creazione di un check: modernize-use-delete Prima dell’avvento dello standard del C++11, per non permettere l’utilizzo di costruttori/distruttori di una classe, li si definiva privati e non implementati. class MyClass{ private: MyClass(const MyClass &); MyClass& operator =( const MyClass &); }; Con il C++11 `e stata introdotta la keyword delete. class MyClass{ public: MyClass(const MyClass &) = delete; MyClass& operator =( const MyClass &) = delete; };
  • 21. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: registerMatchers (MatchFinder *Finder) { if (getLangOpts ().CPlusPlus) { // Distruttore Finder ->addMatcher( cxxDestructorDecl (isPrivate ()).bind( SpecialFunction ),this); Finder ->addMatcher( cxxConstructorDecl ( anyOf(// Costruttore di default allOf(isPrivate (), unless( hasAnyConstructorInitializer (anything ())), parameterCountIs (0)), allOf(// Costruttore di copia isPrivate (),isCopyConstructor (), parameterCountIs (1)))) .bind( SpecialFunction ), this); Finder ->addMatcher(// Operator= cxxMethodDecl(isPrivate (), isCopyAssignmentOperator (), hasParameter (0, hasType( lValueReferenceType ()))) .bind( SpecialFunction ), this); } }
  • 22. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: registerMatchers (MatchFinder *Finder) { if (getLangOpts().CPlusPlus) { // Distruttore Finder ->addMatcher( cxxDestructorDecl (isPrivate ()).bind( SpecialFunction ),this); Finder ->addMatcher( cxxConstructorDecl ( anyOf(// Costruttore di default allOf(isPrivate (), unless( hasAnyConstructorInitializer (anything ())), parameterCountIs (0)), allOf(// Costruttore di copia isPrivate (),isCopyConstructor (), parameterCountIs (1)))) .bind( SpecialFunction ), this); Finder ->addMatcher(// Operator= cxxMethodDecl(isPrivate (), isCopyAssignmentOperator (), hasParameter (0, hasType( lValueReferenceType ()))) .bind( SpecialFunction ), this); } }
  • 23. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: registerMatchers (MatchFinder *Finder) { if (getLangOpts().CPlusPlus) { // Distruttore Finder ->addMatcher(cxxDestructorDecl (isPrivate()).bind( SpecialFunction ),this); Finder ->addMatcher( cxxConstructorDecl ( anyOf(// Costruttore di default allOf(isPrivate (), unless( hasAnyConstructorInitializer (anything ())), parameterCountIs (0)), allOf(// Costruttore di copia isPrivate (),isCopyConstructor (), parameterCountIs (1)))) .bind( SpecialFunction ), this); Finder ->addMatcher(// Operator= cxxMethodDecl(isPrivate (), isCopyAssignmentOperator (), hasParameter (0, hasType( lValueReferenceType ()))) .bind( SpecialFunction ), this); } }
  • 24. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: registerMatchers (MatchFinder *Finder) { if (getLangOpts().CPlusPlus) { // Distruttore Finder ->addMatcher(cxxDestructorDecl (isPrivate()).bind( SpecialFunction ),this); Finder ->addMatcher( cxxConstructorDecl( anyOf(// Costruttore di default allOf(isPrivate(), unless( hasAnyConstructorInitializer (anything ())), parameterCountIs (0)), allOf(// Costruttore di copia isPrivate (),isCopyConstructor (), parameterCountIs (1)))) .bind( SpecialFunction ), this); Finder ->addMatcher(// Operator= cxxMethodDecl(isPrivate (), isCopyAssignmentOperator (), hasParameter (0, hasType( lValueReferenceType ()))) .bind( SpecialFunction ), this); } }
  • 25. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: registerMatchers (MatchFinder *Finder) { if (getLangOpts().CPlusPlus) { // Distruttore Finder ->addMatcher(cxxDestructorDecl (isPrivate()).bind( SpecialFunction ),this); Finder ->addMatcher( cxxConstructorDecl( anyOf(// Costruttore di default allOf(isPrivate(), unless( hasAnyConstructorInitializer (anything ())), parameterCountIs (0)), allOf(// Costruttore di copia isPrivate(),isCopyConstructor(), parameterCountIs (1)))) .bind( SpecialFunction ), this); Finder ->addMatcher(// Operator= cxxMethodDecl(isPrivate (), isCopyAssignmentOperator (), hasParameter (0, hasType( lValueReferenceType ()))) .bind( SpecialFunction ), this); } }
  • 26. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: registerMatchers (MatchFinder *Finder) { if (getLangOpts().CPlusPlus) { // Distruttore Finder ->addMatcher(cxxDestructorDecl (isPrivate()).bind( SpecialFunction ),this); Finder ->addMatcher( cxxConstructorDecl( anyOf(// Costruttore di default allOf(isPrivate(), unless( hasAnyConstructorInitializer (anything ())), parameterCountIs (0)), allOf(// Costruttore di copia isPrivate(),isCopyConstructor(), parameterCountIs (1)))) .bind( SpecialFunction ), this); Finder ->addMatcher(// Operator= cxxMethodDecl(isPrivate(), isCopyAssignmentOperator (), hasParameter (0, hasType( lValueReferenceType ()))) .bind( SpecialFunction ), this); } }
  • 27. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined () || SpecialFunctionDecl ->isDeleted () || SpecialFunctionDecl -> isExplicitlyDefaulted () || SpecialFunctionDecl -> isLateTemplateParsed () || !SpecialFunctionDecl -> isUserProvided () ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint :: CreateInsertion (NewLocation , " = delete"); }
  • 28. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined() || SpecialFunctionDecl ->isDeleted () || SpecialFunctionDecl -> isExplicitlyDefaulted () || SpecialFunctionDecl -> isLateTemplateParsed () || !SpecialFunctionDecl -> isUserProvided () ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint :: CreateInsertion (NewLocation , " = delete"); }
  • 29. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined() || SpecialFunctionDecl ->isDeleted() || SpecialFunctionDecl -> isExplicitlyDefaulted () || SpecialFunctionDecl -> isLateTemplateParsed () || !SpecialFunctionDecl -> isUserProvided () ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint :: CreateInsertion (NewLocation , " = delete"); }
  • 30. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined() || SpecialFunctionDecl ->isDeleted() || SpecialFunctionDecl ->isExplicitlyDefaulted() || SpecialFunctionDecl -> isLateTemplateParsed () || !SpecialFunctionDecl -> isUserProvided () ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint :: CreateInsertion (NewLocation , " = delete"); }
  • 31. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined() || SpecialFunctionDecl ->isDeleted() || SpecialFunctionDecl ->isExplicitlyDefaulted() || SpecialFunctionDecl ->isLateTemplateParsed() || !SpecialFunctionDecl -> isUserProvided () ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint :: CreateInsertion (NewLocation , " = delete"); }
  • 32. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined() || SpecialFunctionDecl ->isDeleted() || SpecialFunctionDecl ->isExplicitlyDefaulted() || SpecialFunctionDecl ->isLateTemplateParsed() || !SpecialFunctionDecl ->isUserProvided() ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint :: CreateInsertion (NewLocation , " = delete"); }
  • 33. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni void UseDeleteCheck :: check(const MatchFinder :: MatchResult &Result) { const auto * SpecialFunctionDecl = Result.Nodes. getNodeAs <CXXMethodDecl >( SpecialFunction ); if (SpecialFunctionDecl ->isDefined() || SpecialFunctionDecl ->isDeleted() || SpecialFunctionDecl ->isExplicitlyDefaulted() || SpecialFunctionDecl ->isLateTemplateParsed() || !SpecialFunctionDecl ->isUserProvided() ) return; // Porzione di codice dove ottengo il nome della funzione speciale PresumedLoc PLoc = Result.SourceManager -> getPresumedLoc (SpecialFunctionDecl ->getLocEnd ()); auto NewLocation = Result.SourceManager -> translateLineCol (Result.SourceManager -> getFileID(SpecialFunctionDecl ->getLocEnd ()), PLoc.getLine (), PLoc.getColumn ()+1); diag(NewLocation ,"Use ’= delete ’ to disable the " + SpecialFunctionName )<< FixItHint:: CreateInsertion (NewLocation , " = delete"); }
  • 34. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Diagnostica e Fix: modernize-use-delete Quello che otteniamo eseguendo il check modernize-use-delete sulla seguente porzione di codice: class MyClass{ private: MyClass(const MyClass &); MyClass& operator =( const MyClass &); }; quello che otteniamo `e il seguente messaggio diagnostico::
  • 35. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Testing di efficacia sulla Parma Polyhedra Library Parma Polyhedra Library (PPL) Libreria di astrazioni numeriche concepita per le applicazioni nel campo dell’analisi e verifica di sistemi complessi. La PPL `e composta da: 78 file d’implementazione (.cc) linee di codice 28· 646 (senza commenti) 366 header file (.hh) linee di codice 129· 602 (senza commenti) Numero totale di righe: 158·248
  • 36. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Risultati ottenuti Check Name Fix Corretti Fix Errati modernize-use-nullptr 247 0 modernize-use-auto 224 0 modernize-use-override 114 0 modernize-use-default 58 0 modernize-pass-by-value 19 2 modernize-use-delete 28 0 modernize-use-emplace 15 0 modernize-replace-auto-ptr 2 0 modernize-redundant-void-arg 2 0 modernize-deprecated-headers 1 0 Clang Tidy agisce su porzioni di codice relativamente semplici. Mentre la PPL per questioni di ottimizzazioni utilizza costrutti complessi.
  • 37. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Conclusioni Il lavoro di tesi ha permesso di studiare le problematiche relative alla modernizzazione del codice mediante checker automatici. Clang Tidy si `e presentato come un interessante progetto open source la cui propriet`a fondamentale `e la modularit`a. Un ottimo strumento di supporto al programmatore nell’attivit`a di modernizzazione del codice C++, anche se ad oggi non `e efficace ed affidabile per essere utilizzato in maniera automatica come software gi`a esistenti.
  • 38. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Sviluppi futuri Nel futuro continuer`o a contribuire allo sviluppo di Clang Tidy, proponendo nuovi check e risolvendo errori nel checker, come nel caso di modernize-pass-by-value. Considerata la difficolt`a iniziale riscontrata nell’utilizzo di Clang Tidy, `e ragionevole pensare allo sviluppo di un’interfaccia grafica che ne semplifichi l’utilizzo.
  • 39. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni GRAZIE PER L’ATTENZIONE !
  • 40. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni
  • 41. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Errore: modernize-pass-by-value Nel testare modernize-pass-by-value si `e riscontrato il seguente errore: //! File iterator_to_const_defs .hh :135 template <typename Container > class Parma_Polyhedra_Library :: const_iterator_to_const { private: //! Constructs from the lower -level const_iterator . const_iterator_to_const (const Base& b); }; Correttamente diventa //! File iterator_to_const_defs .hh :135 template <typename Container > class Parma_Polyhedra_Library :: const_iterator_to_const { private: //! Constructs from the lower -level const_iterator . const_iterator_to_const (Base b); };
  • 42. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Errore: modernize-pass-by-value Lasciando per`o invariata la testata della definizione. //! File iterator_to_const_inline .hh :119 template <typename Container > inline const_iterator_to_const <Container >:: const_iterator_to_const (const Base& b) : base(std:: move(b)) { } Ricompilando tutta la PPL ci accorgiamo che abbiamo degli errori di compilazione.
  • 43. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Commit LLVM Community Figure: Link della revisione: https://reviews.llvm.org/D25649
  • 44. logo.png Modernizzazione del Codice Clang Tidy Estendibilit`a dell’infrastruttura per i check Testing e Conclusioni Commit LLVM Community Prima di rilasciare la patch, `e stato necessario testare che le modifiche apportate al Check, non abbiano aggiunto ulteriori errori e che il checker nel suo insieme fosse ancora stabile. LLVM dispone di una suite di test. In particolari quelli del pacchetto modernize sono locati nella directory /llvm/tools/clang/tools/extra/test/clang-tidy. Nel file modernize-avoid-bind.cpp sono state aggiunte le seguenti istruzioni: namespace C { int add(int x, int y){ return x + y; } } void n(){ auto clj = std:: bind(C::add , 1, 1); // CHECK -MESSAGES: :[[ @LINE -1]]:16: warning: prefer a lambda to std:: bind // CHECK -FIXES: auto clj = [] { return C::add(1, 1); }; }