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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ $(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/analyzer.h lib/astut
$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp

$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/checkers.h lib/config.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp

$(libcppdir)/infer.o: lib/infer.cpp lib/calculate.h lib/config.h lib/errortypes.h lib/infer.h lib/mathlib.h lib/smallvector.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h
Expand Down Expand Up @@ -819,7 +819,7 @@ test/testfunctions.o: test/testfunctions.cpp lib/check.h lib/checkers.h lib/chec
test/testgarbage.o: test/testgarbage.cpp lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testgarbage.cpp

test/testimportproject.o: test/testimportproject.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h test/fixture.h test/redirect.h
test/testimportproject.o: test/testimportproject.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h test/redirect.h
$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testimportproject.cpp

test/testincompletestatement.o: test/testincompletestatement.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
Expand Down
2,930 changes: 2,304 additions & 626 deletions lib/importproject.cpp

Large diffs are not rendered by default.

98 changes: 79 additions & 19 deletions lib/importproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@
#include <map>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>

class Settings;
struct Suppressions;

namespace tinyxml2 {
class XMLDocument;
class XMLElement;
}

/// @addtogroup Core
Expand All @@ -53,14 +55,21 @@ namespace cppcheck {
namespace testing
{
CPPCHECKLIB bool evaluateVcxprojCondition(const std::string& condition, const std::string& configuration, const std::string& platform);
/** Expand MSBuild property expressions ($(Name), $([Class]::Method(args))) in \p expr
* against an empty property map and return the result. Intended for unit tests. */
CPPCHECKLIB std::string expandMSBuildExpression(const std::string& expr);
}
}

using PropertiesMap = std::map<std::string, std::string, cppcheck::stricmp>;
using MetadataMap = std::map<std::string, std::string, cppcheck::stricmp>;

/**
* @brief Importing project settings.
*/
class CPPCHECKLIB WARN_UNUSED ImportProject {
public:

enum class Type : std::uint8_t {
NONE,
UNKNOWN,
Expand All @@ -73,14 +82,22 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
BORLAND,
CPPCHECK_GUI
};
enum class ImportResult : std::uint8_t {
Ok,
NotResolvable,
NotFound,
NotValid,
Cycle
};

protected:
static void fsSetDefines(FileSettings& fs, std::string defs);
static void fsSetIncludePaths(FileSettings& fs, const std::string &basepath, const std::list<std::string> &in, std::map<std::string, std::string, cppcheck::stricmp> &variables);
void fsSetIncludePaths(FileSettings& fs, const std::string &basepath, const std::list<std::string> &in, PropertiesMap &properties);

public:
std::list<FileSettings> fileSettings;
std::vector<std::string> errors;
std::vector<std::string> debugs;

ImportProject() = default;
virtual ~ImportProject() = default;
Expand All @@ -106,30 +123,77 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
void ignoreOtherConfigs(const std::string &cfg);

Type import(const std::string &filename, Settings *settings=nullptr, Suppressions *supprs=nullptr);

static const std::string &importResultStr(ImportResult result);

protected:
bool importCompileCommands(std::istream &istr);
bool importCppcheckGuiProject(std::istream &istr, Settings &settings, Suppressions &supprs);
static std::string collectArgs(const std::string &cmd, std::vector<std::string> &args);
void setRelativePaths(const std::string &filename);

struct SharedItemsProject {
bool successful = false;
std::string pathToProjectFile;
std::vector<std::string> includePaths;
std::vector<std::string> sourceFiles;
};

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 importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);

private:
static void parseArgs(FileSettings &fs, const std::vector<std::string> &args);

bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
bool importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters);
SharedItemsProject importVcxitems(const std::string &filename, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importBcb6Prj(const std::string &projectFilename);

struct ProjectConfiguration {
explicit ProjectConfiguration(const tinyxml2::XMLElement *cfg);

std::string name;
std::string configuration;
enum : std::uint8_t { Win32, x64, ARM64, ARM, Unknown } platform = Unknown;
std::string platformStr;
};

struct ItemGroupClCompile {
explicit ItemGroupClCompile(std::string filename) : filename(std::move(filename)) {}
std::string filename;
MetadataMap metadata;
const std::string &get(const std::string &key) const {
static const std::string empty;
const auto it = metadata.find(key);
return (it != metadata.end()) ? it->second : empty;
}
};

bool importSln(std::istream &istr, const std::string &filename, const std::vector<std::string> &fileFilters);
bool importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters);
bool importDirectorySolutionProps(PropertiesMap &properties);
bool importVcxproj(const std::string &filename, PropertiesMap &properties, const std::vector<std::string> &fileFilters);

