@@ -191,6 +191,7 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
191191
192192 const std::vector<std::string> fileFilters =
193193 settings ? settings->fileFilters : std::vector<std::string>();
194+ std::vector<SharedItemsProject> sharedItemsProjects{};
194195
195196 if (endsWith (filename, " .json" )) {
196197 if (importCompileCommands (fin)) {
@@ -204,7 +205,7 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
204205 }
205206 } else if (endsWith (filename, " .vcxproj" )) {
206207 std::map<std::string, std::string, cppcheck::stricmp> variables;
207- if (importVcxproj (filename, variables, emptyString, fileFilters)) {
208+ if (importVcxproj (filename, variables, emptyString, fileFilters, sharedItemsProjects )) {
208209 setRelativePaths (filename);
209210 return ImportProject::Type::VS_VCXPROJ;
210211 }
@@ -446,7 +447,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
446447 variables[" SolutionDir" ] = path;
447448
448449 bool found = false ;
449-
450+ std::vector<SharedItemsProject> sharedItemsProjects{};
450451 while (std::getline (istr,line)) {
451452 if (!startsWith (line," Project(" ))
452453 continue ;
@@ -824,15 +825,15 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
824825 return true ;
825826}
826827
827-
828- bool ImportProject::importVcxitems (const std::string& filename, std::map<std::string, std::string, cppcheck::stricmp>& variables, const std::string& additionalIncludeDirectories, const std::vector<std::string>& fileFilters)
828+ 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)
829829{
830830 variables[" ProjectDir" ] = Path::simplifyPath (Path::getPathFromFilename (filename));
831831
832832 std::list<ProjectConfiguration> projectConfigurationList;
833833 std::list<std::string> compileList;
834834 std::list<ItemDefinitionGroup> itemDefinitionGroupList;
835835 std::string includePath;
836+ std::vector<SharedItemsProject> sharedItemsProjects;
836837
837838 bool useOfMfc = false ;
838839
@@ -888,45 +889,57 @@ bool ImportProject::importVcxitems(const std::string& filename, std::map<std::st
888889 }
889890 }
890891 }
891- }
892- }
893- // # TODO: support signedness of char via /J (and potential XML option for it)?
894- // we can only set it globally but in this context it needs to be treated per file
895- for ( const std::string& c : compileList) {
896- std::string cfilename = Path::simplifyPath ( Path::isAbsolute (c) ? c : Path::getPathFromFilename (filename) + c);
897-
898- // Remove "msbuild this file directory"
899- {
900- std::string toRemove ( " $(MSBuildThisFileDirectory) " );
901- size_t pos = cfilename. find (toRemove);
902- while (pos != std::string::npos)
903- {
904- auto test = cfilename. erase (pos, toRemove. length ());
905- pos = cfilename. find (toRemove);
892+ else if (labelAttribute && std::strcmp (labelAttribute, " Shared " ) == 0 ) {
893+ for ( const tinyxml2::XMLElement* e = node-> FirstChildElement (); e; e = e-> NextSiblingElement ()) {
894+ if ( std::strcmp (e-> Name (), " Import " ) == 0 ) {
895+ const char * projectAttribute = e-> Attribute ( " Project " );
896+ if (projectAttribute)
897+ {
898+ std::string pathToSharedItemsFile (projectAttribute);
899+ if (! simplifyPathWithVariables (pathToSharedItemsFile, variables)) {
900+ printError ( " Could not simplify path to referenced shared items project " );
901+ exit (- 1 );
902+ }
903+ sharedItemsProjects. emplace_back ( importVcxitems (pathToSharedItemsFile, fileFilters, cache));
904+ }
905+ }
906+ }
906907 }
907908 }
909+ }
908910
911+ // Project files
912+ for (const std::string& c : compileList) {
913+ const std::string cfilename = Path::simplifyPath (Path::isAbsolute (c) ? c : Path::getPathFromFilename (filename) + c);
909914 if (!fileFilters.empty () && !matchglobs (fileFilters, cfilename))
910915 continue ;
911916
912- // TODO(Felix): make this robust by iterating over the projects,
913- // checking retrieving their configurations and add them
914- // if this the shared item project is referenced
915-
916- // Assuming x64 configuration
917- std::string configs[] = { " Debug|x64" , " Release|x64" , };
918- for (auto & c : configs)
919- {
917+ for (const ProjectConfiguration& p : projectConfigurationList) {
918+
919+ if (!guiProject.checkVsConfigs .empty ()) {
920+ const bool doChecking = std::any_of (guiProject.checkVsConfigs .cbegin (), guiProject.checkVsConfigs .cend (), [&](const std::string& c) {
921+ return c == p.configuration ;
922+ });
923+ if (!doChecking)
924+ continue ;
925+ }
926+
920927 FileSettings fs;
921928 fs.filename = cfilename;
922- fs.cfg = c;
923- // TODO: detect actual MSC version
929+ fs.cfg = p.name ;
924930 fs.msc = true ;
925931 fs.useMfc = useOfMfc;
926- fs.defines = " _WIN32=1;_WIN64=1" ;
927- fs.platformType = cppcheck::Platform::Type::Win64;
932+ fs.defines = " _WIN32=1" ;
933+ if (p.platform == ProjectConfiguration::Win32)
934+ fs.platformType = cppcheck::Platform::Type::Win32W;
935+ else if (p.platform == ProjectConfiguration::x64) {
936+ fs.platformType = cppcheck::Platform::Type::Win64;
937+ fs.defines += " ;_WIN64=1" ;
938+ }
928939 std::string additionalIncludePaths;
929940 for (const ItemDefinitionGroup& i : itemDefinitionGroupList) {
941+ if (!i.conditionIsTrue (p))
942+ continue ;
930943 fs.standard = Standards::getCPP (i.cppstd );
931944 fs.defines += ' ;' + i.preprocessorDefinitions ;
932945 if (i.enhancedInstructionSet == " StreamingSIMDExtensions" )
@@ -947,9 +960,142 @@ bool ImportProject::importVcxitems(const std::string& filename, std::map<std::st
947960 }
948961 }
949962
963+ // Shared items files
964+ for (const auto & sharedProject : sharedItemsProjects) {
965+ for (const auto & c : sharedProject.sourceFiles ) {
966+ const std::string cfilename = Path::simplifyPath (c);
967+ if (!fileFilters.empty () && !matchglobs (fileFilters, cfilename))
968+ continue ;
969+
970+ for (const ProjectConfiguration& p : projectConfigurationList) {
971+ if (!guiProject.checkVsConfigs .empty ()) {
972+ const bool doChecking = std::any_of (guiProject.checkVsConfigs .cbegin (), guiProject.checkVsConfigs .cend (), [&](const std::string& c) {
973+ return c == p.configuration ;
974+ });
975+ if (!doChecking)
976+ continue ;
977+ }
978+
979+ FileSettings fs;
980+ fs.filename = cfilename;
981+ fs.cfg = p.name ;
982+ fs.msc = true ;
983+ fs.useMfc = useOfMfc;
984+ fs.defines = " _WIN32=1" ;
985+ if (p.platform == ProjectConfiguration::Win32)
986+ fs.platformType = cppcheck::Platform::Type::Win32W;
987+ else if (p.platform == ProjectConfiguration::x64) {
988+ fs.platformType = cppcheck::Platform::Type::Win64;
989+ fs.defines += " ;_WIN64=1" ;
990+ }
991+ std::string additionalIncludePaths;
992+ for (const ItemDefinitionGroup& i : itemDefinitionGroupList) {
993+ if (!i.conditionIsTrue (p))
994+ continue ;
995+ fs.standard = Standards::getCPP (i.cppstd );
996+ fs.defines += ' ;' + i.preprocessorDefinitions ;
997+ if (i.enhancedInstructionSet == " StreamingSIMDExtensions" )
998+ fs.defines += " ;__SSE__" ;
999+ else if (i.enhancedInstructionSet == " StreamingSIMDExtensions2" )
1000+ fs.defines += " ;__SSE2__" ;
1001+ else if (i.enhancedInstructionSet == " AdvancedVectorExtensions" )
1002+ fs.defines += " ;__AVX__" ;
1003+ else if (i.enhancedInstructionSet == " AdvancedVectorExtensions2" )
1004+ fs.defines += " ;__AVX2__" ;
1005+ else if (i.enhancedInstructionSet == " AdvancedVectorExtensions512" )
1006+ fs.defines += " ;__AVX512__" ;
1007+ additionalIncludePaths += ' ;' + i.additionalIncludePaths ;
1008+ }
1009+ fs.setDefines (fs.defines );
1010+ fs.setIncludePaths (Path::getPathFromFilename (filename), toStringList (includePath + ' ;' + additionalIncludePaths), variables);
1011+ for (const auto & toAddIncludePath : sharedProject.includePaths ) {
1012+ fs.includePaths .emplace_back (Path::simplifyPath (toAddIncludePath));
1013+ }
1014+ fileSettings.push_back (std::move (fs));
1015+ }
1016+ }
1017+ }
1018+
9501019 return true ;
9511020}
9521021
1022+ static std::string stringReplace (const std::string& original, const std::string& toReplace, const std::string& replaceWith)
1023+ {
1024+ std::string result (original);
1025+ size_t pos = result.find (toReplace);
1026+ while (pos != std::string::npos) {
1027+ result.replace (pos, toReplace.length (), replaceWith);
1028+ pos = result.find (toReplace);
1029+ }
1030+ return result;
1031+ }
1032+
1033+ ImportProject::SharedItemsProject ImportProject::importVcxitems (const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache)
1034+ {
1035+ for (const auto & entry : cache)
1036+ {
1037+ if (filename == entry.pathToProjectFile )
1038+ {
1039+ return entry;
1040+ }
1041+ }
1042+
1043+ std::string projectDir = Path::simplifyPath (Path::getPathFromFilename (filename));
1044+ if (projectDir.empty ())
1045+ {
1046+ projectDir = std::string (" ./" );
1047+ }
1048+
1049+ SharedItemsProject result{};
1050+ result.pathToProjectFile = filename;
1051+
1052+ tinyxml2::XMLDocument doc;
1053+ const tinyxml2::XMLError error = doc.LoadFile (filename.c_str ());
1054+ if (error != tinyxml2::XML_SUCCESS) {
1055+ printError (std::string (" Visual Studio project file is not a valid XML - " ) + tinyxml2::XMLDocument::ErrorIDToName (error));
1056+ exit (-1 );
1057+ }
1058+ const tinyxml2::XMLElement* const rootnode = doc.FirstChildElement ();
1059+ if (rootnode == nullptr ) {
1060+ printError (" Visual Studio project file has no XML root node" );
1061+ exit (-1 );
1062+ }
1063+ for (const tinyxml2::XMLElement* node = rootnode->FirstChildElement (); node; node = node->NextSiblingElement ()) {
1064+ if (std::strcmp (node->Name (), " ItemGroup" ) == 0 ) {
1065+ const char * labelAttribute = node->Attribute (" Label" );
1066+ for (const tinyxml2::XMLElement* e = node->FirstChildElement (); e; e = e->NextSiblingElement ()) {
1067+ if (std::strcmp (e->Name (), " ClCompile" ) == 0 ) {
1068+ const char * include = e->Attribute (" Include" );
1069+ if (include && Path::acceptFile (include)) {
1070+ std::string filename = stringReplace (include, " $(MSBuildThisFileDirectory)" , projectDir);
1071+
1072+ // Don't include file if it matches the filter
1073+ if (!fileFilters.empty () && !matchglobs (fileFilters, filename))
1074+ continue ;
1075+
1076+ result.sourceFiles .emplace_back (filename);
1077+ } else {
1078+ printError (" Could not find shared items source file" );
1079+ exit (-1 );
1080+ }
1081+ }
1082+ }
1083+ }
1084+ else if (std::strcmp (node->Name (), " ItemDefinitionGroup" ) == 0 ) {
1085+ ItemDefinitionGroup temp (node, " " );
1086+ for (const auto & includePath : toStringList (temp.additionalIncludePaths )) {
1087+ if (includePath == std::string (" %(AdditionalIncludeDirectories)" ))
1088+ continue ;
1089+
1090+ result.includePaths .emplace_back (stringReplace (includePath, " $(MSBuildThisFileDirectory)" , projectDir));
1091+ }
1092+ }
1093+ }
1094+
1095+ cache.emplace_back (result);
1096+ return result;
1097+ }
1098+
9531099bool ImportProject::importBcb6Prj (const std::string &projectFilename)
9541100{
9551101 tinyxml2::XMLDocument doc;
0 commit comments