Skip to content

Commit 49ed63c

Browse files
author
Felix Faber
committed
Merge branch 'ff/sharedItemsProject' into ff/pullRequest
# Conflicts: # Makefile # cli/main.cpp # cmake/versions.cmake # lib/cppcheck.vcxproj.filters # lib/importproject.cpp # lib/version.h # win_installer/productInfo.wxi
2 parents 686e28d + 6b58ca9 commit 49ed63c

2 files changed

Lines changed: 153 additions & 18 deletions

File tree

lib/importproject.cpp

Lines changed: 143 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,12 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
186186
mPath = Path::getPathFromFilename(Path::fromNativeSeparators(filename));
187187
if (!mPath.empty() && !endsWith(mPath,'/'))
188188
mPath += '/';
189+
if (mPath.empty())
190+
mPath = std::string("./");
189191

190192
const std::vector<std::string> fileFilters =
191193
settings ? settings->fileFilters : std::vector<std::string>();
194+
std::vector<SharedItemsProject> sharedItemsProjects{};
192195

193196
if (endsWith(filename, ".json")) {
194197
if (importCompileCommands(fin)) {
@@ -202,7 +205,7 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
202205
}
203206
} else if (endsWith(filename, ".vcxproj")) {
204207
std::map<std::string, std::string, cppcheck::stricmp> variables;
205-
if (importVcxproj(filename, variables, emptyString, fileFilters)) {
208+
if (importVcxproj(filename, variables, emptyString, fileFilters, sharedItemsProjects)) {
206209
setRelativePaths(filename);
207210
return ImportProject::Type::VS_VCXPROJ;
208211
}
@@ -444,7 +447,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
444447
variables["SolutionDir"] = path;
445448

446449
bool found = false;
447-
450+
std::vector<SharedItemsProject> sharedItemsProjects{};
448451
while (std::getline(istr,line)) {
449452
if (!startsWith(line,"Project("))
450453
continue;
@@ -459,7 +462,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
459462
if (!Path::isAbsolute(vcxproj))
460463
vcxproj = path + vcxproj;
461464
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
462-
if (!importVcxproj(vcxproj, variables, emptyString, fileFilters)) {
465+
if (!importVcxproj(vcxproj, variables, emptyString, fileFilters, sharedItemsProjects)) {
463466
printError("failed to load '" + vcxproj + "' from Visual Studio solution");
464467
return false;
465468
}
@@ -680,14 +683,15 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
680683
}
681684
}
682685

683-
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)
686+
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)
684687
{
685688
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));
686689

687690
std::list<ProjectConfiguration> projectConfigurationList;
688691
std::list<std::string> compileList;
689692
std::list<ItemDefinitionGroup> itemDefinitionGroupList;
690693
std::string includePath;
694+
std::vector<SharedItemsProject> sharedItemsProjects;
691695

692696
bool useOfMfc = false;
693697

@@ -715,37 +719,85 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
715719
}
716720
}
717721
}
718-
} else {
719-
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
722+
}
723+
else {
724+
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
720725
if (std::strcmp(e->Name(), "ClCompile") == 0) {
721-
const char *include = e->Attribute("Include");
722-
if (include && Path::acceptFile(include))
723-
compileList.emplace_back(include);
726+
const char* include = e->Attribute("Include");
727+
if (include && Path::acceptFile(include)) {
728+
std::string toInclude = Path::simplifyPath(Path::isAbsolute(include) ? include : Path::getPathFromFilename(filename) + include);
729+
compileList.emplace_back(toInclude);
730+
}
724731
}
725732
}
726733
}
727-
} else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
734+
}
735+
else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
728736
itemDefinitionGroupList.emplace_back(node, additionalIncludeDirectories);
729-
} else if (std::strcmp(node->Name(), "PropertyGroup") == 0) {
737+
}
738+
else if (std::strcmp(node->Name(), "PropertyGroup") == 0) {
730739
importPropertyGroup(node, variables, includePath, &useOfMfc);
731-
} else if (std::strcmp(node->Name(), "ImportGroup") == 0) {
732-
const char *labelAttribute = node->Attribute("Label");
740+
}
741+
else if (std::strcmp(node->Name(), "ImportGroup") == 0) {
742+
const char* labelAttribute = node->Attribute("Label");
733743
if (labelAttribute && std::strcmp(labelAttribute, "PropertySheets") == 0) {
734-
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
744+
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
735745
if (std::strcmp(e->Name(), "Import") == 0) {
736-
const char *projectAttribute = e->Attribute("Project");
746+
const char* projectAttribute = e->Attribute("Project");
737747
if (projectAttribute)
738748
loadVisualStudioProperties(projectAttribute, variables, includePath, additionalIncludeDirectories, itemDefinitionGroupList);
739749
}
740750
}
741751
}
752+
else if (labelAttribute && std::strcmp(labelAttribute, "Shared") == 0) {
753+
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
754+
if (std::strcmp(e->Name(), "Import") == 0) {
755+
const char* projectAttribute = e->Attribute("Project");
756+
if (projectAttribute)
757+
{
758+
// Path to shared items project is relative to current project directory,
759+
// unless the string starts with $(SolutionDir)
760+
std::string pathToSharedItemsFile;
761+
if (std::string(projectAttribute).rfind("$(SolutionDir)", 0) == 0) {
762+
pathToSharedItemsFile = std::string(projectAttribute);
763+
} else {
764+
pathToSharedItemsFile = variables["ProjectDir"] + std::string(projectAttribute);
765+
}
766+
if (!simplifyPathWithVariables(pathToSharedItemsFile, variables)) {
767+
printError("Could not simplify path to referenced shared items project");
768+
exit(-1);
769+
}
770+
SharedItemsProject toAdd = importVcxitems(pathToSharedItemsFile, fileFilters, cache);
771+
if (!toAdd.successFull)
772+
{
773+
printError("Could not load shared items project \"" + pathToSharedItemsFile + "\" from original path \"" + std::string(projectAttribute) + "\".");
774+
return false;
775+
}
776+
sharedItemsProjects.emplace_back(toAdd);
777+
}
778+
}
779+
}
780+
}
742781
}
743782
}
744783
// # TODO: support signedness of char via /J (and potential XML option for it)?
745784
// we can only set it globally but in this context it needs to be treated per file
746785

