Summaries: Enhanced merge of noreturn info

This commit is contained in:
Daniel Marjamäki 2020-12-20 14:49:34 +01:00
parent bf825ea14f
commit 1bf6a2f62b
3 changed files with 63 additions and 12 deletions

View File

@ -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");
// noreturn.. functionCalls[functionName] = call;
if (line.find(" noreturn:[") != std::string::npos || line.find(" call:[") != std::string::npos) if (call.empty())
summaryNoreturn[functionName] = true; return1.push_back(functionName);
else else {
// If there is a value for function already keep it, otherwise insert false for (const std::string &c: call) {
summaryNoreturn.insert(std::pair<std::string,bool>(functionName, false)); functionCalledBy[c].push_back(functionName);
}
}
} }
} }
summaryReturn.insert(return1.cbegin(), return1.cend());
// recursively set "summaryNoreturn"
for (const std::string &f: return1) {
std::vector<std::string> return2;
removeFunctionCalls(f, functionCalledBy, functionCalls, return2);
summaryReturn.insert(return2.cbegin(), return2.cend());
}
} }

View File

@ -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();

View File

@ -8724,10 +8724,8 @@ 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); return false;
if (it != mSettings->summaryNoreturn.end() && !it->second)
return false;
} }
if (unknown) if (unknown)
*unknown = !unknownFunc.empty(); *unknown = !unknownFunc.empty();