"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/importproject.cpp" between
cppcheck-1.86.tar.gz and cppcheck-1.87.tar.gz

About: Cppcheck is a static analysis tool for C/C++ code. It checks for memory leaks, mismatching allocation-deallocation, buffer overrun, and many more.

importproject.cpp  (cppcheck-1.86):importproject.cpp  (cppcheck-1.87)
/* /*
* Cppcheck - A tool for static C/C++ code analysis * Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2018 Cppcheck team. * Copyright (C) 2007-2019 Cppcheck team.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
skipping to change at line 28 skipping to change at line 28
#include "importproject.h" #include "importproject.h"
#include "path.h" #include "path.h"
#include "settings.h" #include "settings.h"
#include "tinyxml2.h" #include "tinyxml2.h"
#include "token.h" #include "token.h"
#include "tokenize.h" #include "tokenize.h"
#include "tokenlist.h" #include "tokenlist.h"
#include "utils.h" #include "utils.h"
#include "../externals/picojson.h"
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
#include <utility> #include <utility>
void ImportProject::ignorePaths(const std::vector<std::string> &ipaths) void ImportProject::ignorePaths(const std::vector<std::string> &ipaths)
{ {
for (std::list<FileSettings>::iterator it = fileSettings.begin(); it != file Settings.end();) { for (std::list<FileSettings>::iterator it = fileSettings.begin(); it != file Settings.end();) {
bool ignore = false; bool ignore = false;
for (std::size_t i = 0; i < ipaths.size(); ++i) { for (std::size_t i = 0; i < ipaths.size(); ++i) {
skipping to change at line 169 skipping to change at line 170
if (!simplifyPathWithVariables(s, variables)) if (!simplifyPathWithVariables(s, variables))
continue; continue;
} }
if (s.empty()) if (s.empty())
continue; continue;
I.push_back(s + '/'); I.push_back(s + '/');
} }
includePaths.swap(I); includePaths.swap(I);
} }
ImportProject::Type ImportProject::import(const std::string &filename) ImportProject::Type ImportProject::import(const std::string &filename, Settings *settings)
{ {
std::ifstream fin(filename); std::ifstream fin(filename);
if (!fin.is_open()) if (!fin.is_open())
return MISSING; return ImportProject::Type::MISSING;
if (endsWith(filename, ".json", 5)) { if (endsWith(filename, ".json", 5)) {
importCompileCommands(fin); importCompileCommands(fin);
return COMPILE_DB; return ImportProject::Type::COMPILE_DB;
} else if (endsWith(filename, ".sln", 4)) { } else if (endsWith(filename, ".sln", 4)) {
std::string path(Path::getPathFromFilename(Path::fromNativeSeparators(fi lename))); std::string path(Path::getPathFromFilename(Path::fromNativeSeparators(fi lename)));
if (!path.empty() && !endsWith(path,'/')) if (!path.empty() && !endsWith(path,'/'))
path += '/'; path += '/';
importSln(fin,path); importSln(fin,path);
return VS_SLN; return ImportProject::Type::VS_SLN;
} else if (endsWith(filename, ".vcxproj", 8)) { } else if (endsWith(filename, ".vcxproj", 8)) {
std::map<std::string, std::string, cppcheck::stricmp> variables; std::map<std::string, std::string, cppcheck::stricmp> variables;
importVcxproj(filename, variables, emptyString); importVcxproj(filename, variables, emptyString);
return VS_VCXPROJ; return ImportProject::Type::VS_VCXPROJ;
} else if (endsWith(filename, ".bpr", 4)) { } else if (endsWith(filename, ".bpr", 4)) {
importBcb6Prj(filename); importBcb6Prj(filename);
return BORLAND; return ImportProject::Type::BORLAND;
} else if (settings && endsWith(filename, ".cppcheck", 9)) {
return importCppcheckGuiProject(fin, settings) ? ImportProject::Type::CP
PCHECK_GUI : ImportProject::Type::MISSING;
}
return ImportProject::Type::UNKNOWN;
}
static std::string readUntil(const std::string &command, std::string::size_type
*pos, const char until[])
{
std::string ret;
bool str = false;
while (*pos < command.size() && (str || !std::strchr(until, command[*pos])))
{
if (command[*pos] == '\\')
++*pos;
if (*pos < command.size())
ret += command[(*pos)++];
if (endsWith(ret, '\"'))
str = !str;
} }
return UNKNOWN; return ret;
}
void ImportProject::FileSettings::parseCommand(const std::string &command)
{
std::string defs;
// Parse command..
std::string::size_type pos = 0;
while (std::string::npos != (pos = command.find(' ',pos))) {
while (pos < command.size() && command[pos] == ' ')
pos++;
if (pos >= command.size())
break;
if (command[pos] != '/' && command[pos] != '-')
continue;
pos++;
if (pos >= command.size())
break;
const char F = command[pos++];
if (std::strchr("DUI", F)) {
while (pos < command.size() && command[pos] == ' ')
++pos;
}
const std::string fval = readUntil(command, &pos, " =");
if (F=='D') {
const std::string defval = readUntil(command, &pos, " ");
defs += fval;
if (!defval.empty())
defs += defval;
defs += ';';
} else if (F=='U')
undefs.insert(fval);
else if (F=='I')
includePaths.push_back(fval);
else if (F=='s' && fval.compare(0,3,"td=") == 0)
standard = fval.substr(3);
else if (F == 'i' && fval == "system") {
++pos;
const std::string isystem = readUntil(command, &pos, " ");
systemIncludePaths.push_back(isystem);
}
}
setDefines(defs);
} }
void ImportProject::importCompileCommands(std::istream &istr) void ImportProject::importCompileCommands(std::istream &istr)
{ {
std::map<std::string, std::string> values; picojson::value compileCommands;
istr >> compileCommands;
if (!compileCommands.is<picojson::array>())
return;
// TODO: Use a JSON parser for (const picojson::value &fileInfo : compileCommands.get<picojson::array>(
)) {
picojson::object obj = fileInfo.get<picojson::object>();
std::string dirpath = Path::fromNativeSeparators(obj["directory"].get<st
d::string>());
/* CMAKE produces the directory without trailing / so add it if not
* there - it is needed by setIncludePaths() */
if (!endsWith(dirpath, '/'))
dirpath += '/';
const std::string directory = dirpath;
const std::string command = obj["command"].get<std::string>();
const std::string file = Path::fromNativeSeparators(obj["file"].get<std:
:string>());
Settings settings; // Accept file?
TokenList tokenList(&settings); if (!Path::acceptFile(file))
tokenList.createTokens(istr); continue;
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "%str% : %str% [,}]")) { struct FileSettings fs;
const std::string& key = tok->str(); if (Path::isAbsolute(file) || Path::fileExists(file))
const std::string& value = tok->strAt(2); fs.filename = file;
values[key.substr(1, key.size() - 2U)] = value.substr(1, value.size( else {
) - 2U); std::string path = directory;
} if (!path.empty() && !endsWith(path,'/'))
path += '/';
else if (Token::Match(tok, "%str% : [ %str%") && tok->str() == "\"argume path += file;
nts\"") { fs.filename = Path::simplifyPath(path);
std::string cmd;
tok = tok->tokAt(2);
while (Token::Match(tok, ",|[ %str%")) {
const std::string &s = tok->next()->str();
cmd += ' ' + s.substr(1, s.size() - 2);
tok = tok->tokAt(2);
}
values["command"] = cmd.substr(1);
}
else if (tok->str() == "}") {
if (!values["file"].empty() && !values["command"].empty()) {
struct FileSettings fs;
fs.filename = Path::fromNativeSeparators(values["file"]);
const std::string& command = values["command"];
const std::string directory = Path::fromNativeSeparators(values[
"directory"]);
std::string::size_type pos = 0;
while (std::string::npos != (pos = command.find(' ',pos))) {
pos++;
if (pos >= command.size())
break;
if (command[pos] != '/' && command[pos] != '-')
continue;
pos++;
if (pos >= command.size())
break;
const char F = command[pos++];
if (std::strchr("DUI", F)) {
while (pos < command.size() && command[pos] == ' ')
++pos;
}
std::string fval;
while (pos < command.size() && command[pos] != ' ' && comman
d[pos] != '=') {
if (command[pos] != '\\')
fval += command[pos];
pos++;
}
if (F=='D') {
std::string defval;
bool str = false;
while (pos < command.size() && (str || command[pos] != '
')) {
if (command.compare(pos, 4, "\\\\\\\"") == 0) {
defval += '\"';
str = !str;
pos += 4;
} else {
defval += command[pos];
pos++;
}
}
fs.defines += fval;
if (!defval.empty())
fs.defines += defval;
fs.defines += ';';
} else if (F=='U')
fs.undefs.insert(fval);
else if (F=='I')
fs.includePaths.push_back(fval);
else if (F=='s' && fval.compare(0,3,"td=") == 0)
fs.standard = fval.substr(3);
else if (F == 'i' && fval == "system") {
++pos;
std::string isystem;
while (pos < command.size() && command[pos] != ' ') {
if (command[pos] != '\\')
isystem += command[pos];
pos++;
}
fs.systemIncludePaths.push_back(isystem);
}
}
std::map<std::string, std::string, cppcheck::stricmp> variables;
fs.setIncludePaths(directory, fs.includePaths, variables);
fs.setDefines(fs.defines);
fileSettings.push_back(fs);
}
values.clear();
} }
fs.parseCommand(command); // read settings; -D, -I, -U, -std
std::map<std::string, std::string, cppcheck::stricmp> variables;
fs.setIncludePaths(directory, fs.includePaths, variables);
fileSettings.push_back(fs);
} }
} }
void ImportProject::importSln(std::istream &istr, const std::string &path) void ImportProject::importSln(std::istream &istr, const std::string &path)
{ {
std::map<std::string,std::string,cppcheck::stricmp> variables; std::map<std::string,std::string,cppcheck::stricmp> variables;
variables["SolutionDir"] = path; variables["SolutionDir"] = path;
std::string line; std::string line;
while (std::getline(istr,line)) { while (std::getline(istr,line)) {
skipping to change at line 836 skipping to change at line 840
// //
// We can also force C++ compilation for all files using the -P command line switch. // We can also force C++ compilation for all files using the -P command line switch.
const bool cppMode = forceCppMode || Path::getFilenameExtensionInLowerCa se(c) == ".cpp"; const bool cppMode = forceCppMode || Path::getFilenameExtensionInLowerCa se(c) == ".cpp";
FileSettings fs; FileSettings fs;
fs.setIncludePaths(projectDir, toStringList(includePath), variables); fs.setIncludePaths(projectDir, toStringList(includePath), variables);
fs.setDefines(cppMode ? cppDefines : defines); fs.setDefines(cppMode ? cppDefines : defines);
fs.filename = Path::simplifyPath(Path::isAbsolute(c) ? c : projectDir + c); fs.filename = Path::simplifyPath(Path::isAbsolute(c) ? c : projectDir + c);
fileSettings.push_back(fs); fileSettings.push_back(fs);
} }
} }
static std::list<std::string> readXmlStringList(const tinyxml2::XMLElement *node
, const char name[], const char attribute[])
{
std::list<std::string> ret;
for (const tinyxml2::XMLElement *child = node->FirstChildElement(); child; c
hild = child->NextSiblingElement()) {
if (strcmp(child->Name(), name) != 0)
continue;
const char *attr = attribute ? child->Attribute(attribute) : child->GetT
ext();
if (attr)
ret.push_back(attr);
}
return ret;
}
static std::string join(const std::list<std::string> &strlist, const char *sep)
{
std::string ret;
for (const std::string &s : strlist) {
ret += (ret.empty() ? "" : sep) + s;
}
return ret;
}
// These constants are copy/pasted from gui/projectfile.cpp
static const char ProjectElementName[] = "project";
static const char ProjectVersionAttrib[] = "version";
static const char ProjectFileVersion[] = "1";
static const char BuildDirElementName[] = "builddir";
static const char ImportProjectElementName[] = "importproject";
static const char AnalyzeAllVsConfigsElementName[] = "analyze-all-vs-configs";
static const char IncludeDirElementName[] = "includedir";
static const char DirElementName[] = "dir";
static const char DirNameAttrib[] = "name";
static const char DefinesElementName[] = "defines";
static const char DefineName[] = "define";
static const char DefineNameAttrib[] = "name";
static const char UndefinesElementName[] = "undefines";
static const char UndefineName[] = "undefine";
static const char PathsElementName[] = "paths";
static const char PathName[] = "dir";
static const char PathNameAttrib[] = "name";
static const char RootPathName[] = "root";
static const char RootPathNameAttrib[] = "name";
static const char IgnoreElementName[] = "ignore";
static const char IgnorePathName[] = "path";
static const char IgnorePathNameAttrib[] = "name";
static const char ExcludeElementName[] = "exclude";
static const char ExcludePathName[] = "path";
static const char ExcludePathNameAttrib[] = "name";
static const char LibrariesElementName[] = "libraries";
static const char LibraryElementName[] = "library";
static const char PlatformElementName[] = "platform";
static const char SuppressionsElementName[] = "suppressions";
static const char SuppressionElementName[] = "suppression";
static const char AddonElementName[] = "addon";
static const char AddonsElementName[] = "addons";
static const char ToolElementName[] = "tool";
static const char ToolsElementName[] = "tools";
static const char TagsElementName[] = "tags";
static const char TagElementName[] = "tag";
static std::string istream_to_string(std::istream &istr)
{
std::istreambuf_iterator<char> eos;
return std::string(std::istreambuf_iterator<char>(istr), eos);
}
bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
ngs)
{
tinyxml2::XMLDocument doc;
const std::string xmldata = istream_to_string(istr);
if (doc.Parse(xmldata.data(), xmldata.size()) != tinyxml2::XML_SUCCESS)
return false;
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (rootnode == nullptr || strcmp(rootnode->Name(), ProjectElementName) != 0
)
return false;
(void)ProjectFileVersion;
(void)ProjectVersionAttrib;
std::list<std::string> paths;
std::list<std::string> excludePaths;
Settings temp;
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node;
node = node->NextSiblingElement()) {
if (strcmp(node->Name(), RootPathName) == 0 && node->Attribute(RootPathN
ameAttrib))
temp.basePaths.push_back(node->Attribute(RootPathNameAttrib));
else if (strcmp(node->Name(), BuildDirElementName) == 0)
temp.buildDir = node->GetText() ? node->GetText() : "";
else if (strcmp(node->Name(), IncludeDirElementName) == 0)
temp.includePaths = readXmlStringList(node, DirElementName, DirNameA
ttrib);
else if (strcmp(node->Name(), DefinesElementName) == 0)
temp.userDefines = join(readXmlStringList(node, DefineName, DefineNa
meAttrib), ";");
else if (strcmp(node->Name(), UndefinesElementName) == 0) {
for (const std::string &u : readXmlStringList(node, UndefineName, nu
llptr))
temp.userUndefs.insert(u);
} else if (strcmp(node->Name(), ImportProjectElementName) == 0)
guiProject.projectFile = node->GetText() ? node->GetText() : "";
else if (strcmp(node->Name(), PathsElementName) == 0)
paths = readXmlStringList(node, PathName, PathNameAttrib);
else if (strcmp(node->Name(), ExcludeElementName) == 0)
excludePaths = readXmlStringList(node, ExcludePathName, ExcludePathN
ameAttrib);
else if (strcmp(node->Name(), IgnoreElementName) == 0)
excludePaths = readXmlStringList(node, IgnorePathName, IgnorePathNam
eAttrib);
else if (strcmp(node->Name(), LibrariesElementName) == 0)
guiProject.libraries = readXmlStringList(node, LibraryElementName, n
ullptr);
else if (strcmp(node->Name(), SuppressionsElementName) == 0) {
for (const std::string &s : readXmlStringList(node, SuppressionEleme
ntName, nullptr)) {
temp.nomsg.addSuppressionLine(s);
}
} else if (strcmp(node->Name(), PlatformElementName) == 0)
guiProject.platform = node->GetText();
else if (strcmp(node->Name(), AnalyzeAllVsConfigsElementName) == 0)
; // FIXME: Write some warning
else if (strcmp(node->Name(), AddonsElementName) == 0)
node->Attribute(AddonElementName); // FIXME: Handle addons
else if (strcmp(node->Name(), TagsElementName) == 0)
node->Attribute(TagElementName); // FIXME: Write some warning
else if (strcmp(node->Name(), ToolsElementName) == 0)
node->Attribute(ToolElementName); // FIXME: Write some warning
else
return false;
}
settings->basePaths = temp.basePaths;
settings->buildDir = temp.buildDir;
settings->includePaths = temp.includePaths;
settings->userDefines = temp.userDefines;
settings->userUndefs = temp.userUndefs;
for (const std::string &path : paths)
guiProject.pathNames.push_back(path);
settings->project.ignorePaths(std::vector<std::string>(excludePaths.begin(),
excludePaths.end()));
return true;
}
 End of changes. 14 change blocks. 
103 lines changed or deleted 108 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)