ImportResult importPropsOrTargets(const std::string &file,
PropertiesMap &properties,
MetadataMap &metadata,
std::list<ProjectConfiguration> &projectConfigurationList,
std::unordered_set<std::string> &importStack);
ImportResult importVcxitems(const std::string &items,
PropertiesMap &properties,
MetadataMap &metadata,
std::list<ItemGroupClCompile> &compileList,
std::list<ProjectConfiguration> &projectConfigurationList,
std::unordered_set<std::string> &importStack);
ImportResult importProject(const tinyxml2::XMLElement *node,
const std::string &projectDir,
PropertiesMap &properties,
MetadataMap &metadata,
std::list<ProjectConfiguration> &projectConfigurationList,
std::unordered_set<std::string> &importStack);
ImportResult importCompile(const tinyxml2::XMLElement *node,
const std::string &projectDir,
PropertiesMap &properties,
const MetadataMap &metadata,
std::list<ItemGroupClCompile> &compileList);
void checkUnexpandedExpressions(const std::string &text, const char *context);
bool simplifyPathWithVariables(std::string &s, PropertiesMap &properties);
void addProperty(const tinyxml2::XMLElement *node, PropertiesMap &properties);
void addMetadata(const tinyxml2::XMLElement *node, PropertiesMap &properties, MetadataMap &metadata);
std::string getMetadata(const tinyxml2::XMLElement *node, PropertiesMap &properties, const MetadataMap &metadata, const std::string &original);
std::string toAbsolute(const std::string &filename, const std::string &baseDir, PropertiesMap &properties);
static std::string toAbsolute(const std::string &path);
static void setSolution(const std::string &filename, PropertiesMap &properties);


std::string mPath;
std::set<std::string> mAllVSConfigs;
};
Expand Down Expand Up @@ -201,10 +265,6 @@ namespace CppcheckXml {
static constexpr char ProjectNameElementName[] = "project-name";
}

