C++ refactoring: conditional expansion and block elimination

前端 未结 2 914
无人共我
无人共我 2021-01-19 00:03

I\'m in the process of refactoring a very large amount of code, mostly C++, to remove a number of temporary configuration checks which have become permanantly set to given v

2条回答
  •  一向
    一向 (楼主)
    2021-01-19 00:55

    It sounds like you have what I call "zombie code"... dead in practice, but still live as far as the compiler is concerned. This is a pretty common issue with most systems of organized runtime configuration variables: eventually some configuration variables arrive at a permanent fixed state, yet are reevaluated at runtime repeatedly.

    The cure isn't regex, as you have noted, because regex doesn't parse C++ code reliably. What you need is a program transformation system. This is a tool that really parses source code, and can apply a set of code-to-code rewriting rules to the parse tree, and can regenerate source text from the changed tree.

    I understand that Clang has some capability here; it can parse C++ and build a tree, but it does not have source-to-source transformation capability. You can simulate that capability by writing AST-to-AST transformations but that's a lot more inconvenient IMHO. I believe it can regenerate C++ code but I don't know if it will preserve comments or preprocessor directives.

    Our DMS Software Reengineering Toolkit with its C++(11) front end can (and has been used to) carry out massive transformations on C++ source code, and has source-to-source transformations. AFAIK, it is the only production tool that can do this. What you need is a set of transformations that represent your knowledge of the final state of the configuration variables of interest, and some straightforward code simplification rules. The following DMS rules are close to what you likely want:

      rule fix_value1():expression->expression
        "value1()" -> "true";
      rule fix_value2():expression->expression
        "value2()" -> "false";
      rule fix_value3():expression->expression
        "value3()" -> "4";
    
      rule simplify_boolean_and_true(r:relation):condition->condition
         "r && true" -> "r".
      rule simplify_boolean_or_ture(r:relation):condition->condition
         "r || true" -> "true".
      rule simplify_boolean_and_false(r:relation):condition->condition
         "r && false" -> "false".
      ...
      rule simplify_boolean_not_true(r:relation):condition->condition
         "!true" -> "false".
      ...
    
      rule simplify_if_then_false(s:statement): statement->statement
          " if (false) \s" -> ";";
      rule simplify_if_then_true(s:statement): statement->statement
          " if (true) \s" -> "\s";
      rule simplify_if_then_else_false(s1:statement, s2:statement): statement->statement
          " if (false) \s1 else \s2" -> "\s2";
      rule simplify_if_then_else_true(s1:statement, s2: statement): statement->statement
          " if (true) \s1 else \s2" -> "\s2";
    

    You also need rules to simplify ("fold") constant expressions involving arithmetic, and rules to handle switch on expressions that are now constant. To see what DMS rules look like for integer constant folding see Algebra as a DMS domain.

    Unlike regexes, DMS rewrite rules cannot "mismatch" code; they represent the corresponding ASTs and it is that ASTs that are matched. Because it is AST matching, they have no problems with whitespace, line breaks or comments. You might think they could have trouble with order of operands ('what if "false && x" is encountered?'); they do not, as the grammar rules for && and || are marked in the DMS C++ parser as associative and commutative and the matching process automatically takes that into account.

    What these rules cannot do by themselves is value (in your case, constant) propagation across assignments. For this you need flow analysis so that you can trace such assignments ("reaching definitions"). Obviously, if you don't have such assignments or very few, you can hand patch those. If you do, you'll need the flow analysis; alas, DMS's C++ front isn't quite there but we are working on it; we have control flow analysis in place. (DMS's C front end has full flow analysis).

    (EDIT February 2015: Now does full C++14; flow analysis within functions/methods).

    We actually applied this technique to 1.5M SLOC application of mixed C and C++ code from IBM Tivoli almost a decade ago with excellent success; we didn't need the flow analysis :-}

提交回复
热议问题