747-
for (const std::string &c : compileList) {
748-
const std::string cfilename = Path::simplifyPath(Path::isAbsolute(c) ? c : Path::getPathFromFilename(filename) + c);
786+
// Include shared items project files
787+
std::vector<std::string> sharedItemsIncludePaths{};
788+
for (const auto& sharedProject : sharedItemsProjects) {
789+
for (const auto& file : sharedProject.sourceFiles) {
790+
std::string pathToFile = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + file);
791+
compileList.emplace_back(std::move(pathToFile));
792+
}
793+
for (const auto& p : sharedProject.includePaths) {
794+
std::string path = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + p);
795+
sharedItemsIncludePaths.emplace_back(std::move(path));
796+
}
797+
}
798+
799+
// Project files
800+
for (const std::string& cfilename : compileList) {
749801
if (!fileFilters.empty() && !matchglobs(fileFilters, cfilename))
750802
continue;
751803

@@ -792,13 +844,87 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
792844
}
793845
fsSetDefines(fs, fs.defines);
794846
fsSetIncludePaths(fs, Path::getPathFromFilename(filename), toStringList(includePath + ';' + additionalIncludePaths), variables);
847+
for (const auto& path : sharedItemsIncludePaths) {
848+
fs.includePaths.emplace_back(path);
849+
}
795850
fileSettings.push_back(std::move(fs));
796851
}
797852
}
798853

799854
return true;
800855
}
801856

857+
static std::string stringReplace(const std::string& original, const std::string& toReplace, const std::string& replaceWith)
858+
{
859+
std::string result(original);
860+
size_t pos = result.find(toReplace);
861+
while (pos != std::string::npos) {
862+
result.replace(pos, toReplace.length(), replaceWith);
863+
pos = result.find(toReplace);
864+
}
865+
return result;
866+
}
867+
868+
ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache)
869+
{
870+
for (const auto& entry : cache)
871+
{
872+
if (filename == entry.pathToProjectFile)
873+
{
874+
return entry;
875+
}
876+
}
877+
878+
SharedItemsProject result{};
879+
result.pathToProjectFile = filename;
880+
881+
tinyxml2::XMLDocument doc;
882+
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
883+
if (error != tinyxml2::XML_SUCCESS) {
884+
printError(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
885+
return result;
886+
}
887+
const tinyxml2::XMLElement* const rootnode = doc.FirstChildElement();
888+
if (rootnode == nullptr) {
889+
printError("Visual Studio project file has no XML root node");
890+
return result;
891+
}
892+
for (const tinyxml2::XMLElement* node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
893+
if (std::strcmp(node->Name(), "ItemGroup") == 0) {
894+
for (const tinyxml2::XMLElement* e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
895+
if (std::strcmp(e->Name(), "ClCompile") == 0) {
896+
const char* include = e->Attribute("Include");
897+
if (include && Path::acceptFile(include)) {
898+
std::string file = stringReplace(include, "$(MSBuildThisFileDirectory)", "./");
899+
900+
// Don't include file if it matches the filter
901+
if (!fileFilters.empty() && !matchglobs(fileFilters, file))
902+
continue;
903+
904+
result.sourceFiles.emplace_back(file);
905+
} else {
906+
printError("Could not find shared items source file");
907+
return result;
908+
}
909+
}
910+
}
911+
}
912+
else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
913+
ItemDefinitionGroup temp(node, "");
914+
for (const auto& includePath : toStringList(temp.additionalIncludePaths)) {
915+
if (includePath == std::string("%(AdditionalIncludeDirectories)"))
916+
continue;
917+
918+
result.includePaths.emplace_back(stringReplace(includePath, "$(MSBuildThisFileDirectory)", "./"));
919+
}
920+
}
921+
}
922+
923+
result.successFull = true;
924+
cache.emplace_back(result);
925+
return result;
926+
}
927+
802928
bool ImportProject::importBcb6Prj(const std::string &projectFilename)
803929
{
804930
tinyxml2::XMLDocument doc;

lib/importproject.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,18 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
9999
bool importCompileCommands(std::istream &istr);
100100
bool importCppcheckGuiProject(std::istream &istr, Settings *settings);
101101
virtual bool sourceFileExists(const std::string &file);
102+
102103
private:
104+
struct SharedItemsProject {
105+
bool successFull;
106+
std::string pathToProjectFile;
107+
std::vector<std::string> includePaths;
108+
std::vector<std::string> sourceFiles;
109+
};
110+
103111
bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
104-
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);
112+
static SharedItemsProject importVcxitems(const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache);
113+
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);
105114
bool importBcb6Prj(const std::string &projectFilename);
106115

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

0 commit comments

Comments
 (0)