namespace testing
{
CPPCHECKLIB bool evaluateVcxprojCondition(const std::string& condition, const std::string& configuration, const std::string& platform);
}
/// @}
//---------------------------------------------------------------------------
#endif // importprojectH
40 changes: 40 additions & 0 deletions lib/platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,42 @@ bool Platform::set(Type t)
char_bit = 8;
calculateBitMembers();
return true;
case Type::WinARM64:
type = t;
windows = true;
sizeof_bool = 1;
sizeof_short = 2;
sizeof_int = 4;
sizeof_long = 4;
sizeof_long_long = 8;
sizeof_float = 4;
sizeof_double = 8;
sizeof_long_double = 8;
sizeof_wchar_t = 2;
sizeof_size_t = 8;
sizeof_pointer = 8;
defaultSign = 's';
char_bit = 8;
calculateBitMembers();
return true;
case Type::WinARM:
type = t;
windows = true;
sizeof_bool = 1;
sizeof_short = 2;
sizeof_int = 4;
sizeof_long = 4;
sizeof_long_long = 8;
sizeof_float = 4;
sizeof_double = 8;
sizeof_long_double = 8;
sizeof_wchar_t = 2;
sizeof_size_t = 4;
sizeof_pointer = 4;
defaultSign = 's';
char_bit = 8;
calculateBitMembers();
return true;
case Type::Unix32:
type = t;
windows = false;
Expand Down Expand Up @@ -150,6 +186,10 @@ bool Platform::set(const std::string& platformstr, std::string& errstr, const st
set(Type::Win32W);
else if (platformstr == "win64")
set(Type::Win64);
else if (platformstr == "winARM64")
set(Type::WinARM64);
else if (platformstr == "winARM")
set(Type::WinARM);
else if (platformstr == "unix32")
set(Type::Unix32);
else if (platformstr == "unix64")
Expand Down
6 changes: 6 additions & 0 deletions lib/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ class CPPCHECKLIB Platform {
Win32A,
Win32W,
Win64,
WinARM64,
WinARM,
Unix32,
Unix64,
File
Expand Down Expand Up @@ -188,6 +190,10 @@ class CPPCHECKLIB Platform {
return "win32W";
case Type::Win64:
return "win64";
case Type::WinARM64:
return "winARM64";
case Type::WinARM:
return "winARM";
case Type::Unix32:
return "unix32";
case Type::Unix64:
Expand Down
2 changes: 1 addition & 1 deletion oss-fuzz/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ $(libcppdir)/forwardanalyzer.o: ../lib/forwardanalyzer.cpp ../lib/analyzer.h ../
$(libcppdir)/fwdanalysis.o: ../lib/fwdanalysis.cpp ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h
$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp

$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/filesettings.h ../lib/importproject.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.h ../lib/checkers.h ../lib/config.h ../lib/filesettings.h ../lib/importproject.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/standards.h ../lib/suppressions.h ../lib/utils.h ../lib/xml.h
$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp

$(libcppdir)/infer.o: ../lib/infer.cpp ../lib/calculate.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/mathlib.h ../lib/smallvector.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h
Expand Down
9 changes: 7 additions & 2 deletions test/cli/proj2_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
'x = 3 / 0;\n' +
' ^\n') % os.path.join('b', 'b.c')

def __get_lines(s):
# file order is not guaranteed when multiple jobs are used (TEST_CPPCHECK_INJECT_J) so
# compare output order-independently
return sorted(s.split('\n'))

def __create_compile_commands(proj_dir):
proj_dir = str(proj_dir)
j = [{'directory': os.path.join(proj_dir, 'a'), 'command': 'gcc -c a.c', 'file': 'a.c'},
Expand Down Expand Up @@ -152,7 +157,7 @@ def test_gui_project_loads_relative_vs_solution_2(tmp_path):
create_gui_project_file(os.path.join(tmp_path, 'test.cppcheck'), root_path='proj2', import_project='proj2/proj2.sln')
ret, stdout, stderr = cppcheck(['--project=test.cppcheck'], cwd=tmp_path)
assert ret == 0, stdout
assert stderr == __ERR_A + __ERR_B
assert __get_lines(stderr) == __get_lines(__ERR_A + __ERR_B)

def test_gui_project_loads_relative_vs_solution_with_exclude(tmp_path):
proj_dir = tmp_path / 'proj2'
Expand All @@ -170,4 +175,4 @@ def test_gui_project_loads_absolute_vs_solution_2(tmp_path):
import_project=os.path.join(proj_dir, 'proj2.sln'))
ret, stdout, stderr = cppcheck(['--project=test.cppcheck'], cwd=tmp_path)
assert ret == 0, stdout
assert stderr == __ERR_A + __ERR_B
assert __get_lines(stderr) == __get_lines(__ERR_A + __ERR_B)
12 changes: 12 additions & 0 deletions test/cli/props-dirs/Cpp.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<!-- Project configurations -->
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="Cpp.Build.targets" />
</Project>
3 changes: 3 additions & 0 deletions test/cli/props-dirs/Cpp.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
</Project>
6 changes: 6 additions & 0 deletions test/cli/props-dirs/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project>
<PropertyGroup>
<RepoRoot>$(MSBuildThisFileDirectory)</RepoRoot>
</PropertyGroup>
<Import Project="$(RepoRoot)Cpp.Build.props" />
</Project>
2 changes: 2 additions & 0 deletions test/cli/props-dirs/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project>
</Project>
32 changes: 32 additions & 0 deletions test/cli/props-dirs/ProjA/ProjA.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?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>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{a1a1a1a1-a1a1-a1a1-a1a1-a1a1a1a1a1a1}</ProjectGuid>
<RootNamespace>ProjA</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<!-- Pulls in shared/shared.props, which itself pulls in common/common.props -->
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(MSBuildThisFileDirectory)..\shared\shared.props" />
</ImportGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>PROJA_DEFINE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="a.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
11 changes: 11 additions & 0 deletions test/cli/props-dirs/ProjA/a.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "common.h"

#ifndef COMMON_H_INCLUDED_MARKER
#error "common.h was not found - AdditionalIncludeDirectories from common.props did not resolve"
#endif

int main()
{
int x = 1;
return x / 0;
}
29 changes: 29 additions & 0 deletions test/cli/props-dirs/ProjB/ProjB.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?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>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{b2b2b2b2-b2b2-b2b2-b2b2-b2b2b2b2b2b2}</ProjectGuid>
<RootNamespace>ProjB</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<!-- Imports common/common.props DIRECTLY - does NOT go through shared/shared.props.
Must NOT see PROJA_DEFINE or SHARED_DEFINE from ProjA, which is processed first
in the same solution (regression coverage for the mVariables cross-project leak). -->
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(MSBuildThisFileDirectory)..\common\common.props" />
</ImportGroup>
<ItemGroup>
<ClCompile Include="b.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
Loading
Loading