diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 1ee239a9e74..a6faf744599 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1565,82 +1565,84 @@ namespace { }; using ExprIdMap = std::map; void setParentExprId(Token* tok, ExprIdMap& exprIdMap, nonneg int &id) { - if (!tok->astParent() || tok->astParent()->isControlFlowKeyword()) - return; - const Token* op1 = tok->astParent()->astOperand1(); - if (op1 && op1->exprId() == 0 && !Token::Match(op1, "[{[]")) - return; - const Token* op2 = tok->astParent()->astOperand2(); - if (op2 && op2->exprId() == 0 && - !((tok->astParent()->astParent() && tok->astParent()->isAssignmentOp() && tok->astParent()->astParent()->isAssignmentOp()) || - isLambdaCaptureList(op2) || - (op2->str() == "(" && isLambdaCaptureList(op2->astOperand1())) || - Token::simpleMatch(op2, "{ }"))) - return; + for (;;) { + if (!tok->astParent() || tok->astParent()->isControlFlowKeyword()) + break; + const Token* op1 = tok->astParent()->astOperand1(); + if (op1 && op1->exprId() == 0 && !Token::Match(op1, "[{[]")) + break; + const Token* op2 = tok->astParent()->astOperand2(); + if (op2 && op2->exprId() == 0 && + !((tok->astParent()->astParent() && tok->astParent()->isAssignmentOp() && tok->astParent()->astParent()->isAssignmentOp()) || + isLambdaCaptureList(op2) || + (op2->str() == "(" && isLambdaCaptureList(op2->astOperand1())) || + Token::simpleMatch(op2, "{ }"))) + break; - if (tok->astParent()->isExpandedMacro() || Token::Match(tok->astParent(), "++|--")) { - tok->astParent()->exprId(id); - ++id; - setParentExprId(tok->astParent(), exprIdMap, id); - return; - } + if (tok->astParent()->isExpandedMacro() || Token::Match(tok->astParent(), "++|--")) { + tok->astParent()->exprId(id); + ++id; + tok = tok->astParent(); + continue; + } - ExprIdKey key; - key.parentOp = tok->astParent()->str(); - key.operand1 = op1 ? op1->exprId() : 0; - key.operand2 = op2 ? op2->exprId() : 0; + ExprIdKey key; + key.parentOp = tok->astParent()->str(); + key.operand1 = op1 ? op1->exprId() : 0; + key.operand2 = op2 ? op2->exprId() : 0; - if (tok->astParent()->isCast() && tok->astParent()->str() == "(") { - const Token* typeStartToken; - const Token* typeEndToken; - if (tok->astParent()->astOperand2()) { - typeStartToken = tok->astParent()->astOperand1(); - typeEndToken = tok; - } else { - typeStartToken = tok->astParent()->next(); - typeEndToken = tok->astParent()->link(); - } - std::string type; - for (const Token* t = typeStartToken; t != typeEndToken; t = t->next()) { - type += " " + t->str(); + if (tok->astParent()->isCast() && tok->astParent()->str() == "(") { + const Token* typeStartToken; + const Token* typeEndToken; + if (tok->astParent()->astOperand2()) { + typeStartToken = tok->astParent()->astOperand1(); + typeEndToken = tok; + } else { + typeStartToken = tok->astParent()->next(); + typeEndToken = tok->astParent()->link(); + } + std::string type; + for (const Token* t = typeStartToken; t != typeEndToken; t = t->next()) { + type += " " + t->str(); + } + key.parentOp += type; } - key.parentOp += type; - } - for (const auto& ref: followAllReferences(op1)) { - if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm - key.operand1 = ref.token->exprId(); - break; + for (const auto& ref: followAllReferences(op1)) { + if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm + key.operand1 = ref.token->exprId(); + break; + } } - } - for (const auto& ref: followAllReferences(op2)) { - if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm - key.operand2 = ref.token->exprId(); - break; + for (const auto& ref: followAllReferences(op2)) { + if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm + key.operand2 = ref.token->exprId(); + break; + } } - } - if (key.operand1 > key.operand2 && key.operand2 && - Token::Match(tok->astParent(), "%or%|%oror%|+|*|&|&&|^|==|!=")) { - // In C++ the order of operands of + might matter - if (!tok->isCpp() || - key.parentOp != "+" || - !tok->astParent()->valueType() || - tok->astParent()->valueType()->isIntegral() || - tok->astParent()->valueType()->isFloat() || - tok->astParent()->valueType()->pointer > 0) - std::swap(key.operand1, key.operand2); - } + if (key.operand1 > key.operand2 && key.operand2 && + Token::Match(tok->astParent(), "%or%|%oror%|+|*|&|&&|^|==|!=")) { + // In C++ the order of operands of + might matter + if (!tok->isCpp() || + key.parentOp != "+" || + !tok->astParent()->valueType() || + tok->astParent()->valueType()->isIntegral() || + tok->astParent()->valueType()->isFloat() || + tok->astParent()->valueType()->pointer > 0) + std::swap(key.operand1, key.operand2); + } - const auto it = exprIdMap.find(key); - if (it == exprIdMap.end()) { - exprIdMap[key] = id; - tok->astParent()->exprId(id); - ++id; - } else { - tok->astParent()->exprId(it->second); + const auto it = exprIdMap.find(key); + if (it == exprIdMap.end()) { + exprIdMap[key] = id; + tok->astParent()->exprId(id); + ++id; + } else { + tok->astParent()->exprId(it->second); + } + tok = tok->astParent(); } - setParentExprId(tok->astParent(), exprIdMap, id); } } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 195924e7191..b34e9ae4f5f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4838,7 +4838,7 @@ void Tokenizer::setVarIdPass1() } // function declaration inside executable scope? Function declaration is of form: type name "(" args ")" - if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)[]")) { + if (scopeStack.top().isExecutable && !scopeStack.top().isStructInit && Token::Match(tok, "%name% [,)[]")) { bool par = false; const Token* start; Token* end; diff --git a/test/cli/performance_test.py b/test/cli/performance_test.py index 4dc23f9efe5..f79203377c5 100644 --- a/test/cli/performance_test.py +++ b/test/cli/performance_test.py @@ -219,3 +219,22 @@ def test_slow_many_scopes(tmpdir): return EXIT_SUCCESS; }""") cppcheck([filename]) # should not take more than ~1 second + +@pytest.mark.timeout(20) +def test_crash_array_in_namespace(tmpdir): + # 12847 + filename = os.path.join(tmpdir, 'hang.cpp') + with open(filename, 'wt') as f: + f.write(r""" + #define ROW A, A, A, A, A, A, A, A, + #define ROW8 ROW ROW ROW ROW ROW ROW ROW ROW + #define ROW64 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 + #define ROW512 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 + #define ROW4096 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 + namespace N { + static const char A = 'a'; + const char a[] = { + ROW4096 ROW4096 ROW4096 ROW4096 + }; + }""") + cppcheck([filename]) # should not take more than ~5 seconds