Summaries: Enhanced merge of noreturn info
This commit is contained in:
parent
bf825ea14f
commit
1bf6a2f62b
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "valueflow.h"
|
#include "valueflow.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
std::atomic<bool> Settings::mTerminated;
|
std::atomic<bool> Settings::mTerminated;
|
||||||
|
@ -177,11 +178,53 @@ static std::vector<std::string> getSummaryFiles(const std::string &filename)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> getSummaryData(const std::string &line, const std::string &data)
|
||||||
|
{
|
||||||
|
std::vector<std::string> ret;
|
||||||
|
const std::string::size_type start = line.find(" " + data + ":[");
|
||||||
|
if (start == std::string::npos)
|
||||||
|
return ret;
|
||||||
|
const std::string::size_type end = line.find("]", start);
|
||||||
|
if (end >= line.size())
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
std::string::size_type pos1 = start + 3 + data.size();
|
||||||
|
while (pos1 < end) {
|
||||||
|
std::string::size_type pos2 = line.find_first_of(",]",pos1);
|
||||||
|
ret.push_back(line.substr(pos1, pos2-pos1-1));
|
||||||
|
pos1 = pos2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void removeFunctionCalls(const std::string& calledFunction,
|
||||||
|
std::map<std::string, std::vector<std::string>> &functionCalledBy,
|
||||||
|
std::map<std::string, std::vector<std::string>> &functionCalls,
|
||||||
|
std::vector<std::string> &add)
|
||||||
|
{
|
||||||
|
std::vector<std::string> calledBy = functionCalledBy[calledFunction];
|
||||||
|
functionCalledBy.erase(calledFunction);
|
||||||
|
for (const std::string &c: calledBy) {
|
||||||
|
std::vector<std::string> &calls = functionCalls[c];
|
||||||
|
calls.erase(std::remove(calls.begin(), calls.end(), calledFunction), calls.end());
|
||||||
|
if (calls.empty()) {
|
||||||
|
add.push_back(calledFunction);
|
||||||
|
removeFunctionCalls(c, functionCalledBy, functionCalls, add);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Settings::loadSummaries()
|
void Settings::loadSummaries()
|
||||||
{
|
{
|
||||||
if (buildDir.empty())
|
if (buildDir.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::vector<std::string> return1;
|
||||||
|
std::map<std::string, std::vector<std::string>> functionCalls;
|
||||||
|
std::map<std::string, std::vector<std::string>> functionCalledBy;
|
||||||
|
|
||||||
|
// extract "functionNoreturn" and "functionCalledBy" from summaries
|
||||||
std::vector<std::string> summaryFiles = getSummaryFiles(buildDir + "/files.txt");
|
std::vector<std::string> summaryFiles = getSummaryFiles(buildDir + "/files.txt");
|
||||||
for (const std::string &filename: summaryFiles) {
|
for (const std::string &filename: summaryFiles) {
|
||||||
std::ifstream fin(buildDir + '/' + filename);
|
std::ifstream fin(buildDir + '/' + filename);
|
||||||
|
@ -193,13 +236,23 @@ void Settings::loadSummaries()
|
||||||
const std::string::size_type pos1 = 0;
|
const std::string::size_type pos1 = 0;
|
||||||
const std::string::size_type pos2 = line.find(" ", pos1);
|
const std::string::size_type pos2 = line.find(" ", pos1);
|
||||||
const std::string functionName = (pos2 == std::string::npos) ? line : line.substr(0, pos2);
|
const std::string functionName = (pos2 == std::string::npos) ? line : line.substr(0, pos2);
|
||||||
|
std::vector<std::string> call = getSummaryData(line, "call");
|
||||||
|
functionCalls[functionName] = call;
|
||||||
|
if (call.empty())
|
||||||
|
return1.push_back(functionName);
|
||||||
|
else {
|
||||||
|
for (const std::string &c: call) {
|
||||||
|
functionCalledBy[c].push_back(functionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
summaryReturn.insert(return1.cbegin(), return1.cend());
|
||||||
|
|
||||||
// noreturn..
|
// recursively set "summaryNoreturn"
|
||||||
if (line.find(" noreturn:[") != std::string::npos || line.find(" call:[") != std::string::npos)
|
for (const std::string &f: return1) {
|
||||||
summaryNoreturn[functionName] = true;
|
std::vector<std::string> return2;
|
||||||
else
|
removeFunctionCalls(f, functionCalledBy, functionCalls, return2);
|
||||||
// If there is a value for function already keep it, otherwise insert false
|
summaryReturn.insert(return2.cbegin(), return2.cend());
|
||||||
summaryNoreturn.insert(std::pair<std::string,bool>(functionName, false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,7 +416,7 @@ public:
|
||||||
return Settings::mTerminated;
|
return Settings::mTerminated;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, bool> summaryNoreturn;
|
std::set<std::string> summaryReturn;
|
||||||
|
|
||||||
void loadSummaries();
|
void loadSummaries();
|
||||||
|
|
||||||
|
|
|
@ -8724,9 +8724,7 @@ bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
|
||||||
{
|
{
|
||||||
std::string unknownFunc;
|
std::string unknownFunc;
|
||||||
const bool ret = mSettings->library.isScopeNoReturn(endScopeToken,&unknownFunc);
|
const bool ret = mSettings->library.isScopeNoReturn(endScopeToken,&unknownFunc);
|
||||||
if (!unknownFunc.empty()) {
|
if (!unknownFunc.empty() && mSettings->summaryReturn.find(unknownFunc) != mSettings->summaryReturn.end()) {
|
||||||
const std::map<std::string, bool>::const_iterator it = mSettings->summaryNoreturn.find(unknownFunc);
|
|
||||||
if (it != mSettings->summaryNoreturn.end() && !it->second)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (unknown)
|
if (unknown)
|
||||||
|
|
Loading…
Reference in New Issue