C++;重构:条件扩展和块消除 我正在重构大量代码,主要是C++,以删除一些临时配置检查,这些临时配置检查已经永久设置为给定值。例如,我有以下代码: #include <value1.h> #include <value2.h> #include <value3.h> ... if ( value1() ) { // do something } bool b = value2(); if ( b && anotherCondition ) { // do more stuff } if ( value3() < 10 ) { // more stuff again }

C++;重构:条件扩展和块消除 我正在重构大量代码,主要是C++,以删除一些临时配置检查,这些临时配置检查已经永久设置为给定值。例如,我有以下代码: #include <value1.h> #include <value2.h> #include <value3.h> ... if ( value1() ) { // do something } bool b = value2(); if ( b && anotherCondition ) { // do more stuff } if ( value3() < 10 ) { // more stuff again },c++,refactoring,automated-refactoring,C++,Refactoring,Automated Refactoring,问题是,我要做数百(可能数千)个更改,才能从第二个正确但愚蠢的阶段获得最终清理的代码 我想知道是否有人知道可以处理这个问题的重构工具,或者我可以应用的任何技术。主要的问题是C++语法使得完全扩展或消除很难实现,并且上面的代码有很多排列。我觉得我几乎需要一个编译器来处理我需要涵盖的语法变化 我知道也有类似的问题,但我找不到任何类似的要求,我还想知道在被问到之后是否出现了任何工具或程序?你说: 请注意,虽然这些值是合理固定的,但它们不是在编译时设置的,而是从共享内存中读取的,因此编译器目前没有在幕后

问题是,我要做数百(可能数千)个更改,才能从第二个正确但愚蠢的阶段获得最终清理的代码

我想知道是否有人知道可以处理这个问题的重构工具,或者我可以应用的任何技术。主要的问题是C++语法使得完全扩展或消除很难实现,并且上面的代码有很多排列。我觉得我几乎需要一个编译器来处理我需要涵盖的语法变化

我知道也有类似的问题,但我找不到任何类似的要求,我还想知道在被问到之后是否出现了任何工具或程序?

你说:

请注意,虽然这些值是合理固定的,但它们不是在编译时设置的,而是从共享内存中读取的,因此编译器目前没有在幕后优化任何内容

手动不断地折叠这些值没有多大意义,除非它们是完全固定的。如果编译器提供,您可以使用它,也可以在预处理器宏中替换如下内容:

#define value1() true
#define value2() false
#define value3() 4
优化器将从那里照顾您。在没有看到
标题中确切内容的示例,也不知道从共享内存中获取这些值的过程是如何工作的情况下,我只想指出,重命名现有的valueX()函数并进行运行时检查可能很有用,以防将来再次更改:

// call this at startup to make sure our agreed on values haven't changed
void check_values() {
    assert(value1() == get_value1_from_shared_memory());
    assert(value2() == get_value2_from_shared_memory());
    assert(value3() == get_value3_from_shared_memory());
}

听起来你有我所谓的“僵尸代码”。。。在实践中死亡,但就编译器而言仍然活着。对于大多数有组织的运行时配置变量系统来说,这是一个非常常见的问题:最终一些配置变量会达到一个永久固定的状态,但在运行时会反复重新评估

< >您注意到,治疗不是正则表达式,因为正则表达式不可靠地解析C++代码。 你需要的是一份工作。这是一个真正解析源代码的工具,可以将一组代码重写规则应用于解析树,并可以从更改的树中重新生成源文本

我知道Clang在这里有一些能力;它可以解析C++和构建树,但它没有源到源转换能力。您可以通过编写AST到AST的转换来模拟这种能力,但这会给IMHO带来很多不便。我相信它可以再生C++代码,但我不知道它是否会保留注释或预处理器指令。

我们用它的CAN(已经习惯)对C++源代码进行大规模的转换,并有源到源转换。好吧,这是唯一能做到这一点的生产工具。您需要的是一组表示您对感兴趣的配置变量的最终状态的了解的转换,以及一些简单的代码简化规则。以下DMS规则与您可能想要的非常接近:

  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";
您还需要规则来简化涉及算术的(“折叠”)常量表达式,并需要规则来处理现在是常量的表达式上的开关。要查看整数常量折叠的DMS规则,请参阅

与正则表达式不同,DMS重写规则不能“不匹配”代码;它们表示对应的AST,匹配的正是该AST。因为它是AST匹配,所以它们在空格、换行符或注释方面没有问题。您可能认为它们可能在操作数顺序方面有问题('如果遇到“false&&x”怎么办?');它们没有,因为在DMS C++解析器中标记了<强> &和>和强>和<强>><强>的语法规则作为关联和交换,匹配过程自动地将这一点考虑在内。

这些规则本身不能做的是跨赋值的值传播(在您的例子中是常量)。为此,您需要流分析,以便跟踪此类分配(“到达定义”)。显然,如果你没有这样的任务或任务很少,你可以手工修补。如果你这样做了,你将需要流量分析;唉,DMS的C++前端并不完全存在,但我们正在努力工作。我们有控制流分析。(DMS的C前端具有全流分析功能)

(2015年2月编辑:现在进行完整的C++14;函数/方法中的流分析)


我们在IBM蒂沃丽花园近十年前,将这项技术实际应用到混合C和C++代码的1.5 m SLoc中,取得了巨大的成功。我们不需要流分析:-}

谢谢,我的措辞很糟糕:它们是固定的,不会改变,但在编译时不会。我喜欢替换的想法,这样编译器就可以优化了,我已经通过正则表达式替换自动实现了这一点。然而,其中一个目的是删除代码“cruft”-有很多代码块,有些代码块相当大,一旦值被固定,这些代码块将完全冗余,如果它也能从源代码中自动删除,那将是一件好事。如果你很难在脑海中计算表达式,一个穷人寻找不可访问代码的测试方法是遵循我的建议,然后使用类似于gcc的
-Wunreachable code
警告(即使使用
-Wall
,警告通常也是关闭的)。我猜想,C++中的任何免费代码重写工具都会对你造成影响。如果你担心你可能会犯错误,那就不要一次就把它全部替换掉……把这些表达式提出来,在你的简化中坚持它们的相等性。是的,这正是我想要的。正则表达式可以让我明白很多,但它们是不精确的,就像你说的,crucia
// call this at startup to make sure our agreed on values haven't changed
void check_values() {
    assert(value1() == get_value1_from_shared_memory());
    assert(value2() == get_value2_from_shared_memory());
    assert(value3() == get_value3_from_shared_memory());
}
  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";