Как найти в моей программе выражение "const char* + int"

Я в миграции исходного кода, и программа конвертера не преобразовывала конкатенацию встроенных строк целыми числами. Теперь у меня много кода с такими выражениями:

f("some text" + i);

поскольку C / C++ будет интерпретировать это как индекс массива,f получит "some text" или "ome text" или "me text"...

мой исходный язык преобразует конкатенацию строки с int в конкатенацию строки. Теперь мне нужно пройти строчку за строчкой через источник. код и измените вручную предыдущее выражение на:

f("some text" + std::to_string(i));

программа преобразования удалось преобразовать локальный"String" переменные "std::string", в результате выражения:

std::string some_str = ...;
int i = ...;

f(some_str + i);

их было легко исправить, потому что с такими выражениями компилятор C++ выводит ошибку.

есть ли какой-либо инструмент для автоматического поиска таких выражений в исходном коде?

9 ответов


легко! Просто замените все + С -&:

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

вы можете попробовать Флинт, программа lint с открытым исходным кодом для C++, разработанная и используемая в Facebook. Он имеет функцию последовательности маркеров в черном списке (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), I внесены изменения в D версии.


Я не знакома с большим количеством инструментов, которые могут это сделать, но я думаю grep может быть полезно в некоторой степени.

в корневом каталоге исходного кода попробуйте:

grep -rn '".\+"\s*+\s*' .

, который может узнать все файлы, содержащие строку типа "xxxxx" +, надеюсь, это поможет вам найти все линии, которые вам нужны.

если все целые числа постоянны, вы можете изменить grep experssion как:

grep -rn '".\+"\s*+\s*[0-9]*' .

и вы также можете включить ( перед строковая константа:

grep -rn '(".\+"\s*+\s*[0-9]*' .

это может быть не "правильный" ответ, но я надеюсь, что это может вам помочь.


вам может не понадобиться внешний инструмент. Вместо этого можно воспользоваться правилом C++ one-user-defined-conversion. В принципе, вам нужно изменить аргумент вашего


Я нашел очень простой способ обнаружить эту проблему. Регулярное выражение или Линт не будут соответствовать более сложным выражениям, таким как:

f("Hello " + g(i));

мне нужно как-то сделать вывод типа, поэтому я позволяю компилятору это сделать. С помощью std::string вместо литеральной строки возникает ошибка, поэтому I написал простой конвертер исходного кода перевести все строковые литералы в обернутом std::string версия, вроде этого:

f(std::string("Hello ") + g(i));

потом, после перекомпилируя проект, я бы увидел все ошибки. Исходный код находится на GitHub, в 48 строках кода Python:

https://gist.github.com/alejolp/3a700e1730e0328c68de


если ваш случай именно как

"some text in quotations" + a_numeric_variable_or_constant

тогда Powergrep или аналогичные программы позволят вам сканировать все файлы для

("[^"]+")\s*\+\s*(\w+)

и заменить на

 + std::to_string()

это принесет вам возможные матчи, но я настоятельно рекомендую сначала просмотреть, что вы заменяете. Потому что это также заменит строковые переменные.

регулярные выражения не могут понять семантику кода, поэтому они не могут быть уверены, что если они являются целыми числами. Для этого вам нужна программа с парсером, таким как CDT или статические анализаторы кода. Но, к сожалению, я не знаю никого, кто мог бы это сделать. Итак, я надеюсь, что regex поможет:)

PS: в худшем случае, если переменные не являются числовыми, компилятор даст вам ошибку, потому что to_string функция не принимает ничего, кроме числовых значений. Может быть позже, вы можете вручную заменить только их, которые я могу только надеяться, не будет больше.

PS 2: Некоторые могут подумать, что Powergrep дорого. Вы можете использовать бесплатно в течение 15 дней с полной функциональностью.


вы можете попробовать плагин Map-Reduce Clang. Инструмент был разработан в Google, чтобы сделать именно такой рефакторинг, смешивая сильную проверку типов и регулярное выражение.

(см. видео-презентации здесь ).


вы можете использовать оператор типизации C++ и создать новый класс, который может перегрузить оператор + в соответствии с вашими потребностями. Вы можете заменить int на новый класс "Integer" и выполнить требуемую перегрузку. Это не требует никаких изменений или замены слова в вызове основной функции.

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

Я предполагаю для функции f (some_str + i); ваше определение должно быть таким

 void f(std::string value)
 {
    // do something.
 }

Если вы объявите какой-то другой класс, как AdvString реализовать оператор + для intergers. если вы объявите свою функцию, как это показано ниже кода. он будет работать так, как эта реализация f (some_str + i);

 void f(AdvString value)
 {
   // do something.
 }

пример реализации здесь https://github.com/prasaathviki/advstring