/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "executionpath.h" #include "token.h" #include // default : bail out if the condition is has variable handling bool ExecutionPath::parseCondition(const Token &tok, std::list & /*checks*/) const { unsigned int parlevel = 0; for (const Token *tok2 = &tok; tok2; tok2 = tok2->next()) { if (tok2->str() == "(") ++parlevel; else if (tok2->str() == ")") { if (parlevel == 0) break; --parlevel; } else if (Token::Match(tok2, ";{}")) break; if (tok2->varId() != 0) { return true; } } return false; } const Token *checkExecutionPaths(const Token *tok, std::list &checks) { const std::auto_ptr check(checks.front()->copy()); // Number of "if" blocks in current scope unsigned int numberOfIf = 0; for (; tok; tok = tok->next()) { if (tok->str() == "}") return 0; // todo: handle for/while if (Token::Match(tok, "for|while|switch")) { ExecutionPath::bailOut(checks); return 0; } // don't parse into "struct type { .." if (Token::Match(tok, "struct %type% {")) tok = tok->tokAt(2)->link(); if (Token::Match(tok, "= {") || Token::Match(tok, "= ( %type% !!=")) { tok = tok->next()->link(); if (Token::simpleMatch(tok, ") {")) tok = tok->next()->link(); if (!tok) { ExecutionPath::bailOut(checks); return 0; } continue; } if (tok->str() == "if") { ++numberOfIf; if (numberOfIf > 1) return 0; std::list newchecks; while (tok->str() == "if") { // goto "(" tok = tok->next(); // parse condition if (check->parseCondition(*tok->next(), checks)) { ExecutionPath::bailOut(checks); return 0; } // goto ")" tok = tok ? tok->link() : 0; // goto "{" tok = tok ? tok->next() : 0; if (!Token::simpleMatch(tok, "{")) return 0; // Recursively check into the if .. { std::list c; std::list::iterator it; for (it = checks.begin(); it != checks.end(); ++it) c.push_back((*it)->copy()); const Token *tokerr = checkExecutionPaths(tok->next(), c); if (tokerr) return tokerr; while (!c.empty()) { newchecks.push_back(c.back()); c.pop_back(); } } // goto "}" tok = tok->link(); // there is no else => break out if (Token::Match(tok, "} !!else")) break; // parse next "if".. tok = tok->tokAt(2); if (tok->str() == "if") continue; // there is no "if".. const Token *tokerr = checkExecutionPaths(tok->next(), checks); if (tokerr) return tokerr; tok = tok->link(); if (!tok) return 0; } std::list::iterator it; for (it = newchecks.begin(); it != newchecks.end(); ++it) checks.push_back((*it)->copy()); } { bool foundError = false; tok = check->parse(*tok, foundError, checks); std::list::iterator it; for (it = checks.begin(); it != checks.end();) { if ((*it)->bailOut()) { delete *it; it = checks.erase(it); } else { ++it; } } if (checks.empty()) return 0; else if (foundError) return tok; } // return ends all execution paths if (tok->str() == "return") { ExecutionPath::bailOut(checks); } } return 0; }