Skip to content

Commit f2f8780

Browse files
committed
tools/reduce: better handling of #include
1 parent e824f76 commit f2f8780

File tree

1 file changed

+110
-83
lines changed

1 file changed

+110
-83
lines changed

tools/reduce.cpp

Lines changed: 110 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@
1111
class CppcheckExecutor : public ErrorLogger {
1212
private:
1313
CppCheck cppcheck;
14-
const std::string line;
14+
std::string pattern;
1515
bool foundLine;
1616

1717
public:
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

6870
static 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+
75140
int 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

Comments
 (0)