Как найти в моей программе выражение «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 ++ выдает ошибку.

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

12 голосов | спросил vz0 12 J000000Saturday14 2014, 17:10:14

9 ответов


0

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

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

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

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

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

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

ответил vz0 16 J000000Wednesday14 2014, 17:39:50
0

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

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
ответил esneider 16 J000000Wednesday14 2014, 03:34:37
0

Вы можете попробовать flint , программу с открытым исходным кодом для 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), я внес свои изменения в версию D.

ответил Alper 14 J000000Monday14 2014, 17:12:08
0

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

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

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

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

Если все целые числа постоянны, вы можете изменить эксперимент grep следующим образом:

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

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

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

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

ответил nicky_zs 12 J000000Saturday14 2014, 17:22:56
0

Вам может не понадобиться внешний инструмент. Вместо этого вы можете воспользоваться преимуществом правила однопользовательского преобразования C ++. По сути, вам нужно изменить аргумент вашей функции f из const char* /std::string к типу, который неявно преобразуется только из строкового литерала (const char[size]) или экземпляр std::string (что вы получаете, когда добавляете ---- +: = 5 =: + ---- в выражении).

std::to_string

Обратите внимание, что это не будет работать в MSVC, по крайней мере, в версии 2012 года; это, вероятно, ошибка, так как предупреждение также не выдается. Он отлично работает в g ​​++ и clang (вы можете быстро это проверить здесь ).

ответил gwiazdorrr 14 J000000Monday14 2014, 20:33:01
0

Если ваш случай точно такой же, как

"some text in quotations" + a_numeric_variable_or_constant

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

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

и заменить на

\1 + std::to_string(\2)

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

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

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

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

ответил ifyalciner 12 J000000Saturday14 2014, 17:49:18
0

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

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

ответил Nielk 15 J000000Tuesday14 2014, 19:33:09
0

Вы можете использовать оператор ввода типов 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
ответил dvasanth 16 J000000Wednesday14 2014, 15:41:05
0

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

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

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

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

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

ответил Prasaathviki 21 J000000Monday14 2014, 09:25:11

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132