Applications et principales méthodes de la recherche de similitudes
Nous présentons ici les problématiques et applications majeures de la recherche statique de similitudes sur du code source. La recherche de correspondances ainsi que la mise au point de métriques de comparaison entre unités de compilation trouvent leurs applications dans des domaines tels que la recherche de plagiat sur des logiciels commerciaux, l’évaluation de projets d’étudiants ou la factorisation de code intra-projet pour faciliter la maintenance. Nous évo- quons également quelques méthodes généralement utilisées pour ces différentes applications ; certaines d’entre-elles seront plus précisément décrites dans les parties II et III consacrées à la recherche de similarité sur du code source respectivement représenté par une séquence de lexèmes ou un arbre syntaxique. Un bon style de programmation requiert d’éviter dans la mesure du possible l’existence de code dupliqué au sein de projets dans une vision à long terme. En effet, la présence de clones entraîne une augmentation du volume du projet et nécessite ainsi un coût de maintenance plus important. Elle occasionne des problèmes potentiels concernant la fiabilité et la sécurité du projet puisqu’un problème éventuel survenant sur un exemplaire d’une portion de code dupliqué donnant lieu à un correctif pourra ne pas être examiné sur d’autres exemplaires co- piés. L’introduction de code dupliqué peut toutefois présenter un intérêt à court terme [99] (par exemple dans le cadre de variations expérimentales de code avec amélioration de perfor- mance, d’adaptation rapide à différentes architectures matérielles…). Si une bonne discipline du programmeur permet d’éviter les clones les plus importants, il demeure possible, sur des projets réalisés par de multiples protagonistes, de noter l’apparition de clones accidentels, i.e. des portions de code dont le rôle est identique avec une implantation similaire. Il est alors souhaitable d’organiser et de factoriser ces morceaux de code au sein de bibliothèques.
Il est ainsi nécessaire dans un premier temps de parvenir à la détection des portions de code dupliquées. En règle générale, les clones sont générés par copier-coller suivi de quelques éditions afin de pouvoir les adapter à un nouveau contexte (modification de types de variables, ajout ou suppression d’instructions, réécriture de certaines expressions, …). Si la détection de clones exacts est relativement aisée pour une représentation donnée du code, la recherche de correspondances approchées nécessite l’utilisation d’algorithmes de complexité plus importante ou alors l’emploi de certaines heuristiques. Les clones (qu’ils soient exacts ou approchés) reportés, il demeure important de s’interroger sur leur pertinence dans une optique de factorisation de code. Dans certains cas, il est pos- sible d’automatiser la factorisation de clones exacts par la création de nouvelle fonction et le remplacement de chaque exemplaire du clone par une appel à cette fonction. Cette opération peut potentiellement occasionner une dégradation du temps d’exécution liée au surcoût des appels de fonction. Néanmoins, il est à noter que si le code est compilé, le code objet gé- néré peut remplacer les sites d’appel par un développement du corps de la fonction à des fins d’optimisation. Dans un contexte général, l’automatisation de la factorisation de clones approchés n’est pas possible car nécessitant un degré de compréhension sémantique. Il est possible qu’un clone reporté ne soit pas pertinent selon le degré d’abstraction utilisé pour la recherche de similarité. Dans le cas contraire, le clone peut faire l’objet d’une élimination par factorisation mais peut nécessiter une compréhension sémantique humaine pour la mise au point des fonctions partagées. Un outil de détection de code similaire apparaît alors comme une aide au repérage de zones pouvant potentiellement être concernées par une procédure de factorisation.
Une bonne organisation modulaire du code participe à la limitation de redondances de code au sein d’un projet. Il demeure néanmoins difficile d’isoler des portions de code liées à des préoccupations transversales de forte ubiquité dans les différents modules (e.g. : gestion d’erreurs, journalisation d’événements, gestion d’autorisations…). Il en émerge des morceaux de code idiomatiques présents partagés en de nombreux exemplaires à travers les modules, avec plus ou moins d’opérations d’éditions, pouvant être potentiellement recherchés par des outils de recherche de similitude [97] lorsque leur localisation n’est pas formalisée par l’usage d’un langage orienté aspect. Une autre motivation pouvant conduire à la recherche de similarité au sein d’un même projet est le suivi d’évolution d’un projet entre plusieurs versions [80]. En effet, l’évolution d’un projet n’est pas nécessairement modélisée par une succession linéaire de versions : l’apparition de plusieurs branches d’évolution indépendante est également possible [98]. Dans ces conditions, le suivi des éditions réalisées entre des portions de code similaires entre les versions d’une même branche ou de branches différentes demeure indispensable. Outre la modélisation des évolutions destinée à être lisible par un humain, il permet la conception de formats de stockage pour limiter la taille de référentiels de code source. Les méthodes d’analyse de similarités et de différences entre sources peuvent être d’application globale par l’analyse en une unique passe d’un arbre de versions d’un projet, ou bien être incrémentales par la mise à jour de structures de données à chaque nouvelle version ajoutée.