diff --git a/addons/misra.py b/addons/misra.py index ae3cf59c8bc..62a87666490 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -3327,6 +3327,9 @@ def misra_config(self, data): end_token = tok.link while tok != end_token: tok = tok.next + if tok.str == 'sizeof' and tok.next.str == '(': + tok = tok.next.link + continue if tok.str == "(" and tok.isCast: tok = tok.link continue @@ -4254,6 +4257,7 @@ def setSuppressionList(self, suppressionlist): self.addSuppressedRule(ruleNum) def report_config_error(self, location, errmsg): + errmsg = 'Because of missing configuration, misra checking is incomplete. There can be false negatives! ' + errmsg cppcheck_severity = 'error' error_id = 'config' if self.settings.verify: diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index d1ece87f2b2..fc0abdab7ca 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -2035,3 +2035,13 @@ static void misra_22_10(void) f = strtod(inStr, NULL_PTR); if(errno != 0) {} } + +// #12448 +static void check_misra_config(void) +{ + if (sizeof(struct bar) == 0U) {} //no warning + if (sizeof(int abc) == 0U) {} //no warning + if (sizeof(xyz) == 0U) {} //no warning + if (sizeof(const pqr) == 0U) {} //no warning + if (sizeof(const int* const pqrs) == 0U) {} //no-warning +} diff --git a/cfg/std.cfg b/cfg/std.cfg index 7fb77addfd3..faf23d8f992 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -6428,7 +6428,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun std::istringstream& std::istringstream::get (char* s, streamsize n, char delim); stream buffer (3) std::istringstream& std::istringstream::get (streambuf& sb); std::istringstream& std::istringstream::get (streambuf& sb, char delim);--> - false @@ -6509,28 +6509,35 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + false - + false - + false - + + + + + false + + + @@ -6566,6 +6573,31 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun 0: + + + + + + false + + + + + + + + @@ -8303,7 +8335,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init - + false diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 63b88dc2af0..fcb9e52106c 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -16895,8 +16895,6 @@ HFONT CreateFont( - - @@ -16917,8 +16915,124 @@ HFONT CreateFont( - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/createrelease b/createrelease index 2e5828b4c90..71498659bf3 100755 --- a/createrelease +++ b/createrelease @@ -7,7 +7,12 @@ # # check every isPremiumEnabled call: # - every id should be in --errorlist +# git grep 'isPremiumEnabled[(]"' | sed 's/.*isPremiumEnabled[(]"//' | sed 's/".*//' | sort | uniq > ids1.txt +# ./cppcheck --errorlist | grep ' id="' | sed 's/.* id="//' | sed 's/".*//' | sort | uniq > ids2.txt +# diff -y ids1.txt ids2.txt # - premiumaddon: check coverage.py +# python3 coverage.py --id ; sort ids-*.txt | uniq > ~/cppcheck/ids3.txt +# diff -y ids2.txt ids3.txt # # Windows installer: # - ensure latest build was successful diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 7ce557bfc92..5aa979b0bcf 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -766,7 +766,7 @@ void CheckFunctions::useStandardLibrary() continue; // 3. we expect idx incrementing by 1 - const bool inc = stepToken->str() == "++" && stepToken->astOperand1()->varId() == idxVarId; + const bool inc = stepToken->str() == "++" && stepToken->astOperand1() && stepToken->astOperand1()->varId() == idxVarId; const bool plusOne = stepToken->isBinaryOp() && stepToken->str() == "+=" && stepToken->astOperand1()->varId() == idxVarId && stepToken->astOperand2()->str() == "1"; diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 81a55471e7b..7b57eddadbe 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1958,7 +1958,7 @@ void CheckOther::checkIncompleteStatement() continue; if (isVoidStmt(tok)) continue; - if (mTokenizer->isCPP() && tok->str() == "&" && !(tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral())) + if (mTokenizer->isCPP() && tok->str() == "&" && !(tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral())) // Possible archive continue; const bool inconclusive = tok->isConstOp(); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 8458ffe4d5c..e4038adfbf9 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1287,7 +1287,7 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& if (Token::Match((derefValue ? derefValue : vartok)->astParent(), "(|=") && astIsRhs(derefValue ? derefValue : vartok)) { const Token *rhstok = derefValue ? derefValue : vartok; const Token *lhstok = rhstok->astParent()->astOperand1(); - const Variable *lhsvar = lhstok->variable(); + const Variable *lhsvar = lhstok ? lhstok->variable() : nullptr; if (lhsvar && lhsvar->isReference() && lhsvar->nameToken() == lhstok) return nullptr; } diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 6b082514f14..b5558233206 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -320,7 +320,7 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke else pm.setIntValue(tok, 0, then); } - } else if (tok->exprId() > 0) { + } else if (tok && tok->exprId() > 0) { if (endTok && findExpressionChanged(tok, tok->next(), endTok, settings, true)) return; pm.setIntValue(tok, 0, then); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 32b9c921e73..a14b78e7015 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4281,6 +4281,14 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += accessControlToString(function->access); outs +="\""; } + if (function->isOperator()) + outs += " isOperator=\"true\""; + if (function->isExplicit()) + outs += " isExplicit=\"true\""; + if (function->hasOverrideSpecifier()) + outs += " hasOverrideSpecifier=\"true\""; + if (function->hasFinalSpecifier()) + outs += " hasFinalSpecifier=\"true\""; if (function->isInlineKeyword()) outs += " isInlineKeyword=\"true\""; if (function->isStatic()) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9002f514813..98345dd31f9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -828,6 +828,8 @@ namespace { Token* const tok2 = insertTokens(tok, rangeType); Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers); + tok2->originalName(tok->str()); + tok3->originalName(tok->str()); Token *after = tok3; while (Token::Match(after, "%name%|*|&|&&|::")) after = after->next(); @@ -6342,7 +6344,8 @@ void Tokenizer::removeMacrosInGlobalScope() while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName()) tok2 = tok2->linkAt(1)->next(); - if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") && !Token::Match(tok2, "namespace|class|struct|union|private:|protected:|public:")) + if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") && + !Token::Match(tok2, "requires|namespace|class|struct|union|private:|protected:|public:")) unknownMacroError(tok); if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{")) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index a0706491dac..b6e312625d9 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -960,7 +960,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state) Token* const curlyBracket = squareBracket->link()->next(); squareBracket->astOperand1(curlyBracket); state.op.push(squareBracket); - tok = curlyBracket->link()->next(); + tok = curlyBracket->link() ? curlyBracket->link()->next() : nullptr; continue; } } diff --git a/oss-fuzz/type2.cpp b/oss-fuzz/type2.cpp index 0fe4ce343c4..6cd3591ec88 100644 --- a/oss-fuzz/type2.cpp +++ b/oss-fuzz/type2.cpp @@ -19,7 +19,6 @@ #include "type2.h" #include -#include static int getValue(const uint8_t *data, size_t dataSize, uint8_t maxValue, bool *done = nullptr) { @@ -54,19 +53,20 @@ static std::string generateExpression2_lvalue(const uint8_t *data, size_t dataSi static std::string generateExpression2_Op(const uint8_t *data, size_t dataSize, uint8_t numberOfGlobalConstants) { - std::ostringstream code; + std::string code; switch (getValue(data, dataSize, 3)) { case 0: - code << generateExpression2_lvalue(data, dataSize); + code += generateExpression2_lvalue(data, dataSize); break; case 1: - code << "globalconstant" << (1 + getValue(data, dataSize, numberOfGlobalConstants)); + code += "globalconstant"; + code += (1 + getValue(data, dataSize, numberOfGlobalConstants)); break; case 2: - code << (getValue(data, dataSize, 0x80) * 0x80 + getValue(data, dataSize, 0x80)); + code += (getValue(data, dataSize, 0x80) * 0x80 + getValue(data, dataSize, 0x80)); break; } - return code.str(); + return code; } static std::string generateExpression2_Expr(const uint8_t *data, size_t dataSize, uint8_t numberOfGlobalConstants, int depth=0) @@ -130,12 +130,14 @@ static std::string generateExpression2_conditionalCode(const std::string &indent size_t dataSize, uint8_t numberOfGlobalConstants) { - std::ostringstream code; + std::string code; if (indent.empty()) - code << functionStart(); - else - code << indent << "{\n"; + code += functionStart(); + else { + code += indent; + code += "{\n"; + } for (int line = 0; line < 4 || indent.empty(); ++line) { bool done = false; @@ -150,37 +152,60 @@ static std::string generateExpression2_conditionalCode(const std::string &indent ((type1 >= 5) ? mostLikelyType : type1); if (type2 == 0) { - code << indent << " var" << getValue(data, dataSize, 5) << "=" << generateExpression2_Expr(data, dataSize, numberOfGlobalConstants) << ";\n"; + code += indent; + code += " var"; + code += getValue(data, dataSize, 5); + code += "="; + code += generateExpression2_Expr(data, dataSize, numberOfGlobalConstants); + code += ";\n"; } else if (type2 == 1) { - code << indent << " if (" << generateExpression2_Cond(data, dataSize, numberOfGlobalConstants) << ")\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " if ("; + code += generateExpression2_Cond(data, dataSize, numberOfGlobalConstants); + code += ")\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); } else if (type2 == 2) { - code << indent << " if (" << generateExpression2_Cond(data, dataSize, numberOfGlobalConstants) << ")\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); - code << indent << " else\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " if ("; + code += generateExpression2_Cond(data, dataSize, numberOfGlobalConstants); + code += ")\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " else\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); } else if (type2 == 3) { - code << indent << " while (" << generateExpression2_Cond(data, dataSize, numberOfGlobalConstants) << ")\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " while ("; + code += generateExpression2_Cond(data, dataSize, numberOfGlobalConstants); + code += ")\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); } else if (type2 == 4) { - code << indent << " return " << generateExpression2_Expr(data, dataSize, numberOfGlobalConstants) << ";\n"; - if (indent.empty()) - code << "}\n\n" << functionStart(); + code += indent; + code += " return "; + code += generateExpression2_Expr(data, dataSize, numberOfGlobalConstants); + code += ";\n"; + if (indent.empty()) { + code += "}\n\n"; + code += functionStart(); + } else break; } } - if (!indent.empty()) - code << indent << "}\n"; - else - code << " return 0;\n}\n"; - return code.str(); + if (!indent.empty()) { + code += indent; + code += "}\n"; + } + else { + code += " return 0;\n}\n"; + } + return code; } std::string generateCode2(const uint8_t *data, size_t dataSize) { - std::ostringstream code; + std::string code; // create global constants constexpr uint8_t numberOfGlobalConstants = 0; @@ -192,15 +217,15 @@ std::string generateCode2(const uint8_t *data, size_t dataSize) } */ - code << "int var1 = 1;\n" - "int var2 = 0;\n" - "int var3 = 1;\n" - "int var4 = 0;\n" - "int var5 = -1;\n\n"; + code += "int var1 = 1;\n" + "int var2 = 0;\n" + "int var3 = 1;\n" + "int var4 = 0;\n" + "int var5 = -1;\n\n"; - code << generateExpression2_conditionalCode("", data, dataSize, numberOfGlobalConstants); + code += generateExpression2_conditionalCode("", data, dataSize, numberOfGlobalConstants); - return code.str(); + return code; } diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 4fab6bb6957..766c3b08efb 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -25,6 +25,7 @@ #define __STDC_WANT_LIB_EXT1__ 1 #include #include +#include #include #include #include @@ -53,6 +54,20 @@ #include #endif +// https://en.cppreference.com/w/cpp/io/manip/quoted +void uninitvar_std_quoted(std::stringstream &ss, const std::string &input, const char delim, const char escape) +{ + ss << std::quoted(input); + ss << std::quoted(input, delim); + ss << std::quoted(input, delim, escape); + char delimChar; + // cppcheck-suppress uninitvar + ss << std::quoted(input, delimChar); + char escapeChar; + // cppcheck-suppress uninitvar + ss << std::quoted(input, delim, escapeChar); +} + int zerodiv_ldexp() { int i = std::ldexp(0.0, 42.0); @@ -4936,3 +4951,9 @@ void unique_lock_const_ref(std::mutex& m) { std::unique_lock lock(m); } + +void eraseIteratorOutOfBounds_std_deque(std::deque& x) // #8690 +{ + // cppcheck-suppress eraseIteratorOutOfBounds + x.erase(x.end()); +} \ No newline at end of file diff --git a/test/cli/fuzz-crash/crash-26edfe9761d3b681c841dfe80398847dee332f83 b/test/cli/fuzz-crash/crash-26edfe9761d3b681c841dfe80398847dee332f83 new file mode 100644 index 00000000000..37965deed0b Binary files /dev/null and b/test/cli/fuzz-crash/crash-26edfe9761d3b681c841dfe80398847dee332f83 differ diff --git a/test/cli/fuzz-crash/crash-3ea64296c8518edb538e0047c3eba0792d5deeba b/test/cli/fuzz-crash/crash-3ea64296c8518edb538e0047c3eba0792d5deeba new file mode 100644 index 00000000000..f096de3bf78 Binary files /dev/null and b/test/cli/fuzz-crash/crash-3ea64296c8518edb538e0047c3eba0792d5deeba differ diff --git a/test/cli/fuzz-crash/crash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 b/test/cli/fuzz-crash/crash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 new file mode 100644 index 00000000000..80a938891ac Binary files /dev/null and b/test/cli/fuzz-crash/crash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 differ diff --git a/test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b b/test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b new file mode 100644 index 00000000000..cf4921c19c7 --- /dev/null +++ b/test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b @@ -0,0 +1,12 @@ +#include +sho main() +{ + std::veCtor items(2); + stdtryector::iterator iter; + for (iter -= items.begin(); i&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ter != items.end();) { + if (*iter == 2) { + iter = items.erase//(iter); + } else { + } + } +} diff --git a/test/cli/fuzz-crash/crash-e4a26f2d7d0a73836bf086f54e48204d8914b95a b/test/cli/fuzz-crash/crash-e4a26f2d7d0a73836bf086f54e48204d8914b95a new file mode 100644 index 00000000000..89b9bf0f48b Binary files /dev/null and b/test/cli/fuzz-crash/crash-e4a26f2d7d0a73836bf086f54e48204d8914b95a differ diff --git a/test/cli/fuzz_test.py b/test/cli/fuzz_test.py new file mode 100644 index 00000000000..91f1dc84a9f --- /dev/null +++ b/test/cli/fuzz_test.py @@ -0,0 +1,16 @@ +import os +from testutils import cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) + + +def test_fuzz_crash(): + failures = {} + + fuzz_crash_dir = os.path.join(__script_dir, 'fuzz-crash') + for f in os.listdir(fuzz_crash_dir): + ret, stdout, _ = cppcheck(['-q', '--enable=all', '--inconclusive', f], cwd=fuzz_crash_dir) + if ret != 0: + failures[f] = stdout + + assert failures == {} diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index b3096edffcb..a63538f346b 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -230,6 +230,8 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedefShadow); // #4445 - shadow variable TEST_CASE(simplifyTypedefMacro); + + TEST_CASE(simplifyTypedefOriginalName); } #define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__) @@ -4131,6 +4133,62 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS("void foo ( uint32_t prev_segment ) { if ( prev_segment == ( ( uint32_t ) 12 ) ) { } }", simplifyTypedefP(code)); } + + void simplifyTypedefOriginalName() { + const char code[] = "typedef unsigned char uint8_t;" + "typedef float (*rFunctionPointer_fp)(uint8_t, uint8_t);" + "typedef enum eEnumDef {" + " ABC = 0," + "}eEnum_t;" + "typedef enum {" + " ABC = 0," + "}eEnum2_t;" + "typedef short int16_t;" + "typedef struct stStructDef {" + " int16_t swA;" + "}stStruct_t;" + "double endOfTypeDef;" + "eEnum2_t enum2Type;" + "stStruct_t structType;" + "eEnum_t enumType;" + "uint8_t t;" + "void test(rFunctionPointer_fp functionPointer);"; + + Tokenizer tokenizer(settings1, this); + std::istringstream istr(code); + tokenizer.list.createTokens(istr, "file.c"); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + + try { + tokenizer.validate(); + } + catch (const InternalError&) { + ASSERT_EQUALS_MSG(false, true, "Validation of Tokenizer failed"); + } + + const Token* token; + // Get the Token which is at the end of all the Typedef's in this case i placed a variable + const Token* endOfTypeDef = Token::findsimplematch(tokenizer.list.front(), "endOfTypeDef", tokenizer.list.back()); + // Search for the simplified char token and check its original Name + token = Token::findsimplematch(endOfTypeDef, "char", tokenizer.list.back()); + ASSERT_EQUALS("uint8_t", token->originalName()); + // Search for the simplified eEnumDef token and check its original Name + token = Token::findsimplematch(endOfTypeDef, "eEnumDef", tokenizer.list.back()); + ASSERT_EQUALS("eEnum_t", token->originalName()); + // Search for the eEnum2_t token as it does not have a name it should be the direct type name + token = Token::findsimplematch(endOfTypeDef, "eEnum2_t", tokenizer.list.back()); + ASSERT_EQUALS("eEnum2_t", token->str()); + // Search for the simplified stStructDef token and check its original Name + token = Token::findsimplematch(endOfTypeDef, "stStructDef", tokenizer.list.back()); + ASSERT_EQUALS("stStruct_t", token->originalName()); + // Search for the simplified short token and check its original Name, start from front to get the variable in the struct + token = Token::findsimplematch(tokenizer.list.front(), "short", tokenizer.list.back()); + ASSERT_EQUALS("int16_t", token->originalName()); + // Search for the simplified * token -> function pointer gets "(*" tokens infront of it + token = Token::findsimplematch(endOfTypeDef, "*", tokenizer.list.back()); + ASSERT_EQUALS("rFunctionPointer_fp", token->originalName()); + } }; REGISTER_TEST(TestSimplifyTypedef) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 1c42d76fdf9..b3e0818d8e5 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1413,6 +1413,53 @@ class TestSymbolDatabase : public TestFixture { ASSERT(p->valueType()->volatileness == 2); ASSERT(p->valueType()->reference == Reference::None); } + { + GET_SYMBOL_DB_C("typedef unsigned char uint8_t;\n uint8_t ubVar = 0;\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "uint8_t"); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB_C("typedef enum eEnumDef {CPPCHECK=0}eEnum_t;\n eEnum_t eVar = CPPCHECK;\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "eEnum_t"); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB_C("typedef unsigned char uint8_t;\n typedef struct stStructDef {uint8_t ubTest;}stStruct_t;\n stStruct_t stVar;\n"); + const Variable* p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "uint8_t"); + ASSERT(p->valueType()->reference == Reference::None); + p = db->getVariableFromVarId(2); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "stStruct_t"); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB_C("typedef int (*ubFunctionPointer_fp)(int);\n void test(ubFunctionPointer_fp functionPointer);\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "ubFunctionPointer_fp"); + ASSERT(p->valueType()->reference == Reference::None); + } } void VariableValueTypeTemplate() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 03b780eab47..6fa10173b07 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -409,6 +409,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(checkRefQualifiers); TEST_CASE(checkConditionBlock); TEST_CASE(checkUnknownCircularVar); + TEST_CASE(checkRequires); // #9052 TEST_CASE(noCrash1); @@ -7559,6 +7560,12 @@ class TestTokenizer : public TestFixture { "}\n")); } + void checkRequires() + { + ASSERT_NO_THROW(tokenizeAndStringify("template\n" + "struct X { X(U) requires true {} };\n")); + } + void noCrash1() { ASSERT_NO_THROW(tokenizeAndStringify( "struct A {\n"