Skip to content

Commit 5ccc3b5

Browse files
authored
Merge branch 'danmar:main' into fix-14657
2 parents 45ee4af + 6913517 commit 5ccc3b5

11 files changed

Lines changed: 125 additions & 42 deletions

lib/astutils.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown)
461461
return false;
462462
return !branchTok->astOperand1()->valueType()->isTypeEqual(branchTok->astOperand2()->valueType());
463463
}
464-
if (Token::simpleMatch(tok, "(") && tok->astOperand1() &&
464+
if (Token::Match(tok, "(|{") && tok->astOperand1() &&
465465
(tok->astOperand2() || Token::simpleMatch(tok->next(), ")"))) {
466466
if (Token::simpleMatch(tok->astOperand1(), "typeid"))
467467
return false;
@@ -498,9 +498,6 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown)
498498
// Currying a function is unknown in cppcheck
499499
if (Token::simpleMatch(tok, "(") && Token::simpleMatch(tok->astOperand1(), "("))
500500
return unknown;
501-
if (Token::simpleMatch(tok, "{") && Token::simpleMatch(tok->astParent(), "return") && tok->astOperand1() &&
502-
!tok->astOperand2())
503-
return isTemporary(tok->astOperand1(), library);
504501
return true;
505502
}
506503

lib/checkunusedfunctions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting
261261
while (Token::Match(funcname, "%name% :: %name%"))
262262
funcname = funcname->tokAt(2);
263263

264+
if (funcname && funcname->isName() && !funcname->function() && !tok->astParent() && Token::Match(tok, "[(,]")) // unknown type in parameter list
265+
continue;
266+
264267
if (!Token::Match(funcname, "%name% [(),;]:}<>]"))
265268
continue;
266269
}

lib/suppressions.cpp

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,8 @@ std::vector<SuppressionList::Suppression> SuppressionList::parseMultiSuppressCom
207207
return suppressions;
208208
}
209209

210-
SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
210+
SuppressionList::Suppression SuppressionList::parseLine(std::string line)
211211
{
212-
std::istringstream lineStream;
213212
SuppressionList::Suppression suppression;
214213

215214
// Strip any end of line comments
@@ -218,13 +217,18 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
218217
while (endpos > 0 && std::isspace(line[endpos-1])) {
219218
endpos--;
220219
}
221-
lineStream.str(line.substr(0, endpos));
222-
} else {
223-
lineStream.str(line);
220+
line.resize(endpos);
224221
}
225222

