Qualité de
code Java
Eric Bui
Régis Clavel
Matthieu Damerose
Sébastien Grivolat
Hakim Maadadi
Christophe Safra
Arnaud Schulz
Jérôme Valentin
ESSI3 Juin 1999
Retour au CV.
Manuel utilisateur.
Diapositives.
Télécharger les diapositives
(zip d'un fichier PowerPoint).
Sebastien.Grivolat@free.fr
Remarque : Vous revenez au sommaire par les titres !
Retour au CV.
QUELQUES TERMES TECHNIQUES
Introduction
1. Généralités
Le but de ce projet est la réalisation d’un outil de vérification de qualité de code pour le langage Java. De tels outils sont de plus en plus nécessaires afin de contrôler la qualité du code et ainsi, fournir un code propre et bien commenté permettant une maintenance et une réutilisabilité accrue du programme.
Il intègre deux types de fonctionnalités: des fonctions de métriques sur le code et des fonctions d’analyse.
C’est donc dans cet objectif que s’intègre notre outil d’analyse de code Java. Pour cela, il nous faut définir des critères à respecter afin que le code soit correct. Pour les critères, nous nous sommes inspirés des conseils de nos professeurs lors des cours ainsi que de EnvyQA, un outil existant pour le langage Smalltalk. Il offre à l’utilisateur, la possibilité de définir des règles qui doivent être vérifiées dans le code.
Nous avons ainsi déterminé une vingtaine de points à vérifier concernant:
Nous avons aussi choisi de donner des informations plus générales:
Un tel outil permet une analyse du code source fourni par l’utilisateur. Afin d’éviter tous les problèmes liés aux éventuelles erreurs de programmation, un des prérequis de notre programme est de lui fournir des programmes syntaxiquement et sémantiquement corrects, c'est à dire compilables.
Nous allons donc dans un premier temps voir les différentes solutions possibles pour implémenter un tel logiciel (§1), détailler les structures à rajouter qui seront nécessaires (§2), les différents traitements qui seront effectués sur le code fourni (§3), et les autres aspects du développement (§4). Enfin, nous aborderons la répartition du travail dans le groupe (§5) pour conclure par les problèmes que nous avons rencontrés (§6).
1. Généralités
Nous allons dans un premier temps expliquer le cheminement qui nous a conduit à la solution technique utilisée dans notre logiciel.
1.1. Analyse rapide du sujet
Notre projet est basé sur l'analyse de code, il nous est donc nécessaire d'utiliser les techniques de compilation étudiées en cours.
Mais quelle est exactement la phase de compilation que nous utiliserons ?
La réponse est fonction des traitements, cependant l'analyse nécessite un parser dans tous les cas. Pour les traitements les plus complexes, masquage des variables par exemple, il nous faudra également un type checking.
Ensuite nous avons dû décider quelles fonctions il nous serait possible de coder en fonction du temps accordé. Donc nous avons évalué la complexité et le temps pour l'implémentation de chaque fonctionnalité ( les problèmes de répartition seront évoqués au §5 ).
Finalement nous avons décidé de la présentation des résultats, des entrées sorties de notre outil.
1.2. Solutions proposées
private static Vector // contient la liste des traitements
public static addTraitement ()
public static ajouterNoeudAuxTraitement ()
public static lanceTraitement ()
public static recupResult ()
vecteur nœuds // la liste des nœuds auxquels appliquer le traitement
addNoeud ()
startTraitement ()
recupResult ()
NodeJavaQA
IsInterestedByT1() return no;
IsInterestedByT2() return no;
...
IsInterestedByTn() return no;
XXX étant le nom d'un nœud existant, comme WhileStatement :
Javaqa.noeudjavaqa.ConstructorTheo
public class ConstructorTheo {
protected MemberDefinition co; //le constructeur lié
public ConstructorTheo(MemberDefinition md) ;
public MemberDefinition getMemberDefinition () ; // retourne le constructeur lié
// Dans le cas d'un constructeur on peut descendre a son "fils" qui est super(...) ou this(...)
public Expression firstConstructor () ;
public ClassDefinition getClassDefinition () ; // retourne la classe du constructeur lié
public ClassDeclaration getClassDeclaration () ;
public String getClassName() ; // retourne le nom de la classe du constructeur lié
public String getName () ; // retourne le nom (long) du constructeur lié
public String getSourceName () ; // retourne le nom du fichier contenant le constructeur lié
// Verifier si "super()" a été rajoute a un constructeur par le compilateur
// Procede: comparaison des numéros de ligne et d'offset du super() par rapport au constructeur
public boolean haveAddedSuper () ;
public String toString() ;
}
public class NommageClass extends Nommage {
/** Message d'erreur de nommage non vérifié */
public static final String NOMME = "Nommage de classes non respecte !";
private NommageClass () ;
public NommageClass (String ) ;
public NommageClass (String , boolean) ;
public NommageClass (String, boolean, boolean ) ;
public boolean aVerifier (ClassDeclaration) ;
public boolean aVerifier (ClassDefinition) ;
/**
* Verification du nommage
*/
public boolean verifier (ClassDefinition ) ;
public boolean verifier (ClassDeclaration ) ;
}
public class Nommage {
protected RegexpTheo regle;
protected boolean upper_case;
protected boolean lower_case;
protected Nommage () ;
public Nommage (String ) ;
public Nommage (String, boolean ) ;
public Nommage (String, boolean, boolean ) ;
public String getExp ()
/**
* test si l'objet o doit etre verifie
* fonction par defaut
*/
public boolean aVerifier (Object) ;
/** matching */
protected boolean verifierString (String ) ;
}
Diagramme de Gant de la répartition des tâches.
| Traitement | 1er essai (ms) | 2ème essai (ms) | Moyenne |
| Corps des méthodes vides | 610 | 1512 | 1061 |
| Vérification nommage | 360 | 300 | 330 |
| Classes utilisables | 50 | 80 | 65 |
| Fermeture transitive | 110 | 90 | 100 |
| Classes sans constructeurs | 20 | 40 | 30 |
| Présence de super | 1623 | 1121 | 1372 |
| Variables masquées | 390 | 231 | 310,5 |
| Commentaires | 40 | 80 | 60 |
| Accesseurs | 81 | 130 | 105,5 |
| Variables non utilisées | 20 | 10 | 15 |
| Méthodes identiques | 80 | 20 | 50 |
| Variables en dur | 120 | 110 | 115 |
| Méthodes inutiles | 230 | 381 | 305,5 |
| Arguments inutiles | 40 | 50 | 45 |
| Couplage des classes | 110 | 180 | 145 |
| Profondeur d'une classe | 20 | 20 | 20 |
| Usage de la Réflexivité | 10 | 30 | 20 |
| Nombre de membres par classe | 20 | 41 | 30.5 |
| Imports utiles | 350 | 550 | 450 |
| Casts inutiles | 60 | 30 | 45 |
| Total | 4344 | 5008 | 4676 |
| Soit en % du temps total | 7.5% | 8.78% | 8.14% |
| Constructeur de ROOT | 18005 | 17950 | 17977,5 |
| Total pour nous | 22349 | 22958 | 22653,5 |
| Soit en % du temps total | 38.70% | 40.26% | 39.48% |
| Programme complet | 57743 | 57022 | 57382,5 |