Nettoyer les includes C/C++ dans Visual Studio

À compter de Visual Studio 17.8 Preview 1, Visual Studio fournit une fonctionnalité de nettoyage des #include qui améliore la qualité de votre code de la manière suivante :

  • Offre d’ajouter des fichiers d’en-tête pour le code qui se compile uniquement, car un fichier d’en-tête nécessaire est inclus indirectement par un autre fichier d’en-tête.
  • Propose de supprimer les fichiers d’en-tête inutilisés, ce qui améliore les temps de génération et la propreté du code.

Include Cleanup est activé par défaut. Pour savoir comment le configurer, consultez Configurer Include Cleanup pour C/C++ dans Visual Studio.

En-têtes directs et indirects

Tout d’abord, une terminologie :

  • Un en-tête direct est un en-tête que vous avez explicitement #include dans votre code.
  • Un en-tête indirect est un en-tête que vous n’avez pas explicitement #include. Au lieu de cela, un fichier d’en-tête que vous incluez directement l’inclut. Nous disons également qu’un en-tête indirect est inclus transitively.

Include Cleanup analyse votre code et détermine quels en-têtes ne sont pas utilisés et lesquels sont indirectement inclus. Considérez le fichier d’en-tête suivant :

// myHeader.h

#include <string>
#include <iostream>

void myFunc()
{
    std::string s = "myFunc()\n";
    std::cout << s;
}

Et le programme qui l’utilise :

// myProgram.cpp
#include "myHeader.h"

int main()
{
    std::string s = "main()"; // string is indirectly included by myHeader.h
    std::cout << s; // cout is indirectly included by myHeader.h
    myFunc();
}

myHeader.h est un en-tête direct, car myProgram.cpp l’inclut explicitement. myHeader.h inclut <string> et <iostream>, de sorte qu’il s’agit d’en-têtes indirects.

Le problème est que myProgram.cpp utilise std::string et std::cout, mais n’inclut pas directement les en-têtes qui les définissent. Ce code compile, car myHeader.h inclut ces en-têtes. Ce code est fragile, car si myHeader.h arrêtait d’inclure l’un ou l’autre, myProgram.cpp ne compilerait plus.

Conformément aux instructions C++, il est préférable d’inclure explicitement des en-têtes pour toutes vos dépendances afin que votre code ne soit pas soumis à une fragilité causée par les modifications apportées aux fichiers d’en-tête. Pour plus d’informations, consultez C++ Core Guidelines SF.10.

Include Cleanup analyse votre code pour identifier les en-têtes inutilisés et indirectement inclus. Il fournit des commentaires basés sur les paramètres décrits dans Configurer l’outil #include C++ dans Visual Studio. Les commentaires peuvent être sous la forme d’avertissements de liste d’erreurs, de suggestions, etc. Pour plus d’informations sur les commentaires fournis par Include Cleanup, reportez-vous aux messages Include Cleanup.

En-têtes inutilisés

À mesure que votre code évolue, vous n’avez peut-être plus besoin de certains fichiers d’en-tête. Cela est difficile à suivre dans un projet complexe. Au fil du temps, vos builds peuvent prendre plus de temps, car le compilateur traite les fichiers d’en-tête inutiles. Include Cleanup vous permet de rechercher et de supprimer des en-têtes inutilisés. Par exemple, que se passe-t-il si myFunc() est commenté dans myProgram.cpp :

// myProgram.cpp
#include "myHeader.h"

int main()
{
    std::string s = "main()"; // string is indirectly included from myHeader.h
    std::cout << s; // cout is indirectly included from myHeader.h
    // myFunc(); // directly included from myHeader.h
}

Dans la capture d’écran suivante, #include "myHeader.h" est grisé (un paramètre décrit dans Configurer l’outil #include C++ dans Visual Studio), car il n’est pas utilisé, étant donné que myFunc() est commenté.

Placez le curseur sur le #include grisé pour afficher le menu d’action rapide. Cliquez sur l’ampoule (ou choisissez le lien Afficher les correctifs potentiels) pour afficher les actions liées au fichier inutilisé :

Three refactoring options are shown: Remove # include myHeader.h, remove all unused includes, and Add all transitively used and remove all unused # includes.

Ajouter des en-têtes utilisés transitivement

Nous pourrions choisir de supprimer le fichier d’en-tête inutilisé, mais cela casse le code étant donné que <string> et <iostream> sont indirectement inclus via myheader.h.

Au lieu de cela, nous pouvons choisir Ajouter tous les #includes utilisés transitivement et supprimer tous les #includes inutilisés. Cela supprime l’en-tête myHeader.h inutilisé, mais ajoute également tous les en-têtes utilisés indirectement inclus via myHeader.h. Le résultat, dans ce cas, est l’ajout de #include <string> et #include <iostream> à myProgram.cpp, et la suppression de #include "myHeader.h" :

// myProgram.cpp
#include <iostream>
#include <string>

int main()
{
    std::string s = "main()"; // string is directly included from <string>
    std::cout << s; // cout is directly included from <string>
    // MyFunc();
}

L’outil ne met pas à jour les commentaires, mais vous pouvez voir que le code utilise maintenant std::string et std::cout directement. Ce code n’est plus fragile, car il ne dépend pas de myHeader.h pour inclure les autres en-têtes requis.

Bonnes pratiques

Ne supprimez pas ce qui semble être des fichiers d’en-tête inutilisés sans ajouter d’abord des fichiers d’en-tête inclus indirectement. Cela est dû au fait que votre code peut s’appuyer sur des includes indirects dans un fichier d’en-tête qui n’est pas utilisé. Ajoutez d’abord des en-têtes utilisés transitivement. Ensuite, lorsque vous supprimez des en-têtes inutilisés, vous n’obtenez pas d’erreurs de compilation en raison de fichiers d’en-tête manquants inclus indirectement par un fichier d’en-tête que vous avez supprimé.

Pour ce faire, définissez le paramètre Include Cleanup pour Niveau de suggestion d’ajout d’includes manquant sur Suggestion (Outils>Options>Éditeur de texte>C/C++>Nettoyage du code). Définissez également Niveau de suggestion de suppression d’includes inutilisés sur Suggestion. Ensuite :

  1. Dans la liste d’erreurs, vérifiez que le filtre est défini sur Build + IntelliSense.
  2. Recherchez les instances de « Contenu de #include x est utilisé dans ce fichier et inclus transitivement ».
  3. Placez votre curseur sur une ligne avec la suggestion. Dans la liste déroulante de l’ampoule, sélectionnez Ajouter tous les includes utilisés transitivement.
  4. Répétez ces étapes dans votre projet jusqu’à ce que toutes les suggestions concernant les includes transitifs soient traitées.
  5. Supprimez les includes inutilisés : dans la liste d’erreurs, recherchez une instance de « #include x n’est pas utilisé dans ce fichier ».
  6. Placez le curseur sur l’en-tête inutilisé. Dans la liste déroulante de l’ampoule, sélectionnez Supprimer tous les includes inutilisés.
  7. Répétez ces étapes dans votre projet jusqu’à ce que toutes les suggestions de Include Cleanup soient traitées.

Dans cette brève vue d’ensemble, vous avez vu comment Include Cleanup peut vous aider à supprimer des en-têtes inutilisés et à ajouter des en-têtes qui ont été inclus indirectement. Cela vous permet de conserver votre code propre, de générer potentiellement plus rapidement et de réduire la fragilité de votre code.

Voir aussi

Configurer Include Cleanup pour C/C++ dans Visual Studio
Messages Include Cleanup