226-
if (std::getline(lineStream, suppression.errorId, ':')) {
227-
if (std::getline(lineStream, suppression.fileName)) {
223+
const auto parts = splitString(line, '\n');
224+
const std::string& suppr_l = parts[0];
225+
226+
const std::string::size_type first_sep = suppr_l.find(':');
227+
suppression.errorId = suppr_l.substr(0, first_sep);
228+
if (first_sep != std::string::npos) {
229+
suppression.fileName = suppr_l.substr(first_sep+1);
230+
if (!suppression.fileName.empty()) {
231+
// TODO: this only works with files which have an extension
228232
// If there is not a dot after the last colon in "file" then
229233
// the colon is a separator and the contents after the colon
230234
// is a line number..
@@ -234,39 +238,48 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
234238

235239
// if a colon is found and there is no dot after it..
236240
if (pos != std::string::npos &&
237-
suppression.fileName.find('.', pos) == std::string::npos) {
238-
// Try to parse out the line number
239-
try {
240-
std::istringstream istr1(suppression.fileName.substr(pos+1));
241-
istr1 >> suppression.lineNumber;
242-
} catch (...) {
243-
suppression.lineNumber = SuppressionList::Suppression::NO_LINE;
244-
}
241+
suppression.fileName.find('.', pos) == std::string::npos)
242+
{
243+
// parse out the line number
244+
const std::string line_s = suppression.fileName.substr(pos+1);
245+
suppression.fileName.erase(pos);
245246

246-
if (suppression.lineNumber != SuppressionList::Suppression::NO_LINE) {
247-
suppression.fileName.erase(pos);
248-
}
249-
}
247+
if (suppression.fileName.empty())
248+
throw std::runtime_error("filename is missing");
250249

251-
// when parsing string generated internally by toString() there can be newline
252-
std::string extra;
253-
while (std::getline(lineStream, extra)) {
254-
if (startsWith(extra, "symbol="))
255-
suppression.symbolName = extra.substr(7);
256-
else if (extra == "polyspace=1")
257-
suppression.isPolyspace = true;
250+
try {
251+
suppression.lineNumber = strToInt<int>(line_s);
252+
} catch (const std::runtime_error& e) {
253+
throw std::runtime_error(std::string("invalid line number (") + e.what() + ")");
254+
}
258255
}
256+
suppression.fileName = Path::simplifyPath(suppression.fileName);
257+
} else {
258+
throw std::runtime_error("filename is missing");
259259
}
260260
}
261261

262-
suppression.fileName = Path::simplifyPath(suppression.fileName);
262+
// TODO: make this optional - do we even encounter this in production code?
263+
// when parsing string generated internally by toString() there can be newline
264+
for (std::size_t i = 1; i < parts.size(); ++i) {
265+
if (startsWith(parts[i], "symbol="))
266+
suppression.symbolName = parts[i].substr(7);
267+
else if (parts[i] == "polyspace=1")
268+
suppression.isPolyspace = true;
269+
else
270+
throw std::runtime_error("unexpected extra '" + parts[i] + "'");
271+
}
263272

264273
return suppression;
265274
}
266275

267276
std::string SuppressionList::addSuppressionLine(const std::string &line)
268277
{
269-
return addSuppression(parseLine(line));
278+
try {
279+
return addSuppression(parseLine(line));
280+
} catch (const std::exception& e) {
281+
return e.what();
282+
}
270283
}
271284

272285
std::string SuppressionList::addSuppression(SuppressionList::Suppression suppression)

lib/suppressions.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,9 @@ class CPPCHECKLIB SuppressionList {
196196
* Create a Suppression object from a suppression line
197197
* @param line The line to parse.
198198
* @return a suppression object
199+
* @throws std::runtime_error thrown if the given suppression is invalid
199200
*/
200-
static Suppression parseLine(const std::string &line);
201+
static Suppression parseLine(std::string line);
201202

202203
/**
203204
* @brief Don't show the given error.

lib/token.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,11 +1421,6 @@ std::string Token::stringifyList(const Token* end, bool attributes) const
14211421
return stringifyList(false, attributes, false, false, false, nullptr, end);
14221422
}
14231423

1424-
std::string Token::stringifyList(bool varid) const
1425-
{
1426-
return stringifyList(varid, false, true, true, true, nullptr, nullptr);
1427-
}
1428-
14291424
void Token::astParent(Token* tok)
14301425
{
14311426
const Token* tok2 = tok;

lib/token.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ class CPPCHECKLIB Token {
11101110
options.files = true;
11111111
return options;
11121112
}
1113-
// cppcheck-suppress unusedFunction
1113+
// cppcheck-suppress unusedFunction - used in tests only
11141114
static stringifyOptions forDebugVarId() {
11151115
stringifyOptions options = forDebug();
11161116
options.varid = true;
@@ -1142,7 +1142,6 @@ class CPPCHECKLIB Token {
11421142

11431143
std::string stringifyList(const stringifyOptions& options, const std::vector<std::string>* fileNames = nullptr, const Token* end = nullptr) const;
11441144
std::string stringifyList(const Token* end, bool attributes = true) const;
1145-
std::string stringifyList(bool varid = false) const;
11461145

11471146
/**
11481147
* Stringify a list of token, from current instance on.

test/testautovariables.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class TestAutoVariables : public TestFixture {
131131
TEST_CASE(returnReference26);
132132
TEST_CASE(returnReference27);
133133
TEST_CASE(returnReference28);
134+
TEST_CASE(returnReference29);
134135
TEST_CASE(returnReferenceFunction);
135136
TEST_CASE(returnReferenceContainer);
136137
TEST_CASE(returnReferenceLiteral);
@@ -1757,6 +1758,19 @@ class TestAutoVariables : public TestFixture {
17571758
ASSERT_EQUALS("", errout_str());
17581759
}
17591760

1761+
void returnReference29()
1762+
{
1763+
check("const std::string& f() {\n" // #12548
1764+
" return std::string{};\n"
1765+
"}\n"
1766+
"const std::string& g() {\n"
1767+
" return {};\n"
1768+
"}\n");
1769+
ASSERT_EQUALS("[test.cpp:2:23]: (error) Reference to temporary returned. [returnTempReference]\n"
1770+
"[test.cpp:5:12]: (error) Reference to temporary returned. [returnTempReference]\n",
1771+
errout_str());
1772+
}
1773+
17601774
void returnReferenceFunction() {
17611775
check("int& f(int& a) {\n"
17621776
" return a;\n"

test/testsimplifytokens.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ class TestSimplifyTokens : public TestFixture {
208208
ASSERT_LOC(tokenizer.tokenize(code), file, line);
209209

210210
// result..
211-
return tokenizer.tokens()->stringifyList(true);
211+
return tokenizer.tokens()->stringifyList(true, false, true, true, true);
212212
}
213213

214214

test/testsuppressions.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class TestSuppressions : public TestFixture {
5858
void run() override {
5959
mNewTemplate = true;
6060
TEST_CASE(parseLine);
61+
TEST_CASE(parseLineInvalid);
6162
TEST_CASE(suppressionsBadId1);
6263
TEST_CASE(suppressionsDosFormat); // Ticket #1836
6364
TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon
@@ -146,13 +147,62 @@ class TestSuppressions : public TestFixture {
146147

147148

148149
void parseLine() const {
150+
ASSERT_EQUALS("bad", SuppressionList::parseLine("bad").toString());
151+
ASSERT_EQUALS("bad:test.c", SuppressionList::parseLine("bad:test.c").toString());
149152
ASSERT_EQUALS("bad:test.c:1", SuppressionList::parseLine("bad:test.c:1").toString());
150153

151154
// symbol
155+
ASSERT_EQUALS("bad\nsymbol=x", SuppressionList::parseLine("bad\nsymbol=x").toString());
156+
ASSERT_EQUALS("bad:test.c\nsymbol=x", SuppressionList::parseLine("bad:test.c\nsymbol=x").toString());
152157
ASSERT_EQUALS("bad:test.c:1\nsymbol=x", SuppressionList::parseLine("bad:test.c:1\nsymbol=x").toString());
153158

159+
// empty symbol
160+
ASSERT_EQUALS("bad", SuppressionList::parseLine("bad\nsymbol=").toString());
161+
ASSERT_EQUALS("bad:test.c", SuppressionList::parseLine("bad:test.c\nsymbol=").toString());
162+
ASSERT_EQUALS("bad:test.c:1", SuppressionList::parseLine("bad:test.c:1\nsymbol=").toString());
163+
154164
// polyspace
165+
ASSERT_EQUALS("bad\npolyspace=1", SuppressionList::parseLine("bad\npolyspace=1").toString());
166+
ASSERT_EQUALS("bad:test.c\npolyspace=1", SuppressionList::parseLine("bad:test.c\npolyspace=1").toString());
155167
ASSERT_EQUALS("bad:test.c:1\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\npolyspace=1").toString());
168+
169+
// symbol + polyspace
170+
ASSERT_EQUALS("bad\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad\nsymbol=x\npolyspace=1").toString());
171+
ASSERT_EQUALS("bad:test.c\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c\nsymbol=x\npolyspace=1").toString());
172+
ASSERT_EQUALS("bad:test.c:1\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\nsymbol=x\npolyspace=1").toString());
173+
174+
// polyspace + symbol
175+
ASSERT_EQUALS("bad\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad\npolyspace=1\nsymbol=x").toString());
176+
ASSERT_EQUALS("bad:test.c\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c\npolyspace=1\nsymbol=x").toString());
177+
ASSERT_EQUALS("bad:test.c:1\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\npolyspace=1\nsymbol=x").toString());
178+
}
179+
180+
void parseLineInvalid() const {
181+
// missing filename
182+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:"), std::runtime_error, "filename is missing");
183+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:\n"), std::runtime_error, "filename is missing");
184+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:\n1.c"), std::runtime_error, "filename is missing");
185+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:#1.c"), std::runtime_error, "filename is missing"); // TODO: looks like a valid filename
186+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id://1.c"), std::runtime_error, "filename is missing");
187+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id::"), std::runtime_error, "filename is missing");
188+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id::1"), std::runtime_error, "filename is missing");
189+
190+
// missing/invalid line
191+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)");
192+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)");
193+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)");
194+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:#1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)"); // TODO: looks like a valid filename
195+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c://1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)");
196+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:zero"), std::runtime_error, "invalid line number (converting 'zero' to integer failed - not an integer)");
197+
198+
// invalid extras
199+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\n"), std::runtime_error, "unexpected extra ''");
200+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\nsym=x"), std::runtime_error, "unexpected extra 'sym=x'");
201+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\nsymbol:x"), std::runtime_error, "unexpected extra 'symbol:x'");
202+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\npolyspace=0"), std::runtime_error, "unexpected extra 'polyspace=0'");
203+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\npolyspace:1"), std::runtime_error, "unexpected extra 'polyspace:1'");
204+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id\n:"), std::runtime_error, "unexpected extra ':'");
205+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c\n:"), std::runtime_error, "unexpected extra ':'");
156206
}
157207

158208
void suppressionsBadId1() const {

test/testtokenize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8378,7 +8378,7 @@ class TestTokenizer : public TestFixture {
83788378
// Tokenizer..
83798379
ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
83808380

8381-
return tokenizer.tokens()->stringifyList();
8381+
return tokenizer.tokens()->stringifyList(false, false, true, true, true);
83828382
}
83838383

83848384
void checkHeader1() {

0 commit comments

Comments
 (0)