Skip to content

Commit

Permalink
Merge branch 'ff/sharedItemsProject' into ff/pullRequest
Browse files Browse the repository at this point in the history
# Conflicts:
#	Makefile
#	cli/main.cpp
#	cmake/versions.cmake
#	lib/cppcheck.vcxproj.filters
#	lib/importproject.cpp
#	lib/version.h
#	win_installer/productInfo.wxi
  • Loading branch information
Felix Faber committed Apr 12, 2024
2 parents 686e28d + 6b58ca9 commit 49ed63c
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 18 deletions.
160 changes: 143 additions & 17 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,12 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
mPath = Path::getPathFromFilename(Path::fromNativeSeparators(filename));
if (!mPath.empty() && !endsWith(mPath,'/'))
mPath += '/';
if (mPath.empty())
mPath = std::string("./");

const std::vector<std::string> fileFilters =
settings ? settings->fileFilters : std::vector<std::string>();
std::vector<SharedItemsProject> sharedItemsProjects{};

if (endsWith(filename, ".json")) {
if (importCompileCommands(fin)) {
Expand All @@ -202,7 +205,7 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
}
} else if (endsWith(filename, ".vcxproj")) {
std::map<std::string, std::string, cppcheck::stricmp> variables;
if (importVcxproj(filename, variables, emptyString, fileFilters)) {
if (importVcxproj(filename, variables, emptyString, fileFilters, sharedItemsProjects)) {
setRelativePaths(filename);
return ImportProject::Type::VS_VCXPROJ;
}
Expand Down Expand Up @@ -444,7 +447,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
variables["SolutionDir"] = path;

bool found = false;

std::vector<SharedItemsProject> sharedItemsProjects{};
while (std::getline(istr,line)) {
if (!startsWith(line,"Project("))
continue;
Expand All @@ -459,7 +462,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
if (!Path::isAbsolute(vcxproj))
vcxproj = path + vcxproj;
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
if (!importVcxproj(vcxproj, variables, emptyString, fileFilters)) {
if (!importVcxproj(vcxproj, variables, emptyString, fileFilters, sharedItemsProjects)) {
printError("failed to load '" + vcxproj + "' from Visual Studio solution");
return false;
}
Expand Down Expand Up @@ -680,14 +683,15 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
}
}

bool ImportProject::importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters)
bool ImportProject::importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache)
{
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));

std::list<ProjectConfiguration> projectConfigurationList;
std::list<std::string> compileList;
std::list<ItemDefinitionGroup> itemDefinitionGroupList;
std::string includePath;
std::vector<SharedItemsProject> sharedItemsProjects;

bool useOfMfc = false;

Expand Down Expand Up @@ -715,37 +719,85 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
}
}
}
} else {
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
}
else {
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "ClCompile") == 0) {
const char *include = e->Attribute("Include");
if (include && Path::acceptFile(include))
compileList.emplace_back(include);
const char* include = e->Attribute("Include");
if (include && Path::acceptFile(include)) {
std::string toInclude = Path::simplifyPath(Path::isAbsolute(include) ? include : Path::getPathFromFilename(filename) + include);
compileList.emplace_back(toInclude);
}
}
}
}
} else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
}
else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
itemDefinitionGroupList.emplace_back(node, additionalIncludeDirectories);
} else if (std::strcmp(node->Name(), "PropertyGroup") == 0) {
}
else if (std::strcmp(node->Name(), "PropertyGroup") == 0) {
importPropertyGroup(node, variables, includePath, &useOfMfc);
} else if (std::strcmp(node->Name(), "ImportGroup") == 0) {
const char *labelAttribute = node->Attribute("Label");
}
else if (std::strcmp(node->Name(), "ImportGroup") == 0) {
const char* labelAttribute = node->Attribute("Label");
if (labelAttribute && std::strcmp(labelAttribute, "PropertySheets") == 0) {
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "Import") == 0) {
const char *projectAttribute = e->Attribute("Project");
const char* projectAttribute = e->Attribute("Project");
if (projectAttribute)
loadVisualStudioProperties(projectAttribute, variables, includePath, additionalIncludeDirectories, itemDefinitionGroupList);
}
}
}
else if (labelAttribute && std::strcmp(labelAttribute, "Shared") == 0) {
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "Import") == 0) {
const char* projectAttribute = e->Attribute("Project");
if (projectAttribute)
{
// Path to shared items project is relative to current project directory,
// unless the string starts with $(SolutionDir)
std::string pathToSharedItemsFile;
if (std::string(projectAttribute).rfind("$(SolutionDir)", 0) == 0) {
pathToSharedItemsFile = std::string(projectAttribute);
} else {
pathToSharedItemsFile = variables["ProjectDir"] + std::string(projectAttribute);
}
if (!simplifyPathWithVariables(pathToSharedItemsFile, variables)) {
printError("Could not simplify path to referenced shared items project");
exit(-1);
}
SharedItemsProject toAdd = importVcxitems(pathToSharedItemsFile, fileFilters, cache);
if (!toAdd.successFull)
{
printError("Could not load shared items project \"" + pathToSharedItemsFile + "\" from original path \"" + std::string(projectAttribute) + "\".");
return false;
}
sharedItemsProjects.emplace_back(toAdd);
}
}
}
}
}
}
// # TODO: support signedness of char via /J (and potential XML option for it)?
// we can only set it globally but in this context it needs to be treated per file

