speed up checks by caching commonly looked up stuff in the symbol database (checkexceptionsafety)
This commit is contained in:
parent
cf7996e299
commit
3064b48156
|
@ -36,12 +36,15 @@ void CheckExceptionSafety::destructors()
|
||||||
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
|
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
|
||||||
// Perform check..
|
// Perform check..
|
||||||
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
|
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||||
for (std::list<Function>::const_iterator j = i->functionList.begin(); j != i->functionList.end(); ++j) {
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
|
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||||
|
const Function * j = scope->function;
|
||||||
|
if (j) {
|
||||||
// only looking for destructors
|
// only looking for destructors
|
||||||
if (j->type == Function::eDestructor && j->functionScope) {
|
if (j->type == Function::eDestructor) {
|
||||||
// Inspect this destructor..
|
// Inspect this destructor..
|
||||||
for (const Token *tok = j->functionScope->classStart->next(); tok != j->functionScope->classEnd; tok = tok->next()) {
|
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
||||||
// Skip try blocks
|
// Skip try blocks
|
||||||
if (Token::simpleMatch(tok, "try {")) {
|
if (Token::simpleMatch(tok, "try {")) {
|
||||||
tok = tok->next()->link();
|
tok = tok->next()->link();
|
||||||
|
@ -70,52 +73,56 @@ void CheckExceptionSafety::deallocThrow()
|
||||||
|
|
||||||
// Deallocate a global/member pointer and then throw exception
|
// Deallocate a global/member pointer and then throw exception
|
||||||
// the pointer will be a dead pointer
|
// the pointer will be a dead pointer
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||||
// only looking for delete now
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
if (tok->str() != "delete")
|
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||||
continue;
|
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
||||||
|
// only looking for delete now
|
||||||
|
if (tok->str() != "delete")
|
||||||
|
continue;
|
||||||
|
|
||||||
// Check if this is something similar with: "delete p;"
|
// Check if this is something similar with: "delete p;"
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
if (Token::simpleMatch(tok, "[ ]"))
|
if (Token::simpleMatch(tok, "[ ]"))
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
if (!tok)
|
if (!tok)
|
||||||
break;
|
break;
|
||||||
if (!Token::Match(tok, "%var% ;"))
|
if (!Token::Match(tok, "%var% ;"))
|
||||||
continue;
|
continue;
|
||||||
const unsigned int varid(tok->varId());
|
const unsigned int varid(tok->varId());
|
||||||
if (varid == 0)
|
if (varid == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we only look for global variables
|
// we only look for global variables
|
||||||
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
|
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
|
||||||
if (!var || !(var->isGlobal() || var->isStatic()))
|
if (!var || !(var->isGlobal() || var->isStatic()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Token where throw occurs
|
// Token where throw occurs
|
||||||
const Token *ThrowToken = 0;
|
const Token *ThrowToken = 0;
|
||||||
|
|
||||||
// is there a throw after the deallocation?
|
// is there a throw after the deallocation?
|
||||||
const Token* const end2 = tok->scope()->classEnd;
|
const Token* const end2 = tok->scope()->classEnd;
|
||||||
for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) {
|
for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) {
|
||||||
// Throw after delete -> Dead pointer
|
// Throw after delete -> Dead pointer
|
||||||
if (tok2->str() == "throw") {
|
if (tok2->str() == "throw") {
|
||||||
if (_settings->inconclusive) { // For inconclusive checking, throw directly.
|
if (_settings->inconclusive) { // For inconclusive checking, throw directly.
|
||||||
deallocThrowError(tok2, tok->str());
|
deallocThrowError(tok2, tok->str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ThrowToken = tok2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable is assigned -> Bail out
|
||||||
|
else if (Token::Match(tok2, "%varid% =", varid)) {
|
||||||
|
if (ThrowToken) // For non-inconclusive checking, wait until we find an assignement to it. Otherwise we assume it is safe to leave a dead pointer.
|
||||||
|
deallocThrowError(ThrowToken, tok2->str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ThrowToken = tok2;
|
// Variable passed to function. Assume it becomes assigned -> Bail out
|
||||||
|
else if (Token::Match(tok2, "[,(] &| %varid% [,)]", varid)) // TODO: No bailout if passed by value or as const reference
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variable is assigned -> Bail out
|
|
||||||
else if (Token::Match(tok2, "%varid% =", varid)) {
|
|
||||||
if (ThrowToken) // For non-inconclusive checking, wait until we find an assignement to it. Otherwise we assume it is safe to leave a dead pointer.
|
|
||||||
deallocThrowError(ThrowToken, tok2->str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Variable passed to function. Assume it becomes assigned -> Bail out
|
|
||||||
else if (Token::Match(tok2, "[,(] &| %varid% [,)]", varid)) // TODO: No bailout if passed by value or as const reference
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue