1111class CppcheckExecutor : public ErrorLogger {
1212private:
1313 CppCheck cppcheck;
14- const std::string line ;
14+ std::string pattern ;
1515 bool foundLine;
1616
1717public:
18- CppcheckExecutor (const std::string &l )
18+ CppcheckExecutor (int linenr )
1919 : ErrorLogger()
2020 , cppcheck(*this ,false )
21- , line(' :' + l + ' ]' )
2221 , foundLine(false ) {
22+ std::ostringstream ostr;
23+ ostr << linenr;
24+ pattern = " :" + ostr.str () + " ]" ;
25+ cppcheck.settings ().addEnabled (" all" );
26+ cppcheck.settings ().inconclusive = true ;
27+ cppcheck.settings ()._force = true ;
2328 }
2429
2530 bool run (const char filename[]) {
2631 foundLine = false ;
27- Settings settings;
28- settings.addEnabled (" all" );
29- settings.inconclusive = true ;
30- settings._force = true ;
31- cppcheck.settings () = settings;
3232 cppcheck.check (filename);
3333 return foundLine;
3434 }
3535
3636 void reportOut (const std::string &outmsg) { }
3737 void reportErr (const ErrorLogger::ErrorMessage &msg) {
38- if (msg.toString (false ).find (line ) != std::string::npos) {
38+ if (msg.toString (false ).find (pattern ) != std::string::npos) {
3939 foundLine = true ;
4040 cppcheck.terminate ();
4141 }
@@ -44,7 +44,7 @@ class CppcheckExecutor : public ErrorLogger {
4444};
4545
4646
47- static bool test (CppcheckExecutor &cppcheck, const char *filename, const std::vector<std::string> &filedata, const std::size_t line1, const std::size_t line2)
47+ static bool test (const char *filename, int linenr , const std::vector<std::string> &filedata, const std::size_t line1, const std::size_t line2)
4848{
4949 std::string path (filename);
5050 if (path.find_first_of (" \\ /" ) != std::string::npos)
@@ -57,12 +57,14 @@ static bool test(CppcheckExecutor &cppcheck, const char *filename, const std::ve
5757 for (std::size_t i = 0 ; i < filedata.size (); i++)
5858 fout << ((i>=line1 && i<=line2) ? " " : filedata[i]) << std::endl;
5959 fout.close ();
60+
61+ CppcheckExecutor cppcheck (linenr);
6062 return cppcheck.run (tempfilename.c_str ());
6163}
6264
63- static bool test (CppcheckExecutor &cppcheck, const char *filename, const std::vector<std::string> &filedata, const std::size_t line)
65+ static bool test (const char *filename, int linenr , const std::vector<std::string> &filedata, const std::size_t line)
6466{
65- return test (cppcheck, filename , filedata, line, line);
67+ return test (filename, linenr , filedata, line, line);
6668}
6769
6870static void printstr (const std::vector<std::string> &filedata, int i1, int i2)
@@ -72,6 +74,69 @@ static void printstr(const std::vector<std::string> &filedata, int i1, int i2)
7274 std::cout << i << " :" << filedata[i] << std::endl;
7375}
7476
77+ static std::vector<std::string> readfile (const std::string &filename)
78+ {
79+ std::vector<std::string> filedata;
80+ std::ifstream fin (filename.c_str ());
81+ std::string line;
82+ bool blockComment = false ;
83+ while (std::getline (fin,line)) {
84+ // replace various space characters with space
85+ for (std::string::size_type pos = 0 ; pos < line.size (); ++pos) {
86+ if (line[pos] & 0x80 || std::isspace (line[pos]))
87+ line[pos] = ' ' ;
88+ }
89+
90+ // remove block comments TODO: Handle /* inside strings
91+ if (blockComment) {
92+ if (line.find (" */" ) == std::string::npos)
93+ line.clear ();
94+ else {
95+ if (line.find (" */" ) + 2U == line.size ())
96+ line.clear ();
97+ else
98+ line = line.substr (line.find (" */" ) + 2U );
99+ blockComment = false ;
100+ }
101+ }
102+ while (!blockComment && line.find (" /*" ) != std::string::npos) {
103+ std::string::size_type pos = line.find (" /*" );
104+ if (line.find (" */" ,pos) == std::string::npos) {
105+ blockComment = true ;
106+ if (pos==0 )
107+ line.clear ();
108+ else
109+ line = line.substr (0 ,pos);
110+ } else {
111+ blockComment = false ;
112+ line = line.erase (pos, 2U + line.find (" */" , pos) - pos);
113+ }
114+ }
115+
116+ // Remove // comments
117+ if (line.find (" //" ) != std::string::npos)
118+ line = line.substr (0 , line.find (" //" ));
119+
120+ // empty line
121+ if (line.find_first_not_of (" " ) == std::string::npos)
122+ line.clear ();
123+ else {
124+ const std::string::size_type pos = line.find_first_not_of (" " );
125+
126+ // remove spaces before leading #
127+ if (line[pos]==' #' )
128+ line = line.substr (pos);
129+ }
130+
131+ // remove trailing spaces
132+ while (!line.empty () && std::isspace (line[line.size ()-1U ]))
133+ line = line.substr (0 , line.size () - 1U );
134+
135+ filedata.push_back (line);
136+ }
137+ return filedata;
138+ }
139+
75140int main (int argc, char *argv[])
76141{
77142 std::cout << " cppcheck tool that reduce code for a false positive" << std::endl;
@@ -82,94 +147,56 @@ int main(int argc, char *argv[])
82147 }
83148
84149 const char * const filename = argv[1 ];
85- const char * const linenr = argv[2 ];
150+ int linenr = std::atoi ( argv[2 ]) ;
86151
87152 std::cout << " make sure false positive can be reproduced" << std::endl;
88153
89154 // Execute Cppcheck on the file..
90- CppcheckExecutor cppcheck (linenr);
91- if (!cppcheck.run (filename)) {
92- std::cerr << " Can't reproduce false positive at line " << linenr << std::endl;
93- return EXIT_FAILURE;
94- }
95-
96- // Read file..
97- std::vector<std::string> filedata;
98155 {
99- std::ifstream fin (filename);
100- std::string line;
101- bool blockComment = false ;
102- while (std::getline (fin,line)) {
103- // replace various space characters with space
104- for (std::string::size_type pos = 0 ; pos < line.size (); ++pos) {
105- if (line[pos] & 0x80 || std::isspace (line[pos]))
106- line[pos] = ' ' ;
107- }
108-
109- // remove block comments TODO: Handle /* inside strings
110- if (blockComment) {
111- if (line.find (" */" ) == std::string::npos)
112- line.clear ();
113- else {
114- if (line.find (" */" ) + 2U == line.size ())
115- line.clear ();
116- else
117- line = line.substr (line.find (" */" ) + 2U );
118- blockComment = false ;
119- }
120- }
121- while (!blockComment && line.find (" /*" ) != std::string::npos) {
122- std::string::size_type pos = line.find (" /*" );
123- if (line.find (" */" ,pos) == std::string::npos) {
124- blockComment = true ;
125- if (pos==0 )
126- line.clear ();
127- else
128- line = line.substr (0 ,pos);
129- } else {
130- blockComment = false ;
131- line = line.erase (pos, 2U + line.find (" */" , pos) - pos);
132- }
133- }
134-
135- // Remove // comments
136- if (line.find (" //" ) != std::string::npos)
137- line = line.substr (0 , line.find (" //" ));
138-
139- // empty line
140- if (line.find_first_not_of (" " ) == std::string::npos)
141- line.clear ();
142- else {
143- const std::string::size_type pos = line.find_first_not_of (" " );
144-
145- // remove spaces before leading #
146- if (line[pos]==' #' )
147- line = line.substr (pos);
148- }
149-
150- // remove trailing spaces
151- while (!line.empty () && std::isspace (line[line.size ()-1U ]))
152- line = line.substr (0 , line.size () - 1U );
153-
154- filedata.push_back (line);
156+ CppcheckExecutor cppcheck (linenr);
157+ if (!cppcheck.run (filename)) {
158+ std::cerr << " Can't reproduce false positive at line " << linenr << std::endl;
159+ return EXIT_FAILURE;
155160 }
156161 }
157162
163+ // Read file..
164+ std::vector<std::string> filedata (readfile (filename));
158165
159166 // Write resulting code..
160- if (!test (cppcheck, filename , filedata, ~0 )) {
167+ if (!test (filename, linenr , filedata, ~0 )) {
161168 std::cerr << " Cleanup failed." << std::endl;
162169 return EXIT_FAILURE;
163170 }
164171
165172 // Remove includes..
173+ std::set<std::string> headers;
166174 for (std::size_t i = 0 ; i < filedata.size (); i++) {
167175 if (filedata[i].compare (0 ,8 ," #include" )==0 ) {
168- if (test (cppcheck, filename, filedata, i)) {
176+ if (test (filename, linenr, filedata, i)) {
177+ std::cout << " removed #include : " << filedata[i] << std::endl;
169178 filedata[i].clear ();
170- std::cout << " removed #include at line " << i << std::endl;
171179 } else {
172- std::cout << " kept #include at line " << i << std::endl;
180+ std::string header = filedata[i];
181+ header = header.substr (1U + header.find_first_of (" \" <" ));
182+ header = header.erase (header.find_last_of (" \" >" ));
183+ if (headers.find (header) != headers.end ()) {
184+ std::cerr << " Failed to reduce headers" << std::endl;
185+ return EXIT_FAILURE;
186+ }
187+ headers.insert (header);
188+ std::string path (filename);
189+ if (path.find_first_of (" \\ /" ) != std::string::npos)
190+ path = path.erase (1 + path.find_last_of (" \\ /" ));
191+ else
192+ path.clear ();
193+ std::cout << " expand #include : " << (path+header) << std::endl;
194+ std::vector<std::string> data (readfile (path+header));
195+ if (!data.empty ()) {
196+ filedata[i].clear ();
197+ filedata.insert (filedata.begin ()+i, data.begin (), data.end ());
198+ linenr += data.size ();
199+ }
173200 }
174201 }
175202 }
@@ -185,7 +212,7 @@ int main(int argc, char *argv[])
185212
186213 // some kind of single line declaration
187214 if (std::isalpha (startChar) && endChar==' ;' ) {
188- if (test (cppcheck, filename , filedata, i)) {
215+ if (test (filename, linenr , filedata, i)) {
189216 filedata[i].clear ();
190217 std::cout << " removed declaration at line " << i << std::endl;
191218 } else {
@@ -229,7 +256,7 @@ int main(int argc, char *argv[])
229256
230257 // does block of code end with a '}'
231258 if ((pos2 < filedata.size ()) && (filedata[pos2] == " }" || filedata[pos2] == " };" )) {
232- if (test (cppcheck, filename , filedata, pos, pos2)) {
259+ if (test (filename, linenr , filedata, pos, pos2)) {
233260 for (i = pos; i <= pos2; i++)
234261 filedata[i].clear ();
235262 std::cout << " removed block of code at lines " << pos << " -" << pos2 << std::endl;
0 commit comments