for (const std::string &c : compileList) {
const std::string cfilename = Path::simplifyPath(Path::isAbsolute(c) ? c : Path::getPathFromFilename(filename) + c);
// Include shared items project files
std::vector<std::string> sharedItemsIncludePaths{};
for (const auto& sharedProject : sharedItemsProjects) {
for (const auto& file : sharedProject.sourceFiles) {
std::string pathToFile = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + file);
compileList.emplace_back(std::move(pathToFile));
}
for (const auto& p : sharedProject.includePaths) {
std::string path = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + p);
sharedItemsIncludePaths.emplace_back(std::move(path));
}
}

// Project files
for (const std::string& cfilename : compileList) {
if (!fileFilters.empty() && !matchglobs(fileFilters, cfilename))
continue;

Expand Down Expand Up @@ -792,13 +844,87 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
}
fsSetDefines(fs, fs.defines);
fsSetIncludePaths(fs, Path::getPathFromFilename(filename), toStringList(includePath + ';' + additionalIncludePaths), variables);
for (const auto& path : sharedItemsIncludePaths) {
fs.includePaths.emplace_back(path);
}
fileSettings.push_back(std::move(fs));
}
}

return true;
}

static std::string stringReplace(const std::string& original, const std::string& toReplace, const std::string& replaceWith)
{
std::string result(original);
size_t pos = result.find(toReplace);
while (pos != std::string::npos) {
result.replace(pos, toReplace.length(), replaceWith);
pos = result.find(toReplace);
}
return result;
}

ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache)
{
for (const auto& entry : cache)
{
if (filename == entry.pathToProjectFile)
{
return entry;
}
}

SharedItemsProject result{};
result.pathToProjectFile = filename;

tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
printError(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return result;
}
const tinyxml2::XMLElement* const rootnode = doc.FirstChildElement();
if (rootnode == nullptr) {
printError("Visual Studio project file has no XML root node");
return result;
}
for (const tinyxml2::XMLElement* node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
if (std::strcmp(node->Name(), "ItemGroup") == 0) {
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "ClCompile") == 0) {
const char* include = e->Attribute("Include");
if (include && Path::acceptFile(include)) {
std::string file = stringReplace(include, "$(MSBuildThisFileDirectory)", "./");

// Don't include file if it matches the filter
if (!fileFilters.empty() && !matchglobs(fileFilters, file))
continue;

result.sourceFiles.emplace_back(file);
} else {
printError("Could not find shared items source file");
return result;
}
}
}
}
else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
ItemDefinitionGroup temp(node, "");
for (const auto& includePath : toStringList(temp.additionalIncludePaths)) {
if (includePath == std::string("%(AdditionalIncludeDirectories)"))
continue;

result.includePaths.emplace_back(stringReplace(includePath, "$(MSBuildThisFileDirectory)", "./"));
}
}
}

result.successFull = true;
cache.emplace_back(result);
return result;
}

bool ImportProject::importBcb6Prj(const std::string &projectFilename)
{
tinyxml2::XMLDocument doc;
Expand Down
11 changes: 10 additions & 1 deletion lib/importproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,18 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
bool importCompileCommands(std::istream &istr);
bool importCppcheckGuiProject(std::istream &istr, Settings *settings);
virtual bool sourceFileExists(const std::string &file);

private:
struct SharedItemsProject {
bool successFull;
std::string pathToProjectFile;
std::vector<std::string> includePaths;
std::vector<std::string> sourceFiles;
};

bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters);
static SharedItemsProject importVcxitems(const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache);
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importBcb6Prj(const std::string &projectFilename);

static void printError(const std::string &message);
Expand Down

0 comments on commit 49ed63c

Please sign in to comment.