Avec une échelle comme la taille de la base de code de l'OP, ce qui est nécessaire est un program transformation system (PTS). C'est un outil qui analyse un fichier source de langage cible dans des structures de données de compilateur (habituellement des AST), vous permet d'appliquer des transformations aux ASTs, puis de régénérer un code source valide incluant les commentaires originaux pour le programme modifié. Pensez à PST comme des outils pour refactoring dans le grand.
Un bon PTS vous permettra d'écrire source-source transforme de la forme:
when you see *this*, replace it by *that* if *condition*
où ce et que sont exprimés dans la syntaxe de la langue cible, où ce correspond uniquement si le code source correspond à la syntaxe explicite. [Ce ne sont pas des correspondances de chaînes; ils travaillent sur les AST, donc la mise en page n'affecte pas leur capacité à correspondre].
Vous avez besoin d'une règle clé qui ressemble à ceci:
rule move_to_initializer(constructor_name:IDENTIFIER,
arguments: argument_list,
initializer_list: initializer,
member_name:IDENTIFIER,
initializer_expression: expression,
statements: statement_list
): constructor -> constructor =
" \constructor_name(\arguments): \initializer_list
{ \member_name = \initializer_expression ;
\statements } "
-> " \constructor_name(\arguments): \initializer_list, \member_name(\initializer_expression)
{ \statements } ";
The syntax of these rules/patterns for our DMS Software Reengineering Toolkit is explained here. DMS est le seul PTS source-à-source que je connaisse capable de gérer C++; il gère même le dialecte MSVS].
J'ai omis une éventuelle "if condition" vérifier que le nom de membre est bien un membre de la classe, en supposant que vos constructeurs ne sont pas abusifs.
Parce que vos constructeurs ne peuvent pas avoir une liste d'initialisation, vous avez besoin d'une règle d'aide pour introduire un si nécessaire:
rule move_to_initializer(constructor_name:IDENTIFIER,
arguments: argument_list,
member_name:IDENTIFIER,
initializer_expression: expression,
statements: statement_list
): constructor -> constructor =
" \constructor_name(\arguments)
{ \member_name = \initializer_expression ;
\statements } "
-> " \constructor_name(\arguments): \member_name(\initializer_expression)
{ \statements } ";
{ \member_name = \e ; } "
Invariablement vous avez besoin des règles supplémentaires pour couvrir d'autres cas particuliers, mais il ne devrait pas être plus quelques.
En ce qui concerne le contrôle sur d'ordre de l'initialisation, vous pouvez déclencher un tel contrôle à l'aide d'un (DMS) modèle:
pattern check_initializer_order(constructor_name:IDENTIFIER,
initializer_list: initializer,
statements: statement_list
): constructor =
" \constructor_name(): \initializer_list,
{ \statements } "
if complain_if_not_ordered(constructor_name,initializer_list);
qui nécessite une méta-prédicat auxiliaire qui vérifie l'ordre, qui se plaint si elles sont mal coordonné. Vous avez besoin de constructor_name pour permettre au prédicat de rechercher la classe correspondante et d'inspecter l'ordre des membres. [DMS fournit le means to access a symbol table avec cette information].
Alternativement, vous pouvez tout simplement réordonner les utiliser une règle de réécriture différente:
rule order_initializers(constructor_name:IDENTIFIER,
arguments: argument_list,
initializer_list_prefix: initializer,
initializer_list_suffix: initializer,
member1_name:IDENTIFIER,
initializer1_expression: expression,
member2_name:IDENTIFIER,
initializer2_expression:expression,
statements: statement_list
): constructor -> constructor =
" \constructor_name(\arguments):
\initializer_list_prefix,
\member1_name(\initializer1),
\member2_name(\initializer2),
\initialize_list_suffix
{ \statements } "
->
" \constructor_name(\arguments):
\initializer_list_prefix,
\member2_name(\initializer2),
\member1_name(\initializer1),
\initialize_list_suffix
{ \statements } "
if is_wrong_order(constructor_name,member1_name,member2_name);
Cette règle trie essentiellement les initialiseurs. [Notez qu'il s'agit d'une sorte de bulle: mais les listes d'initialisation ont tendance à ne pas être longues, et vous ne l'exécuterez qu'une fois par constructeur.] Vous devriez exécuter cette règle après avoir levé tous les initialiseurs du corps du constructeur en utilisant les règles montrées plus tôt.
Comme pour la deuxième partie: GCC a '-Wreorder'. – Biffen
@Biffen fait Visual Studio 2012? Comme c'est ce que j'utilise. – fwgx
Pas que je sache, et un google rapide n'a rien donné. Je vais vous laisser faire plus de recherches à ce sujet. – Biffen