我在源代码迁移中,转换器程序没有将嵌入字符串的串联转换为整数。现在我有很多代码用这种表达式:
f("some text" + i);
由于C / C ++会将此解释为数组下标,f
将收到"some text"
,"ome text"
或"me text"
...
我的源语言将字符串的串联转换为字符串连接。现在我需要逐行浏览源代码并手动将前一个表达式更改为:
f("some text" + std::to_string(i));
转化计划设法转换本地" String
"变量到" std::string
",产生表达式:
std::string some_str = ...;
int i = ...;
f(some_str + i);
这些很容易修复,因为有了这样的表达式,C ++编译器会输出错误。
是否有任何工具可以在源代码中自动找到这样的表达式?
答案 0 :(得分:8)
轻松!只需将所有+
替换为-&
:
find . -name '*.cpp' -print0 | xargs -0 sed -i '' 's/+/-\&/g'
在尝试编译项目时,您会在其他错误之间看到类似这样的内容:
foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
return f(s -& i);
~ ^~~~
(我使用clang,但其他编译器应该发出类似的错误)
因此,您只需过滤编译器输出以仅保留这些错误:
clang++ foo.cpp 2>&1 | grep -F "error: 'const char *' and 'int *' are not pointers to compatible types"
你得到:
foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
foo.cpp:18:10: error: 'const char *' and 'int *' are not pointers to compatible types
答案 1 :(得分:7)
您可以尝试flint,这是在Facebook开发和使用的C ++开源lint程序。它具有列入黑名单的令牌序列功能(checkBlacklistedSequences
)。您可以将令牌序列添加到checkBlacklistedSequences
功能,flint
会报告它们。
在checkBlacklistedSequences
函数中,我添加了序列string_literal + number
BlacklistEntry([tk!"string_literal", tk!"+", tk!"number"],
"string_literal + number problem!\n",
true),
然后编译并测试
$ cat -n test.cpp
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 void f(string str)
7 {
8 cout << str << endl;
9 }
10
11 int main(int argc, char *argv[])
12 {
13 f("Hello World" + 2);
14
15 f("Hello World" + std::to_string(2));
16
17 f("Hello World" + 2);
18
19 return 0;
20 }
$ ./flint test.cpp
test.cpp(13): Warning: string_literal + number problem!
test.cpp(17): Warning: string_literal + number problem!
flint
有两个版本(旧版本用C ++开发,新版本用D语言开发),我在D版本中进行了更改。
答案 2 :(得分:3)
我不熟悉很多可以做到这一点的工具,但我认为grep
在某些方面可能会有所帮助。
在源代码的根目录中,尝试:
grep -rn '".\+"\s*+\s*' .
,它可以找出包含像"xxxxx" +
这样的行的所有文件,希望这可以帮助您找到所需的所有行。
如果所有整数都是常数,则可以将grep experssion改为:
grep -rn '".\+"\s*+\s*[0-9]*' .
您还可以在字符串常量之前包含(
:
grep -rn '(".\+"\s*+\s*[0-9]*' .
这可能不是“正确”的答案,但我希望这可以帮到你。
答案 3 :(得分:2)
您可能不需要外部工具。相反,您可以利用C ++单用户定义转换规则。基本上,您需要将f
函数的参数从const char*
/ std::string
更改为只能从字符串文字(const char[size]
)隐式转换的类型或std::string
实例(在表达式中添加std::to_string
时获得的内容)。
#include <string>
#include <iostream>
struct string_proxy
{
std::string value;
string_proxy(const std::string& value) : value(value) {}
string_proxy(std::string&& value) : value(std::move(value)) {}
template <size_t size>
string_proxy(const char (&str)[size]) : value(str) {}
};
void f(string_proxy proxy)
{
std::cout << proxy.value << std::endl;
}
int main()
{
f("this works"); // const char[size]
f("this works too: " + std::to_string(10)); // std::string
f("compile error!" + 10); // const char*
return 0;
}
请注意,这在MSVC上无法运行,至少在2012版本中没有;它可能是一个错误,因为也没有发出警告。它在g ++和clang中运行得非常好(你可以快速检查它here)。
答案 4 :(得分:2)
我找到了一种非常简单的方法来检测这个问题。正则表达式和lint不匹配更复杂的表达式,如下所示:
f("Hello " + g(i));
我需要的是以某种方式进行类型推断,所以我让编译器去做。使用std::string
而不是文字字符串会引发错误,因此我wrote a simple source code converter将所有字符串文字转换为包装std::string
版本,如下所示:
f(std::string("Hello ") + g(i));
然后,在重新编译项目后,我会看到所有错误。源代码在GitHub上,有48行Python代码:
答案 5 :(得分:0)
如果您的情况与
完全相同"some text in quotations" + a_numeric_variable_or_constant
然后Powergrep或类似的程序将允许您扫描所有文件
("[^"]+")\s*\+\s*(\w+)
并替换为
\1 + std::to_string(\2)
这将为您带来可能的匹配,但我强烈建议您首先预览您要替换的内容。因为这也会替换字符串变量。
正则表达式无法理解代码的语义,因此如果它们是整数,则无法确定它们。为此,您需要一个带有CDT或静态代码分析器等解析器的程序。但不幸的是,我不知道有什么可以做到这一点。总而言之,我希望正则表达式有所帮助:)
PS:对于最坏的情况,如果变量不是数字,那么编译器会给你错误,因为to_string
函数不接受任何数字值。可能稍后您可以手动替换它们,我只能希望它们不会更多。
答案 6 :(得分:0)
您可以试试Map-Reduce Clang插件。 该工具是在谷歌开发的,只进行这种重构,混合了强类型检查和正则表达式。
(见视频演示here)。
答案 7 :(得分:0)
您可以使用C ++类型转换操作符&amp;创建一个新的类,可以超出操作员+您的需要。您可以将int替换为新类&#34; Integer&#34; &安培;执行所需的重载。这不需要在主函数调用中进行任何更改或单词替换。
class Integer{
long i;
std::string formatted;
public:
Integer(int i){i = i;}
operator char*(){
return (char*)formatted.c_str();}
friend Integer operator +( char* input, Integer t);
};
Integer operator +( char* input, Integer integer) {
integer.formatted = input + std::to_string(integer.i);
return integer;
}
Integer i = ....
f("test" + i); //executes the overloaded operator
答案 8 :(得分:0)
我假设函数f(some_str + i);你的定义应该是这样的
void f(std::string value)
{
// do something.
}
如果你声明其他类如AdvString来实现操作符+ for intergers。如果你声明你的函数如下代码。它将像这个实现f(some_str + i);
一样工作 void f(AdvString value)
{
// do something.
}