| 1933 | } |
| 1934 | |
| 1935 | void TokenList::validateAst(bool print) const |
| 1936 | { |
| 1937 | OnException oe{[&] { |
| 1938 | if (print) |
| 1939 | mTokensFrontBack->front->printOut(std::cout); |
| 1940 | }}; |
| 1941 | // Check for some known issues in AST to avoid crash/hang later on |
| 1942 | std::set<const Token*> safeAstTokens; // list of "safe" AST tokens without endless recursion |
| 1943 | for (const Token *tok = mTokensFrontBack->front; tok; tok = tok->next()) { |
| 1944 | // Syntax error if binary operator only has 1 operand |
| 1945 | if ((tok->isAssignmentOp() || tok->isComparisonOp() || Token::Match(tok,"[|^/%]")) && tok->astOperand1() && !tok->astOperand2()) |
| 1946 | throw InternalError(tok, "Syntax Error: AST broken, binary operator has only one operand.", InternalError::AST); |
| 1947 | |
| 1948 | // Syntax error if we encounter "?" with operand2 that is not ":" |
| 1949 | if (tok->str() == "?") { |
| 1950 | if (!tok->astOperand1() || !tok->astOperand2()) |
| 1951 | throw InternalError(tok, "AST broken, ternary operator missing operand(s)", InternalError::AST); |
| 1952 | if (tok->astOperand2()->str() != ":") |
| 1953 | throw InternalError(tok, "Syntax Error: AST broken, ternary operator lacks ':'.", InternalError::AST); |
| 1954 | } |
| 1955 | |
| 1956 | // Check for endless recursion |
| 1957 | const Token* parent = tok->astParent(); |
| 1958 | if (parent) { |
| 1959 | std::set<const Token*> astTokens; // list of ancestors |
| 1960 | astTokens.insert(tok); |
| 1961 | do { |
| 1962 | if (safeAstTokens.find(parent) != safeAstTokens.end()) |
| 1963 | break; |
| 1964 | if (astTokens.find(parent) != astTokens.end()) |
| 1965 | throw InternalError(tok, "AST broken: endless recursion from '" + tok->str() + "'", InternalError::AST); |
| 1966 | astTokens.insert(parent); |
| 1967 | } while ((parent = parent->astParent()) != nullptr); |
| 1968 | safeAstTokens.insert(astTokens.cbegin(), astTokens.cend()); |
| 1969 | } else if (tok->str() == ";") { |
| 1970 | safeAstTokens.clear(); |
| 1971 | } else { |
| 1972 | safeAstTokens.insert(tok); |
| 1973 | } |
| 1974 | |
| 1975 | // Don't check templates |
| 1976 | if (tok->str() == "<" && tok->link()) { |
| 1977 | tok = tok->link(); |
| 1978 | continue; |
| 1979 | } |
| 1980 | if (tok->isCast()) { |
| 1981 | if (!tok->astOperand2() && precedes(tok->astOperand1(), tok)) |
| 1982 | throw InternalError(tok, "AST broken: '" + tok->str() + "' has improper operand.", InternalError::AST); |
| 1983 | if (tok->astOperand1() && tok->link()) { // skip casts (not part of the AST) |
| 1984 | tok = tok->link(); |
| 1985 | continue; |
| 1986 | } |
| 1987 | } |
| 1988 | |
| 1989 | if (findLambdaEndToken(tok)) { // skip lambda captures |
| 1990 | tok = tok->link(); |
| 1991 | continue; |
| 1992 | } |