Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 53 additions & 16 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,12 +617,13 @@ namespace {
std::string platformStr;
};

struct ConditionalGroup {
explicit ConditionalGroup(const tinyxml2::XMLElement *idg){
struct Conditional {
explicit Conditional(const tinyxml2::XMLElement *idg){
const char *condAttr = idg->Attribute("Condition");
if (condAttr)
mCondition = condAttr;
}
explicit Conditional(const std::string &condition) : mCondition(condition) {}

static void replaceAll(std::string &c, const std::string &from, const std::string &to) {
std::string::size_type pos;
Expand Down Expand Up @@ -751,8 +752,8 @@ namespace {
std::string mCondition;
};

struct ItemDefinitionGroup : ConditionalGroup {
explicit ItemDefinitionGroup(const tinyxml2::XMLElement *idg, std::string includePaths) : ConditionalGroup(idg), additionalIncludePaths(std::move(includePaths)) {
struct ItemDefinitionGroup : Conditional {
explicit ItemDefinitionGroup(const tinyxml2::XMLElement *idg, std::string includePaths) : Conditional(idg), additionalIncludePaths(std::move(includePaths)) {
for (const tinyxml2::XMLElement *e1 = idg->FirstChildElement(); e1; e1 = e1->NextSiblingElement()) {
const char* name = e1->Name();
if (std::strcmp(name, "ClCompile") == 0) {
Expand Down Expand Up @@ -802,8 +803,8 @@ namespace {
Standards::cppstd_t cppstd = Standards::CPPLatest;
};

struct ConfigurationPropertyGroup : ConditionalGroup {
explicit ConfigurationPropertyGroup(const tinyxml2::XMLElement *idg) : ConditionalGroup(idg) {
struct ConfigurationPropertyGroup : Conditional {
explicit ConfigurationPropertyGroup(const tinyxml2::XMLElement *idg) : Conditional(idg) {
for (const tinyxml2::XMLElement *e = idg->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "UseOfMfc") == 0) {
useOfMfc = true;
Expand All @@ -816,6 +817,37 @@ namespace {
bool useOfMfc = false;
bool useUnicode = false;
};

struct ItemGroupClCompile {
explicit ItemGroupClCompile(std::string filename) : mFilename(std::move(filename)) {}
ItemGroupClCompile(const tinyxml2::XMLElement *element, std::string file) : mFilename(std::move(file)) {
for (const tinyxml2::XMLElement* childElement = element->FirstChildElement(); childElement; childElement = childElement->NextSiblingElement()) {
const char *name = childElement->Name();
if (!name)
continue;
if (std::strcmp(name, "ExcludedFromBuild") == 0) {
const char *condition = childElement->Attribute("Condition");
const char *text = childElement->GetText();
if (!condition || !text || std::strcmp(text, "true") != 0)
continue;
mConditions.emplace_back(condition);
}
// TODO: ForcedIncludeFiles and PrecompiledHeaderFile
}
}
bool exclude(const ProjectConfiguration& p, std::vector<std::string>& errors) const {
if (mConditions.empty())
return false;
for (const std::string& condition : mConditions) {
Conditional conditional(condition);
if (conditional.conditionIsTrue(p, mFilename, errors))
return true;
}
return false;
}
std::string mFilename;
std::list<std::string> mConditions;
};
}

static std::list<std::string> toStringList(const std::string &s)
Expand Down Expand Up @@ -923,7 +955,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));

std::list<ProjectConfiguration> projectConfigurationList;
std::list<std::string> compileList;
std::list<ItemGroupClCompile> compileList;
std::list<ItemDefinitionGroup> itemDefinitionGroupList;
std::vector<ConfigurationPropertyGroup> configurationPropertyGroups;
std::string includePath;
Expand Down Expand Up @@ -954,7 +986,8 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
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);
findAndReplace(toInclude, "$(MSBuildThisFileDirectory)", "./");
compileList.emplace_back(e, toInclude);
}
}
}
Expand Down Expand Up @@ -1016,7 +1049,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
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));
compileList.emplace_back(pathToFile);
}
for (const auto &p : sharedProject.includePaths) {
std::string path = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + p);
Expand All @@ -1026,8 +1059,8 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X

// Project files
PathMatch filtermatcher(fileFilters, Path::getCurrentPath());
for (const std::string &cfilename : compileList) {
if (!fileFilters.empty() && !filtermatcher.match(cfilename))
for (const ItemGroupClCompile& compile : compileList) {
if (!fileFilters.empty() && !filtermatcher.match(compile.mFilename))
continue;

for (const ProjectConfiguration &p : projectConfigurationList) {
Expand All @@ -1040,7 +1073,11 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
continue;
}

FileSettings fs{cfilename, Standards::Language::None, 0}; // file will be identified later on
// check if the file should be excluded for this configuration
if (compile.exclude(p, errors))
continue;

FileSettings fs{ compile.mFilename, Standards::Language::None, 0}; // file will be identified later on
fs.cfg = p.name;
// TODO: detect actual MSC version
fs.msc = true;
Expand All @@ -1053,7 +1090,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
}
std::string additionalIncludePaths;
for (const ItemDefinitionGroup &i : itemDefinitionGroupList) {
if (!i.conditionIsTrue(p, cfilename, errors))
if (!i.conditionIsTrue(p, compile.mFilename, errors))
continue;
fs.standard = Standards::getCPP(i.cppstd);
fs.defines += ';' + i.preprocessorDefinitions;
Expand All @@ -1071,7 +1108,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
}
bool useUnicode = false;
for (const ConfigurationPropertyGroup &c : configurationPropertyGroups) {
if (!c.conditionIsTrue(p, cfilename, errors))
if (!c.conditionIsTrue(p, compile.mFilename, errors))
continue;
// in msbuild the last definition wins
useUnicode = c.useUnicode;
Expand All @@ -1081,7 +1118,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
fs.defines += ";UNICODE=1;_UNICODE=1";
}
fsSetDefines(fs, fs.defines);
fsSetIncludePaths(fs, Path::getPathFromFilename(filename), toStringList(includePath + ';' + additionalIncludePaths), variables);
fsSetIncludePaths(fs, Path::getPathFromFilename(compile.mFilename), toStringList(includePath + ';' + additionalIncludePaths), variables);
for (const auto &path : sharedItemsIncludePaths) {
fs.includePaths.emplace_back(path);
}
Expand Down Expand Up @@ -1754,5 +1791,5 @@ bool cppcheck::testing::evaluateVcxprojCondition(const std::string& condition, c
ProjectConfiguration p;
p.configuration = configuration;
p.platformStr = platform;
return ConditionalGroup::evalCondition(condition, p);
return Conditional::evalCondition(condition, p);
}
8 changes: 8 additions & 0 deletions test/cli/exclude/DebugX64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <iostream>

int foo()
{
std::cout << "DebugX64\n";
int x = 3 / 0; (void)x; // ERROR
return 0;
}
8 changes: 8 additions & 0 deletions test/cli/exclude/ReleaseX64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <iostream>

int foo()
{
std::cout << "ReleaseX64\n";
int x = 3 / 0; (void)x; // ERROR
return 0;
}
16 changes: 16 additions & 0 deletions test/cli/exclude/exclude.cppcheck
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="1">
<builddir>exclude-cppcheck-build-dir</builddir>
<importproject>exclude.slnx</importproject>
<analyze-all-vs-configs>false</analyze-all-vs-configs>
<check-headers>true</check-headers>
<check-unused-templates>true</check-unused-templates>
<inline-suppression>true</inline-suppression>
<max-ctu-depth>2</max-ctu-depth>
<max-template-recursion>100</max-template-recursion>
<vs-configurations>
<config>Debug</config>
</vs-configurations>
<check-level-normal/>
<project-name>exclude</project-name>
</project>
6 changes: 6 additions & 0 deletions test/cli/exclude/exclude.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Solution>
<Configurations>
<Platform Name="x64" />
</Configurations>
<Project Path="exclude.vcxproj" Id="c9d1dca1-d8ff-4c05-9159-f00816645319" />
</Solution>
94 changes: 94 additions & 0 deletions test/cli/exclude/exclude.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>18.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{c9d1dca1-d8ff-4c05-9159-f00816645319}</ProjectGuid>
<RootNamespace>exclude</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableSegmentHeap>true</EnableSegmentHeap>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableSegmentHeap>true</EnableSegmentHeap>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="DebugX64.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="ReleaseX64.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="foo.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
1 change: 1 addition & 0 deletions test/cli/exclude/foo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int foo();
20 changes: 20 additions & 0 deletions test/cli/exclude_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

# python -m pytest exclude_test.py

import os

from testutils import cppcheck

__script_dir = os.path.dirname(os.path.abspath(__file__))
__proj_dir = os.path.join(__script_dir, 'exclude')

def test_exclude():
args = [
'--template=cppcheck1',
'--project=exclude/exclude.cppcheck',
'--no-cppcheck-build-dir'
]
ret, stdout, stderr = cppcheck(args, cwd=__script_dir)
filename = os.path.join('exclude', 'DebugX64.cpp')
assert ret == 0, stdout
assert stderr == '[%s:6]: (error) Division by zero.\n' % filename
Loading