library: improved handling of noreturn. The Tokenizer::isScopeNoReturn will now try to use the library to determine if scope is noreturn.
This commit is contained in:
parent
7d237579c9
commit
b2f6e9e3eb
|
@ -33,7 +33,7 @@ Library::Library() : allocid(0)
|
||||||
_dealloc["fclose"] = allocid;
|
_dealloc["fclose"] = allocid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Library::Library(const Library &lib) : use(lib.use), ignore(lib.ignore), noreturn(lib.noreturn), allocid(lib.allocid), _alloc(lib._alloc), _dealloc(lib._dealloc)
|
Library::Library(const Library &lib) : use(lib.use), ignore(lib.ignore), allocid(lib.allocid), _alloc(lib._alloc), _dealloc(lib._dealloc), _noreturn(lib._noreturn)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,28 @@ bool Library::load(const char path[])
|
||||||
|
|
||||||
else if (strcmp(node->Name(),"ignore")==0)
|
else if (strcmp(node->Name(),"ignore")==0)
|
||||||
ignore.insert(node->GetText());
|
ignore.insert(node->GetText());
|
||||||
else if (strcmp(node->Name(),"noreturn")==0)
|
else if (strcmp(node->Name(),"function")==0) {
|
||||||
noreturn.insert(node->GetText());
|
const char *name = node->Attribute("name");
|
||||||
else
|
if (name == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) {
|
||||||
|
if (strcmp(functionnode->Name(),"noreturn")==0)
|
||||||
|
_noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0);
|
||||||
|
else if (strcmp(functionnode->Name(),"arg")==0 && functionnode->Attribute("nr") != NULL) {
|
||||||
|
const int nr = atoi(functionnode->Attribute("nr"));
|
||||||
|
|
||||||
|
const char *nullpointer = functionnode->Attribute("nullpointer");
|
||||||
|
const char *uninitdata = functionnode->Attribute("uninitdata");
|
||||||
|
const char *uninitderefdata = functionnode->Attribute("uninitderefdata");
|
||||||
|
|
||||||
|
functionArgument[name][nr].nullpointer = (nullpointer != NULL);
|
||||||
|
functionArgument[name][nr].uninitdata = (uninitdata != NULL);
|
||||||
|
functionArgument[name][nr].uninitderefdata = (uninitderefdata != NULL);
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -60,12 +60,31 @@ public:
|
||||||
|
|
||||||
std::set<std::string> use;
|
std::set<std::string> use;
|
||||||
std::set<std::string> ignore;
|
std::set<std::string> ignore;
|
||||||
std::set<std::string> noreturn;
|
|
||||||
|
bool isnoreturn(const std::string &name) const {
|
||||||
|
std::map<std::string,bool>::const_iterator it = _noreturn.find(name);
|
||||||
|
return (it != _noreturn.end() && it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isnotnoreturn(const std::string &name) const {
|
||||||
|
std::map<std::string,bool>::const_iterator it = _noreturn.find(name);
|
||||||
|
return (it != _noreturn.end() && !it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Argument {
|
||||||
|
bool nullpointer;
|
||||||
|
bool uninitdata;
|
||||||
|
bool uninitderefdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
// function name, argument nr => argument data
|
||||||
|
std::map<std::string, std::map<int, Argument> > functionArgument;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int allocid;
|
int allocid;
|
||||||
std::map<std::string, int> _alloc; // allocation functions
|
std::map<std::string, int> _alloc; // allocation functions
|
||||||
std::map<std::string, int> _dealloc; // deallocation functions
|
std::map<std::string, int> _dealloc; // deallocation functions
|
||||||
|
std::map<std::string, bool> _noreturn; // is function noreturn?
|
||||||
|
|
||||||
int getid(const std::map<std::string,int> &data, const std::string &name) const {
|
int getid(const std::map<std::string,int> &data, const std::string &name) const {
|
||||||
const std::map<std::string,int>::const_iterator it = data.find(name);
|
const std::map<std::string,int>::const_iterator it = data.find(name);
|
||||||
|
|
|
@ -7731,7 +7731,7 @@ void Tokenizer::simplifyStd()
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool Tokenizer::IsScopeNoReturn(const Token *endScopeToken, bool *unknown)
|
bool Tokenizer::IsScopeNoReturn(const Token *endScopeToken, bool *unknown) const
|
||||||
{
|
{
|
||||||
if (unknown)
|
if (unknown)
|
||||||
*unknown = false;
|
*unknown = false;
|
||||||
|
@ -7755,6 +7755,13 @@ bool Tokenizer::IsScopeNoReturn(const Token *endScopeToken, bool *unknown)
|
||||||
while (tok && (Token::Match(tok, "::|.") || tok->isName()))
|
while (tok && (Token::Match(tok, "::|.") || tok->isName()))
|
||||||
tok = tok->previous();
|
tok = tok->previous();
|
||||||
|
|
||||||
|
if (Token::Match(tok, "[;{}] %var% (")) {
|
||||||
|
if (_settings->library.isnoreturn(tok->next()->str()))
|
||||||
|
return true;
|
||||||
|
if (_settings->library.isnotnoreturn(tok->next()->str()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, "[;{}]")) {
|
if (Token::Match(tok, "[;{}]")) {
|
||||||
if (unknown)
|
if (unknown)
|
||||||
*unknown = true;
|
*unknown = true;
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
* \param unknown set to true if it's unknown if the scope is noreturn
|
* \param unknown set to true if it's unknown if the scope is noreturn
|
||||||
* \return true if scope ends with a function call that might be 'noreturn'
|
* \return true if scope ends with a function call that might be 'noreturn'
|
||||||
*/
|
*/
|
||||||
static bool IsScopeNoReturn(const Token *endScopeToken, bool *unknown = 0);
|
bool IsScopeNoReturn(const Token *endScopeToken, bool *unknown = 0) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tokenize code
|
* Tokenize code
|
||||||
|
|
Loading…
Reference in New Issue