Merge simplecpp branch
This commit is contained in:
parent
a68da1a725
commit
03d2829fb9
28
Makefile
28
Makefile
|
@ -107,15 +107,15 @@ ifndef PREFIX
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef INCLUDE_FOR_LIB
|
ifndef INCLUDE_FOR_LIB
|
||||||
INCLUDE_FOR_LIB=-Ilib -Iexternals/tinyxml
|
INCLUDE_FOR_LIB=-Ilib -Iexternals/simplecpp -Iexternals/tinyxml
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef INCLUDE_FOR_CLI
|
ifndef INCLUDE_FOR_CLI
|
||||||
INCLUDE_FOR_CLI=-Ilib -Iexternals/tinyxml
|
INCLUDE_FOR_CLI=-Ilib -Iexternals/simplecpp -Iexternals/tinyxml
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef INCLUDE_FOR_TEST
|
ifndef INCLUDE_FOR_TEST
|
||||||
INCLUDE_FOR_TEST=-Ilib -Icli -Iexternals/tinyxml
|
INCLUDE_FOR_TEST=-Ilib -Icli -Iexternals/simplecpp -Iexternals/tinyxml
|
||||||
endif
|
endif
|
||||||
|
|
||||||
BIN=$(DESTDIR)$(PREFIX)/bin
|
BIN=$(DESTDIR)$(PREFIX)/bin
|
||||||
|
@ -171,6 +171,9 @@ LIBOBJ = $(SRCDIR)/astutils.o \
|
||||||
$(SRCDIR)/tokenlist.o \
|
$(SRCDIR)/tokenlist.o \
|
||||||
$(SRCDIR)/valueflow.o
|
$(SRCDIR)/valueflow.o
|
||||||
|
|
||||||
|
EXTOBJ = externals/simplecpp/simplecpp.o \
|
||||||
|
externals/tinyxml/tinyxml2.o
|
||||||
|
|
||||||
CLIOBJ = cli/cmdlineparser.o \
|
CLIOBJ = cli/cmdlineparser.o \
|
||||||
cli/cppcheckexecutor.o \
|
cli/cppcheckexecutor.o \
|
||||||
cli/filelister.o \
|
cli/filelister.o \
|
||||||
|
@ -236,12 +239,6 @@ TESTOBJ = test/options.o \
|
||||||
test/testvalueflow.o \
|
test/testvalueflow.o \
|
||||||
test/testvarid.o
|
test/testvarid.o
|
||||||
|
|
||||||
ifndef TINYXML
|
|
||||||
TINYXML = externals/tinyxml/tinyxml2.o
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
EXTOBJ += $(TINYXML)
|
|
||||||
.PHONY: run-dmake
|
.PHONY: run-dmake
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,11 +267,11 @@ dmake: tools/dmake.o cli/filelister.o cli/pathmatch.o lib/path.o
|
||||||
run-dmake: dmake
|
run-dmake: dmake
|
||||||
./dmake
|
./dmake
|
||||||
|
|
||||||
reduce: tools/reduce.o externals/tinyxml/tinyxml2.o $(LIBOBJ)
|
reduce: tools/reduce.o $(LIBOBJ) $(EXTOBJ)
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o reduce tools/reduce.o -Ilib -Iexternals/tinyxml $(LIBOBJ) $(LIBS) externals/tinyxml/tinyxml2.o $(LDFLAGS) $(RDYNAMIC)
|
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o reduce tools/reduce.o $(INCLUDE_FOR_LIB) $(LIBOBJ) $(LIBS) $(EXTOBJ) $(LDFLAGS) $(RDYNAMIC)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/tinyxml/*.o testrunner reduce dmake cppcheck cppcheck.1
|
rm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner reduce dmake cppcheck cppcheck.1
|
||||||
|
|
||||||
man: man/cppcheck.1
|
man: man/cppcheck.1
|
||||||
|
|
||||||
|
@ -395,7 +392,7 @@ $(SRCDIR)/mathlib.o: lib/mathlib.cpp lib/cxx11emu.h lib/mathlib.h lib/config.h l
|
||||||
$(SRCDIR)/path.o: lib/path.cpp lib/cxx11emu.h lib/path.h lib/config.h
|
$(SRCDIR)/path.o: lib/path.cpp lib/cxx11emu.h lib/path.h lib/config.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/path.o $(SRCDIR)/path.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/path.o $(SRCDIR)/path.cpp
|
||||||
|
|
||||||
$(SRCDIR)/preprocessor.o: lib/preprocessor.cpp lib/cxx11emu.h lib/preprocessor.h lib/config.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/token.h lib/valueflow.h lib/mathlib.h lib/path.h lib/settings.h lib/library.h lib/standards.h lib/timer.h
|
$(SRCDIR)/preprocessor.o: lib/preprocessor.cpp lib/cxx11emu.h lib/preprocessor.h lib/config.h lib/path.h lib/errorlogger.h lib/suppressions.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/preprocessor.o $(SRCDIR)/preprocessor.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/preprocessor.o $(SRCDIR)/preprocessor.cpp
|
||||||
|
|
||||||
$(SRCDIR)/settings.o: lib/settings.cpp lib/cxx11emu.h lib/settings.h lib/config.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/timer.h lib/preprocessor.h lib/utils.h
|
$(SRCDIR)/settings.o: lib/settings.cpp lib/cxx11emu.h lib/settings.h lib/config.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/timer.h lib/preprocessor.h lib/utils.h
|
||||||
|
@ -614,8 +611,11 @@ test/testvalueflow.o: test/testvalueflow.cpp lib/cxx11emu.h test/testsuite.h lib
|
||||||
test/testvarid.o: test/testvarid.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/standards.h lib/timer.h
|
test/testvarid.o: test/testvarid.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/standards.h lib/timer.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testvarid.o test/testvarid.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testvarid.o test/testvarid.cpp
|
||||||
|
|
||||||
|
externals/simplecpp/simplecpp.o: externals/simplecpp/simplecpp.cpp lib/cxx11emu.h externals/simplecpp/simplecpp.h
|
||||||
|
$(CXX) $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o externals/simplecpp/simplecpp.o externals/simplecpp/simplecpp.cpp
|
||||||
|
|
||||||
externals/tinyxml/tinyxml2.o: externals/tinyxml/tinyxml2.cpp lib/cxx11emu.h externals/tinyxml/tinyxml2.h
|
externals/tinyxml/tinyxml2.o: externals/tinyxml/tinyxml2.cpp lib/cxx11emu.h externals/tinyxml/tinyxml2.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o externals/tinyxml/tinyxml2.o externals/tinyxml/tinyxml2.cpp
|
$(CXX) $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o externals/tinyxml/tinyxml2.o externals/tinyxml/tinyxml2.cpp
|
||||||
|
|
||||||
tools/dmake.o: tools/dmake.cpp lib/cxx11emu.h cli/filelister.h cli/pathmatch.h
|
tools/dmake.o: tools/dmake.cpp lib/cxx11emu.h cli/filelister.h cli/pathmatch.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o tools/dmake.o tools/dmake.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o tools/dmake.o tools/dmake.cpp
|
||||||
|
|
|
@ -154,7 +154,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>..\lib;..\externals;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\lib;..\externals\simplecpp;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<BrowseInformation>false</BrowseInformation>
|
<BrowseInformation>false</BrowseInformation>
|
||||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
INCLUDEPATH += $${PWD}/simplecpp \
|
||||||
|
$${PWD}/tinyxml
|
||||||
|
|
||||||
|
HEADERS += $${PWD}/simplecpp/simplecpp.h \
|
||||||
|
$${PWD}/tinyxml/tinyxml2.h
|
||||||
|
|
||||||
|
SOURCES += $${PWD}/simplecpp/simplecpp.cpp \
|
||||||
|
$${PWD}/tinyxml/tinyxml2.cpp
|
|
@ -0,0 +1,166 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
|
||||||
|
* Copyright (C) 2016 Daniel Marjamäki.
|
||||||
|
*
|
||||||
|
* This library is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation, either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef simplecppH
|
||||||
|
#define simplecppH
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <istream>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace simplecpp {
|
||||||
|
|
||||||
|
typedef std::string TokenString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Location in source code
|
||||||
|
*/
|
||||||
|
class Location {
|
||||||
|
public:
|
||||||
|
Location(const std::vector<std::string> &f) : files(f), fileIndex(0), line(1U), col(0U) {}
|
||||||
|
|
||||||
|
Location &operator=(const Location &other) {
|
||||||
|
if (this != &other) {
|
||||||
|
fileIndex = other.fileIndex;
|
||||||
|
line = other.line;
|
||||||
|
col = other.col;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** increment this location by string */
|
||||||
|
void adjust(const std::string &str);
|
||||||
|
|
||||||
|
bool operator<(const Location &rhs) const {
|
||||||
|
if (fileIndex != rhs.fileIndex)
|
||||||
|
return fileIndex < rhs.fileIndex;
|
||||||
|
if (line != rhs.line)
|
||||||
|
return line < rhs.line;
|
||||||
|
return col < rhs.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sameline(const Location &other) const {
|
||||||
|
return fileIndex == other.fileIndex && line == other.line;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string file() const {
|
||||||
|
return fileIndex < files.size() ? files[fileIndex] : std::string("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> &files;
|
||||||
|
unsigned int fileIndex;
|
||||||
|
unsigned int line;
|
||||||
|
unsigned int col;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token class.
|
||||||
|
* @todo don't use std::string representation - for both memory and performance reasons
|
||||||
|
*/
|
||||||
|
class Token {
|
||||||
|
public:
|
||||||
|
Token(const TokenString &s, const Location &loc) :
|
||||||
|
str(string), location(loc), previous(nullptr), next(nullptr), string(s)
|
||||||
|
{
|
||||||
|
flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
Token(const Token &tok) :
|
||||||
|
str(string), macro(tok.macro), location(tok.location), previous(nullptr), next(nullptr), string(tok.str)
|
||||||
|
{
|
||||||
|
flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
void flags() {
|
||||||
|
name = (str[0] == '_' || std::isalpha(str[0]));
|
||||||
|
comment = (str.compare(0, 2, "//") == 0 || str.compare(0, 2, "/*") == 0);
|
||||||
|
number = std::isdigit(str[0]) || (str.size() > 1U && str[0] == '-' && std::isdigit(str[1]));
|
||||||
|
op = (str.size() == 1U) ? str[0] : '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void setstr(const std::string &s) {
|
||||||
|
string = s;
|
||||||
|
flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOneOf(const char ops[]) const;
|
||||||
|
bool startsWithOneOf(const char c[]) const;
|
||||||
|
bool endsWithOneOf(const char c[]) const;
|
||||||
|
|
||||||
|
char op;
|
||||||
|
const TokenString &str;
|
||||||
|
TokenString macro;
|
||||||
|
bool comment;
|
||||||
|
bool name;
|
||||||
|
bool number;
|
||||||
|
Location location;
|
||||||
|
Token *previous;
|
||||||
|
Token *next;
|
||||||
|
private:
|
||||||
|
TokenString string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Output from preprocessor */
|
||||||
|
struct Output {
|
||||||
|
Output(const std::vector<std::string> &files) : type(ERROR), location(files) {}
|
||||||
|
enum Type {
|
||||||
|
ERROR, /* error */
|
||||||
|
WARNING /* warning */
|
||||||
|
} type;
|
||||||
|
Location location;
|
||||||
|
std::string msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<struct Output> OutputList;
|
||||||
|
|
||||||
|
/** List of tokens. */
|
||||||
|
class TokenList {
|
||||||
|
public:
|
||||||
|
TokenList(std::vector<std::string> &filenames);
|
||||||
|
TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = 0);
|
||||||
|
TokenList(const TokenList &other);
|
||||||
|
~TokenList();
|
||||||
|
void operator=(const TokenList &other);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
bool empty() const {
|
||||||
|
return !cbegin();
|
||||||
|
}
|
||||||
|
void push_back(Token *token);
|
||||||
|
|
||||||
|
void dump() const;
|
||||||
|
std::string stringify() const;
|
||||||
|
|
||||||
|
void readfile(std::istream &istr, const std::string &filename=std::string(), OutputList *outputList = 0);
|
||||||
|
void constFold();
|
||||||
|
|
||||||
|
void removeComments();
|
||||||
|
|
||||||
|
Token *begin() {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token *cbegin() const {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token *end() {
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token *cend() const {
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteToken(Token *tok) {
|
||||||
|
if (!tok)
|
||||||
|
return;
|
||||||
|
Token *prev = tok->previous;
|
||||||
|
Token *next = tok->next;
|
||||||
|
if (prev)
|
||||||
|
prev->next = next;
|
||||||
|
if (next)
|
||||||
|
next->previous = prev;
|
||||||
|
if (first == tok)
|
||||||
|
first = next;
|
||||||
|
if (last == tok)
|
||||||
|
last = prev;
|
||||||
|
delete tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void combineOperators();
|
||||||
|
|
||||||
|
void constFoldUnaryNotPosNeg(Token *tok);
|
||||||
|
void constFoldMulDivRem(Token *tok);
|
||||||
|
void constFoldAddSub(Token *tok);
|
||||||
|
void constFoldComparison(Token *tok);
|
||||||
|
void constFoldBitwise(Token *tok);
|
||||||
|
void constFoldLogicalOp(Token *tok);
|
||||||
|
void constFoldQuestionOp(Token **tok);
|
||||||
|
|
||||||
|
std::string readUntil(std::istream &istr, const Location &location, const char start, const char end, OutputList *outputList);
|
||||||
|
|
||||||
|
std::string lastLine() const;
|
||||||
|
|
||||||
|
unsigned int fileIndex(const std::string &filename);
|
||||||
|
|
||||||
|
Token *first;
|
||||||
|
Token *last;
|
||||||
|
std::vector<std::string> &files;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Tracking how macros are used */
|
||||||
|
struct MacroUsage {
|
||||||
|
MacroUsage(const std::vector<std::string> &f) : macroLocation(f), useLocation(f) {}
|
||||||
|
std::string macroName;
|
||||||
|
Location macroLocation;
|
||||||
|
Location useLocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DUI {
|
||||||
|
std::list<std::string> defines;
|
||||||
|
std::set<std::string> undefined;
|
||||||
|
std::list<std::string> includePaths;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, TokenList*> load(const TokenList &rawtokens, std::vector<std::string> &filenames, const struct DUI &dui, OutputList *outputList = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preprocess
|
||||||
|
*
|
||||||
|
* Preprocessing is done in two steps currently:
|
||||||
|
* const simplecpp::TokenList tokens1 = simplecpp::TokenList(f);
|
||||||
|
* const simplecpp::TokenList tokens2 = simplecpp::preprocess(tokens1, defines);
|
||||||
|
*
|
||||||
|
* The "tokens1" will contain tokens for comments and for preprocessor directives. And there is no preprocessing done.
|
||||||
|
* This "tokens1" can be used if you need to see what comments/directives there are. Or what code is hidden in #if.
|
||||||
|
*
|
||||||
|
* The "tokens2" will have normal preprocessor output. No comments nor directives are seen.
|
||||||
|
*
|
||||||
|
* @todo simplify interface
|
||||||
|
*/
|
||||||
|
TokenList preprocess(const TokenList &rawtokens, std::vector<std::string> &files, const std::map<std::string, TokenList*> &filedata, const struct DUI &dui, OutputList *outputList = 0, std::list<struct MacroUsage> *macroUsage = 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,2 +0,0 @@
|
||||||
HEADERS += $${PWD}/tinyxml2.h
|
|
||||||
SOURCES += $${PWD}/tinyxml2.cpp
|
|
|
@ -37,7 +37,6 @@ static const struct CWE CWE197(197U); // Numeric Truncation Error
|
||||||
static const struct CWE CWE369(369U);
|
static const struct CWE CWE369(369U);
|
||||||
static const struct CWE CWE398(398U); // Indicator of Poor Code Quality
|
static const struct CWE CWE398(398U); // Indicator of Poor Code Quality
|
||||||
static const struct CWE CWE475(475U); // Undefined Behavior for Input to API
|
static const struct CWE CWE475(475U); // Undefined Behavior for Input to API
|
||||||
static const struct CWE CWE484(484U); // Omitted Break Statement in Switch
|
|
||||||
static const struct CWE CWE561(561U); // Dead Code
|
static const struct CWE CWE561(561U); // Dead Code
|
||||||
static const struct CWE CWE563(563U); // Assignment to Variable without Use ('Unused Variable')
|
static const struct CWE CWE563(563U); // Assignment to Variable without Use ('Unused Variable')
|
||||||
static const struct CWE CWE570(570U); // Expression is Always False
|
static const struct CWE CWE570(570U); // Expression is Always False
|
||||||
|
@ -839,79 +838,6 @@ void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
// Detect fall through cases (experimental).
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void CheckOther::checkSwitchCaseFallThrough()
|
|
||||||
{
|
|
||||||
if (!(_settings->isEnabled("style") && _settings->experimental))
|
|
||||||
return;
|
|
||||||
|
|
||||||
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
|
|
||||||
|
|
||||||
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
|
|
||||||
if (i->type != Scope::eSwitch || !i->classStart) // Find the beginning of a switch
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check the contents of the switch statement
|
|
||||||
std::stack<std::pair<Token *, bool> > ifnest;
|
|
||||||
bool justbreak = true;
|
|
||||||
bool firstcase = true;
|
|
||||||
for (const Token *tok2 = i->classStart; tok2 != i->classEnd; tok2 = tok2->next()) {
|
|
||||||
if (Token::simpleMatch(tok2, "if (")) {
|
|
||||||
tok2 = tok2->next()->link()->next();
|
|
||||||
ifnest.push(std::make_pair(tok2->link(), false));
|
|
||||||
justbreak = false;
|
|
||||||
} else if (Token::simpleMatch(tok2, "while (")) {
|
|
||||||
tok2 = tok2->next()->link()->next();
|
|
||||||
if (tok2->link()) // skip over "do { } while ( ) ;" case
|
|
||||||
tok2 = tok2->link();
|
|
||||||
justbreak = false;
|
|
||||||
} else if (Token::simpleMatch(tok2, "do {")) {
|
|
||||||
tok2 = tok2->next()->link();
|
|
||||||
justbreak = false;
|
|
||||||
} else if (Token::simpleMatch(tok2, "for (")) {
|
|
||||||
tok2 = tok2->next()->link()->next()->link();
|
|
||||||
justbreak = false;
|
|
||||||
} else if (Token::simpleMatch(tok2, "switch (")) {
|
|
||||||
// skip over nested switch, we'll come to that soon
|
|
||||||
tok2 = tok2->next()->link()->next()->link();
|
|
||||||
} else if (Token::Match(tok2, "break|continue|return|exit|goto|throw")) {
|
|
||||||
justbreak = true;
|
|
||||||
tok2 = Token::findsimplematch(tok2, ";");
|
|
||||||
} else if (Token::Match(tok2, "case|default")) {
|
|
||||||
if (!justbreak && !firstcase) {
|
|
||||||
switchCaseFallThrough(tok2);
|
|
||||||
}
|
|
||||||
tok2 = Token::findsimplematch(tok2, ":");
|
|
||||||
justbreak = true;
|
|
||||||
firstcase = false;
|
|
||||||
} else if (tok2->str() == "}") {
|
|
||||||
if (!ifnest.empty() && tok2 == ifnest.top().first) {
|
|
||||||
if (tok2->next()->str() == "else") {
|
|
||||||
tok2 = tok2->tokAt(2);
|
|
||||||
ifnest.pop();
|
|
||||||
ifnest.push(std::make_pair(tok2->link(), justbreak));
|
|
||||||
justbreak = false;
|
|
||||||
} else {
|
|
||||||
justbreak &= ifnest.top().second;
|
|
||||||
ifnest.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (tok2->str() != ";") {
|
|
||||||
justbreak = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckOther::switchCaseFallThrough(const Token *tok)
|
|
||||||
{
|
|
||||||
reportError(tok, Severity::style,
|
|
||||||
"switchCaseFallThrough", "Switch falls through case without comment. 'break;' missing?", CWE484, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Check for statements like case A||B: in switch()
|
// Check for statements like case A||B: in switch()
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -88,7 +88,6 @@ public:
|
||||||
checkOther.checkMisusedScopedObject();
|
checkOther.checkMisusedScopedObject();
|
||||||
checkOther.checkMemsetZeroBytes();
|
checkOther.checkMemsetZeroBytes();
|
||||||
checkOther.checkMemsetInvalid2ndParam();
|
checkOther.checkMemsetInvalid2ndParam();
|
||||||
checkOther.checkSwitchCaseFallThrough();
|
|
||||||
checkOther.checkPipeParameterSize();
|
checkOther.checkPipeParameterSize();
|
||||||
|
|
||||||
checkOther.checkInvalidFree();
|
checkOther.checkInvalidFree();
|
||||||
|
@ -143,9 +142,6 @@ public:
|
||||||
/** @brief %Check for code like 'case A||B:'*/
|
/** @brief %Check for code like 'case A||B:'*/
|
||||||
void checkSuspiciousEqualityComparison();
|
void checkSuspiciousEqualityComparison();
|
||||||
|
|
||||||
/** @brief %Check for switch case fall through without comment */
|
|
||||||
void checkSwitchCaseFallThrough();
|
|
||||||
|
|
||||||
/** @brief %Check for objects that are destroyed immediately */
|
/** @brief %Check for objects that are destroyed immediately */
|
||||||
void checkMisusedScopedObject();
|
void checkMisusedScopedObject();
|
||||||
|
|
||||||
|
@ -230,7 +226,6 @@ private:
|
||||||
void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var);
|
void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var);
|
||||||
void redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var);
|
void redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var);
|
||||||
void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
|
void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
|
||||||
void switchCaseFallThrough(const Token *tok);
|
|
||||||
void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString);
|
void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString);
|
||||||
void suspiciousEqualityComparisonError(const Token* tok);
|
void suspiciousEqualityComparisonError(const Token* tok);
|
||||||
void selfAssignmentError(const Token *tok, const std::string &varname);
|
void selfAssignmentError(const Token *tok, const std::string &varname);
|
||||||
|
@ -287,7 +282,6 @@ private:
|
||||||
c.variableScopeError(nullptr, "varname");
|
c.variableScopeError(nullptr, "varname");
|
||||||
c.redundantAssignmentInSwitchError(nullptr, 0, "var");
|
c.redundantAssignmentInSwitchError(nullptr, 0, "var");
|
||||||
c.redundantCopyInSwitchError(nullptr, 0, "var");
|
c.redundantCopyInSwitchError(nullptr, 0, "var");
|
||||||
c.switchCaseFallThrough(nullptr);
|
|
||||||
c.suspiciousCaseInSwitchError(nullptr, "||");
|
c.suspiciousCaseInSwitchError(nullptr, "||");
|
||||||
c.suspiciousEqualityComparisonError(nullptr);
|
c.suspiciousEqualityComparisonError(nullptr);
|
||||||
c.selfAssignmentError(nullptr, "varname");
|
c.selfAssignmentError(nullptr, "varname");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "cppcheck.h"
|
#include "cppcheck.h"
|
||||||
|
|
||||||
#include "preprocessor.h" // Preprocessor
|
#include "preprocessor.h" // Preprocessor
|
||||||
|
#include "simplecpp.h"
|
||||||
#include "tokenize.h" // Tokenizer
|
#include "tokenize.h" // Tokenizer
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
@ -99,43 +100,62 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
||||||
bool internalErrorFound(false);
|
bool internalErrorFound(false);
|
||||||
try {
|
try {
|
||||||
Preprocessor preprocessor(_settings, this);
|
Preprocessor preprocessor(_settings, this);
|
||||||
std::list<std::string> configurations;
|
std::set<std::string> configurations;
|
||||||
std::string filedata;
|
|
||||||
|
|
||||||
{
|
simplecpp::OutputList outputList;
|
||||||
Timer t("Preprocessor::preprocess", _settings.showtime, &S_timerResults);
|
std::vector<std::string> files;
|
||||||
preprocessor.preprocess(fileStream, filedata, configurations, filename, _settings.includePaths);
|
const simplecpp::TokenList tokens1(fileStream, files, filename, &outputList);
|
||||||
|
|
||||||
|
// Get configurations..
|
||||||
|
if (_settings.userDefines.empty() || _settings.force) {
|
||||||
|
Timer t("Preprocessor::getConfigs", _settings.showtime, &S_timerResults);
|
||||||
|
preprocessor.loadFiles(tokens1, files);
|
||||||
|
configurations = preprocessor.getConfigs(tokens1);
|
||||||
|
} else {
|
||||||
|
configurations.insert(_settings.userDefines);
|
||||||
|
preprocessor.loadFiles(tokens1, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preprocessor.inlineSuppressions(tokens1);
|
||||||
|
|
||||||
if (_settings.checkConfiguration) {
|
if (_settings.checkConfiguration) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run define rules on raw code
|
// Run define rules on raw code
|
||||||
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
|
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
|
||||||
if (it->tokenlist == "define") {
|
if (it->tokenlist != "define")
|
||||||
Tokenizer tokenizer2(&_settings, this);
|
continue;
|
||||||
std::istringstream istr2(filedata);
|
|
||||||
tokenizer2.list.createTokens(istr2, filename);
|
|
||||||
|
|
||||||
for (const Token *tok = tokenizer2.list.front(); tok; tok = tok->next()) {
|
for (const simplecpp::Token *tok = tokens1.cbegin(); tok; tok = tok->next) {
|
||||||
if (tok->str() == "#define") {
|
if (tok->op != '#')
|
||||||
std::string code = std::string(tok->linenr()-1U, '\n');
|
continue;
|
||||||
for (const Token *tok2 = tok; tok2 && tok2->linenr() == tok->linenr(); tok2 = tok2->next())
|
if (tok->previous && tok->previous->location.sameline(tok->location))
|
||||||
code += " " + tok2->str();
|
continue;
|
||||||
Tokenizer tokenizer3(&_settings, this);
|
|
||||||
std::istringstream istr3(code);
|
std::string directive;
|
||||||
tokenizer3.list.createTokens(istr3, tokenizer2.list.file(tok));
|
for (const simplecpp::Token *tok2 = tok; tok2 && tok->location.sameline(tok2->location); tok2 = tok2->next) {
|
||||||
executeRules("define", tokenizer3);
|
if (tok2->comment)
|
||||||
}
|
continue;
|
||||||
|
while (directive.size() < tok2->location.col)
|
||||||
|
directive += ' ';
|
||||||
|
directive += tok2->str;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_settings.userDefines.empty() && _settings.maxConfigs==1U) {
|
if (directive.compare(0,8,"#define ") != 0)
|
||||||
configurations.clear();
|
continue;
|
||||||
configurations.push_back(_settings.userDefines);
|
|
||||||
|
const std::string code = "#line " +
|
||||||
|
std::to_string(tok->location.line) +
|
||||||
|
'\"' + tok->location.file() + "\'\n" +
|
||||||
|
directive;
|
||||||
|
|
||||||
|
Tokenizer tokenizer2(&_settings, this);
|
||||||
|
std::istringstream istr2(code);
|
||||||
|
tokenizer2.list.createTokens(istr2, tok->location.file());
|
||||||
|
executeRules("define", tokenizer2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_settings.force && configurations.size() > _settings.maxConfigs) {
|
if (!_settings.force && configurations.size() > _settings.maxConfigs) {
|
||||||
|
@ -159,7 +179,7 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
||||||
|
|
||||||
std::set<unsigned long long> checksums;
|
std::set<unsigned long long> checksums;
|
||||||
unsigned int checkCount = 0;
|
unsigned int checkCount = 0;
|
||||||
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
|
for (std::set<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
|
||||||
// bail out if terminated
|
// bail out if terminated
|
||||||
if (_settings.terminated())
|
if (_settings.terminated())
|
||||||
break;
|
break;
|
||||||
|
@ -184,10 +204,11 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
||||||
cfg = _settings.userDefines + cfg;
|
cfg = _settings.userDefines + cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer t("Preprocessor::getcode", _settings.showtime, &S_timerResults);
|
std::string codeWithoutCfg;
|
||||||
std::string codeWithoutCfg = preprocessor.getcode(filedata, cfg, filename);
|
{
|
||||||
t.Stop();
|
Timer t("Preprocessor::getcode", _settings.showtime, &S_timerResults);
|
||||||
|
codeWithoutCfg = preprocessor.getcode(tokens1, cfg, files, true);
|
||||||
|
}
|
||||||
codeWithoutCfg += _settings.append();
|
codeWithoutCfg += _settings.append();
|
||||||
|
|
||||||
if (_settings.preprocessOnly) {
|
if (_settings.preprocessOnly) {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp" />
|
||||||
<ClCompile Include="..\externals\tinyxml\tinyxml2.cpp" />
|
<ClCompile Include="..\externals\tinyxml\tinyxml2.cpp" />
|
||||||
<ClCompile Include="astutils.cpp" />
|
<ClCompile Include="astutils.cpp" />
|
||||||
<ClCompile Include="check.cpp">
|
<ClCompile Include="check.cpp">
|
||||||
|
@ -264,7 +265,7 @@
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>CPPCHECKLIB_EXPORT;TINYXML2_EXPORT;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>CPPCHECKLIB_EXPORT;TINYXML2_EXPORT;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<AdditionalIncludeDirectories>..\externals;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\externals\simplecpp;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<DisableSpecificWarnings>4251;4482;4512</DisableSpecificWarnings>
|
<DisableSpecificWarnings>4251;4482;4512</DisableSpecificWarnings>
|
||||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
|
|
@ -140,6 +140,9 @@
|
||||||
<ClCompile Include="checkfunctions.cpp">
|
<ClCompile Include="checkfunctions.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="checkbufferoverrun.h">
|
<ClInclude Include="checkbufferoverrun.h">
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# no manual edits - this file is autogenerated by dmake
|
# no manual edits - this file is autogenerated by dmake
|
||||||
|
|
||||||
include($$PWD/pcrerules.pri)
|
include($$PWD/pcrerules.pri)
|
||||||
include($$PWD/../externals/tinyxml/tinyxml.pri)
|
include($$PWD/../externals/externals.pri)
|
||||||
INCLUDEPATH += $$PWD $$PWD/../externals/tinyxml
|
INCLUDEPATH += $$PWD
|
||||||
HEADERS += $${PWD}/check.h \
|
HEADERS += $${PWD}/check.h \
|
||||||
$${PWD}/astutils.h \
|
$${PWD}/astutils.h \
|
||||||
$${PWD}/check.h \
|
$${PWD}/check.h \
|
||||||
|
|
3275
lib/preprocessor.cpp
3275
lib/preprocessor.cpp
File diff suppressed because it is too large
Load Diff
|
@ -21,12 +21,14 @@
|
||||||
#define preprocessorH
|
#define preprocessorH
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "simplecpp.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
class ErrorLogger;
|
class ErrorLogger;
|
||||||
class Settings;
|
class Settings;
|
||||||
|
@ -79,10 +81,17 @@ public:
|
||||||
static char macroChar;
|
static char macroChar;
|
||||||
|
|
||||||
Preprocessor(Settings& settings, ErrorLogger *errorLogger = nullptr);
|
Preprocessor(Settings& settings, ErrorLogger *errorLogger = nullptr);
|
||||||
|
virtual ~Preprocessor();
|
||||||
|
|
||||||
static bool missingIncludeFlag;
|
static bool missingIncludeFlag;
|
||||||
static bool missingSystemIncludeFlag;
|
static bool missingSystemIncludeFlag;
|
||||||
|
|
||||||
|
void inlineSuppressions(const simplecpp::TokenList &tokens);
|
||||||
|
|
||||||
|
std::set<std::string> getConfigs(const simplecpp::TokenList &tokens) const;
|
||||||
|
|
||||||
|
void loadFiles(const simplecpp::TokenList &rawtokens, std::vector<std::string> &files);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the code for each configuration
|
* Extract the code for each configuration
|
||||||
* @param istr The (file/string) stream to read from.
|
* @param istr The (file/string) stream to read from.
|
||||||
|
@ -115,14 +124,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void preprocess(std::istream &srcCodeStream, std::string &processedFile, std::list<std::string> &resultConfigurations, const std::string &filename, const std::list<std::string> &includePaths);
|
void preprocess(std::istream &srcCodeStream, std::string &processedFile, std::list<std::string> &resultConfigurations, const std::string &filename, const std::list<std::string> &includePaths);
|
||||||
|
|
||||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
std::string getcode(const simplecpp::TokenList &tokens1, const std::string &cfg, std::vector<std::string> &files, const bool writeLocations);
|
||||||
std::string read(std::istream &istr, const std::string &filename);
|
|
||||||
|
|
||||||
/** read preprocessor statements into a string. */
|
|
||||||
static std::string readpreprocessor(std::istream &istr, const unsigned int bom);
|
|
||||||
|
|
||||||
/** should __cplusplus be defined? */
|
|
||||||
static bool cplusplus(const Settings *settings, const std::string &filename);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get preprocessed code for a given configuration
|
* Get preprocessed code for a given configuration
|
||||||
|
@ -132,14 +134,6 @@ public:
|
||||||
*/
|
*/
|
||||||
std::string getcode(const std::string &filedata, const std::string &cfg, const std::string &filename);
|
std::string getcode(const std::string &filedata, const std::string &cfg, const std::string &filename);
|
||||||
|
|
||||||
/**
|
|
||||||
* simplify condition
|
|
||||||
* @param variables Variable values
|
|
||||||
* @param condition The condition to simplify
|
|
||||||
* @param match if true, 'defined(A)' is replaced with 0 if A is not defined
|
|
||||||
*/
|
|
||||||
void simplifyCondition(const std::map<std::string, std::string> &variables, std::string &condition, bool match);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* preprocess all whitespaces
|
* preprocess all whitespaces
|
||||||
* @param processedFile The data to be processed
|
* @param processedFile The data to be processed
|
||||||
|
@ -155,8 +149,6 @@ public:
|
||||||
bool validateCfg(const std::string &code, const std::string &cfg);
|
bool validateCfg(const std::string &code, const std::string &cfg);
|
||||||
void validateCfgError(const std::string &cfg, const std::string ¯o);
|
void validateCfgError(const std::string &cfg, const std::string ¯o);
|
||||||
|
|
||||||
void handleUndef(std::list<std::string> &configurations) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* report error
|
* report error
|
||||||
* @param fileName name of file that the error was found in
|
* @param fileName name of file that the error was found in
|
||||||
|
@ -167,39 +159,6 @@ public:
|
||||||
*/
|
*/
|
||||||
static void writeError(const std::string &fileName, const unsigned int linenr, ErrorLogger *errorLogger, const std::string &errorType, const std::string &errorText);
|
static void writeError(const std::string &fileName, const unsigned int linenr, ErrorLogger *errorLogger, const std::string &errorType, const std::string &errorText);
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace "#if defined" with "#ifdef" where possible
|
|
||||||
*
|
|
||||||
* @param str The string to be converted
|
|
||||||
*/
|
|
||||||
void replaceIfDefined(std::string &str) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* expand macros in code. ifdefs etc are ignored so the code must be a single configuration
|
|
||||||
* @param code The input code
|
|
||||||
* @param filename filename of source file
|
|
||||||
* @param cfg user given -D configuration
|
|
||||||
* @param errorLogger Error logger to write errors to (if any)
|
|
||||||
* @return the expanded string
|
|
||||||
*/
|
|
||||||
static std::string expandMacros(const std::string &code, std::string filename, const std::string &cfg, ErrorLogger *errorLogger);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove comments from code. This should only be called from read().
|
|
||||||
* If there are inline suppressions, the _settings member is modified
|
|
||||||
* @param str Code processed by read().
|
|
||||||
* @param filename filename
|
|
||||||
* @return code without comments
|
|
||||||
*/
|
|
||||||
std::string removeComments(const std::string &str, const std::string &filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup 'if 0' from the code
|
|
||||||
* @param code Code processed by read().
|
|
||||||
* @return code without 'if 0'
|
|
||||||
*/
|
|
||||||
static std::string removeIf0(const std::string &code);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove redundant parentheses from preprocessor commands. This should only be called from read().
|
* Remove redundant parentheses from preprocessor commands. This should only be called from read().
|
||||||
* @param str Code processed by read().
|
* @param str Code processed by read().
|
||||||
|
@ -236,40 +195,9 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all possible configurations sorted in alphabetical order.
|
|
||||||
* By looking at the ifdefs and ifndefs in filedata
|
|
||||||
*/
|
|
||||||
std::list<std::string> getcfgs(const std::string &filedata, const std::string &filename, const std::map<std::string, std::string> &defs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove asm(...) from a string
|
|
||||||
* @param str Code
|
|
||||||
*/
|
|
||||||
static void removeAsm(std::string &str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate condition 'numerically'
|
|
||||||
* @param cfg configuration
|
|
||||||
* @param def condition
|
|
||||||
* @return result when evaluating the condition
|
|
||||||
*/
|
|
||||||
bool match_cfg_def(std::map<std::string, std::string> cfg, std::string def);
|
|
||||||
|
|
||||||
static void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings);
|
static void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings);
|
||||||
|
|
||||||
/**
|
|
||||||
* handle includes for a specific configuration
|
|
||||||
* @param code code in string
|
|
||||||
* @param filePath filename of code
|
|
||||||
* @param includePaths Paths where headers might be
|
|
||||||
* @param defs defines (only values)
|
|
||||||
* @param pragmaOnce includes that has already been included and contains a \#pragma once statement
|
|
||||||
* @param includes provide a empty list. this is just used to prevent recursive inclusions.
|
|
||||||
* \return resulting string
|
|
||||||
*/
|
|
||||||
std::string handleIncludes(const std::string &code, const std::string &filePath, const std::list<std::string> &includePaths, std::map<std::string,std::string> &defs, std::set<std::string> &pragmaOnce, std::list<std::string> includes);
|
|
||||||
|
|
||||||
void setFile0(const std::string &f) {
|
void setFile0(const std::string &f) {
|
||||||
file0 = f;
|
file0 = f;
|
||||||
}
|
}
|
||||||
|
@ -284,25 +212,14 @@ private:
|
||||||
|
|
||||||
void error(const std::string &filename, unsigned int linenr, const std::string &msg);
|
void error(const std::string &filename, unsigned int linenr, const std::string &msg);
|
||||||
|
|
||||||
/**
|
|
||||||
* Search includes from code and append code from the included
|
|
||||||
* file
|
|
||||||
* @param[in,out] code The source code to modify
|
|
||||||
* @param filePath Relative path to file to check e.g. "src/main.cpp"
|
|
||||||
* @param includePaths List of paths where include files should be searched from,
|
|
||||||
* single path can be e.g. in format "include/".
|
|
||||||
* There must be a path separator at the end. Default parameter is empty list.
|
|
||||||
* Note that if path from given filename is also extracted and that is used as
|
|
||||||
* a last include path if include file was not found from earlier paths.
|
|
||||||
*/
|
|
||||||
void handleIncludes(std::string &code, const std::string &filePath, const std::list<std::string> &includePaths);
|
|
||||||
|
|
||||||
Settings& _settings;
|
Settings& _settings;
|
||||||
ErrorLogger *_errorLogger;
|
ErrorLogger *_errorLogger;
|
||||||
|
|
||||||
/** list of all directives met while preprocessing file */
|
/** list of all directives met while preprocessing file */
|
||||||
std::list<Directive> directives;
|
std::list<Directive> directives;
|
||||||
|
|
||||||
|
std::map<std::string, simplecpp::TokenList *> tokenlists;
|
||||||
|
|
||||||
/** filename for cpp/c file - useful when reporting errors */
|
/** filename for cpp/c file - useful when reporting errors */
|
||||||
std::string file0;
|
std::string file0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
#ifndef A
|
#ifdef A
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
[samples\syntaxError\bad.c:2]: (error) Invalid number of character '{' when these macros are defined: 'A'.
|
[samples\syntaxError\bad.c:2]: (error) Invalid number of character '{' when these macros are defined: ''.
|
||||||
|
|
|
@ -23,7 +23,8 @@ void leakReturnValNotUsed()
|
||||||
// cppcheck-suppress nullPointer
|
// cppcheck-suppress nullPointer
|
||||||
strcasestr("test", NULL);
|
strcasestr("test", NULL);
|
||||||
|
|
||||||
//
|
// cppcheck-suppress knownConditionTrueFalse
|
||||||
|
// cppcheck-suppress duplicateExpression
|
||||||
if (42 == __builtin_expect(42, 0))
|
if (42 == __builtin_expect(42, 0))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,6 @@ private:
|
||||||
TEST_CASE(switchRedundantAssignmentTest);
|
TEST_CASE(switchRedundantAssignmentTest);
|
||||||
TEST_CASE(switchRedundantOperationTest);
|
TEST_CASE(switchRedundantOperationTest);
|
||||||
TEST_CASE(switchRedundantBitwiseOperationTest);
|
TEST_CASE(switchRedundantBitwiseOperationTest);
|
||||||
TEST_CASE(switchFallThroughCase);
|
|
||||||
TEST_CASE(unreachableCode);
|
TEST_CASE(unreachableCode);
|
||||||
|
|
||||||
TEST_CASE(suspiciousCase);
|
TEST_CASE(suspiciousCase);
|
||||||
|
@ -221,41 +220,6 @@ private:
|
||||||
check(code, nullptr, false, false, true, &settings);
|
check(code, nullptr, false, false, true, &settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_preprocess_suppress(const char precode[], const char *filename = nullptr) {
|
|
||||||
// Clear the error buffer..
|
|
||||||
errout.str("");
|
|
||||||
|
|
||||||
if (filename == nullptr)
|
|
||||||
filename = "test.cpp";
|
|
||||||
|
|
||||||
Settings settings;
|
|
||||||
settings.addEnabled("warning");
|
|
||||||
settings.addEnabled("style");
|
|
||||||
settings.addEnabled("performance");
|
|
||||||
settings.experimental = true;
|
|
||||||
|
|
||||||
// Preprocess file..
|
|
||||||
SimpleSuppressor logger(settings, this);
|
|
||||||
Preprocessor preprocessor(settings, &logger);
|
|
||||||
std::list<std::string> configurations;
|
|
||||||
std::string filedata = "";
|
|
||||||
std::istringstream fin(precode);
|
|
||||||
preprocessor.preprocess(fin, filedata, configurations, filename, settings.includePaths);
|
|
||||||
const std::string code = preprocessor.getcode(filedata, "", filename);
|
|
||||||
|
|
||||||
// Tokenize..
|
|
||||||
Tokenizer tokenizer(&settings, &logger);
|
|
||||||
std::istringstream istr(code);
|
|
||||||
tokenizer.tokenize(istr, filename);
|
|
||||||
|
|
||||||
// Check..
|
|
||||||
CheckOther checkOther(&tokenizer, &settings, &logger);
|
|
||||||
checkOther.checkSwitchCaseFallThrough();
|
|
||||||
|
|
||||||
logger.reportUnmatchedSuppressions(settings.nomsg.getUnmatchedLocalSuppressions(filename, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void emptyBrackets() {
|
void emptyBrackets() {
|
||||||
check("{\n"
|
check("{\n"
|
||||||
"}");
|
"}");
|
||||||
|
@ -2163,307 +2127,6 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchFallThroughCase() {
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" break;\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" break;\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" continue;\n"
|
|
||||||
" case 3:\n"
|
|
||||||
" return;\n"
|
|
||||||
" case 4:\n"
|
|
||||||
" exit(1);\n"
|
|
||||||
" case 5:\n"
|
|
||||||
" goto end;\n"
|
|
||||||
" case 6:\n"
|
|
||||||
" throw e;\n"
|
|
||||||
" case 7:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 0:\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" break;\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" default:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // fall through\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" /* FALLTHRU */\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" break;\n"
|
|
||||||
" // fall through\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:7]: (information) Unmatched suppression: switchCaseFallThrough\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" {\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" for (;;) {\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:7]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" if (b) {\n"
|
|
||||||
" break;\n"
|
|
||||||
" } else {\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" if (b) {\n"
|
|
||||||
" break;\n"
|
|
||||||
" } else {\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:8]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" if (b) {\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:7]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" if (b) {\n"
|
|
||||||
" } else {\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:8]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" if (b) {\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" } else {\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" int x;\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" switch (b) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" return;\n"
|
|
||||||
" default:\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
// This fails because the switch parsing code currently doesn't understand
|
|
||||||
// that all paths after g() actually return. It's a pretty unusual case
|
|
||||||
// (no pun intended).
|
|
||||||
TODO_ASSERT_EQUALS("",
|
|
||||||
"[test.cpp:11]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
"#ifndef A\n"
|
|
||||||
" g();\n"
|
|
||||||
" // fall through\n"
|
|
||||||
"#endif\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" goto leave;\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"leave:\n"
|
|
||||||
" if (x) {\n"
|
|
||||||
" g();\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" switch (a) {\n"
|
|
||||||
" case 1:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // fall through\n"
|
|
||||||
" case 2:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // falls through\n"
|
|
||||||
" case 3:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // fall-through\n"
|
|
||||||
" case 4:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // drop through\n"
|
|
||||||
" case 5:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // pass through\n"
|
|
||||||
" case 5:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // no break\n"
|
|
||||||
" case 5:\n"
|
|
||||||
" g();\n"
|
|
||||||
" // fallthru\n"
|
|
||||||
" case 6:\n"
|
|
||||||
" g();\n"
|
|
||||||
" /* fall */\n"
|
|
||||||
" default:\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check_preprocess_suppress(
|
|
||||||
"void foo() {\n"
|
|
||||||
" // unrelated comment saying 'fall through'\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void unreachableCode() {
|
void unreachableCode() {
|
||||||
check("void foo(int a) {\n"
|
check("void foo(int a) {\n"
|
||||||
" while(1) {\n"
|
" while(1) {\n"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,6 +29,7 @@
|
||||||
<ClCompile Include="..\cli\filelister.cpp" />
|
<ClCompile Include="..\cli\filelister.cpp" />
|
||||||
<ClCompile Include="..\cli\pathmatch.cpp" />
|
<ClCompile Include="..\cli\pathmatch.cpp" />
|
||||||
<ClCompile Include="..\cli\threadexecutor.cpp" />
|
<ClCompile Include="..\cli\threadexecutor.cpp" />
|
||||||
|
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp" />
|
||||||
<ClCompile Include="options.cpp" />
|
<ClCompile Include="options.cpp" />
|
||||||
<ClCompile Include="test64bit.cpp" />
|
<ClCompile Include="test64bit.cpp" />
|
||||||
<ClCompile Include="testassert.cpp" />
|
<ClCompile Include="testassert.cpp" />
|
||||||
|
@ -168,7 +169,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>..\cli;..\lib;..\externals;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\cli;..\lib;..\externals\simplecpp;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
|
|
|
@ -202,6 +202,9 @@
|
||||||
<ClCompile Include="testfunctions.cpp">
|
<ClCompile Include="testfunctions.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="options.h">
|
<ClInclude Include="options.h">
|
||||||
|
|
|
@ -112,45 +112,6 @@ static void makeConditionalVariable(std::ostream &os, const std::string &variabl
|
||||||
<< "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getLibName(const std::string &path)
|
|
||||||
{
|
|
||||||
// path can be e.g. "externals/foo/foo.cpp" then returned
|
|
||||||
// library name is "FOO".
|
|
||||||
std::string libName = path.substr(path.find('/')+1);
|
|
||||||
libName = libName.substr(0, libName.find('/'));
|
|
||||||
std::transform(libName.begin(), libName.end(),libName.begin(), ::toupper);
|
|
||||||
return libName;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void makeExtObj(std::ostream &fout, const std::vector<std::string> &externalfiles)
|
|
||||||
{
|
|
||||||
bool start = true;
|
|
||||||
std::ostringstream libNames;
|
|
||||||
std::string libName;
|
|
||||||
for (std::size_t i = 0; i < externalfiles.size(); ++i) {
|
|
||||||
if (start) {
|
|
||||||
libName = getLibName(externalfiles[i]);
|
|
||||||
fout << "ifndef " << libName << "\n";
|
|
||||||
fout << " " << libName << " = " << objfile(externalfiles[i]);
|
|
||||||
libNames << "EXTOBJ += $(" << libName << ")\n";
|
|
||||||
start = false;
|
|
||||||
} else {
|
|
||||||
fout << std::string(14, ' ') << objfile(externalfiles[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i+1 >= externalfiles.size() || libName != getLibName(externalfiles[i+1])) {
|
|
||||||
// This was the last file for this library
|
|
||||||
fout << "\nendif\n\n\n";
|
|
||||||
start = true;
|
|
||||||
} else {
|
|
||||||
// There are more files for this library
|
|
||||||
fout << " \\\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fout << libNames.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const bool release(argc >= 2 && std::string(argv[1]) == "--release");
|
const bool release(argc >= 2 && std::string(argv[1]) == "--release");
|
||||||
|
@ -159,6 +120,10 @@ int main(int argc, char **argv)
|
||||||
std::vector<std::string> libfiles;
|
std::vector<std::string> libfiles;
|
||||||
getCppFiles(libfiles, "lib/", false);
|
getCppFiles(libfiles, "lib/", false);
|
||||||
|
|
||||||
|
std::vector<std::string> extfiles;
|
||||||
|
extfiles.push_back("externals/simplecpp/simplecpp.cpp");
|
||||||
|
extfiles.push_back("externals/tinyxml/tinyxml2.cpp");
|
||||||
|
|
||||||
std::vector<std::string> clifiles;
|
std::vector<std::string> clifiles;
|
||||||
getCppFiles(clifiles, "cli/", false);
|
getCppFiles(clifiles, "cli/", false);
|
||||||
|
|
||||||
|
@ -173,18 +138,14 @@ int main(int argc, char **argv)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> externalfiles;
|
|
||||||
getCppFiles(externalfiles, "externals/", true);
|
|
||||||
|
|
||||||
|
|
||||||
// QMAKE - lib/lib.pri
|
// QMAKE - lib/lib.pri
|
||||||
{
|
{
|
||||||
std::ofstream fout1("lib/lib.pri");
|
std::ofstream fout1("lib/lib.pri");
|
||||||
if (fout1.is_open()) {
|
if (fout1.is_open()) {
|
||||||
fout1 << "# no manual edits - this file is autogenerated by dmake\n\n";
|
fout1 << "# no manual edits - this file is autogenerated by dmake\n\n";
|
||||||
fout1 << "include($$PWD/pcrerules.pri)\n";
|
fout1 << "include($$PWD/pcrerules.pri)\n";
|
||||||
fout1 << "include($$PWD/../externals/tinyxml/tinyxml.pri)\n";
|
fout1 << "include($$PWD/../externals/externals.pri)\n";
|
||||||
fout1 << "INCLUDEPATH += $$PWD $$PWD/../externals/tinyxml\n";
|
fout1 << "INCLUDEPATH += $$PWD\n";
|
||||||
fout1 << "HEADERS += $${PWD}/check.h \\\n";
|
fout1 << "HEADERS += $${PWD}/check.h \\\n";
|
||||||
for (unsigned int i = 0; i < libfiles.size(); ++i) {
|
for (unsigned int i = 0; i < libfiles.size(); ++i) {
|
||||||
std::string fname(libfiles[i].substr(4));
|
std::string fname(libfiles[i].substr(4));
|
||||||
|
@ -375,9 +336,9 @@ int main(int argc, char **argv)
|
||||||
<< "endif\n\n";
|
<< "endif\n\n";
|
||||||
|
|
||||||
makeConditionalVariable(fout, "PREFIX", "/usr");
|
makeConditionalVariable(fout, "PREFIX", "/usr");
|
||||||
makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals/tinyxml");
|
makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals/simplecpp -Iexternals/tinyxml");
|
||||||
makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals/tinyxml");
|
makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals/simplecpp -Iexternals/tinyxml");
|
||||||
makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals/tinyxml");
|
makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals/simplecpp -Iexternals/tinyxml");
|
||||||
|
|
||||||
fout << "BIN=$(DESTDIR)$(PREFIX)/bin\n\n";
|
fout << "BIN=$(DESTDIR)$(PREFIX)/bin\n\n";
|
||||||
fout << "# For 'make man': sudo apt-get install xsltproc docbook-xsl docbook-xml on Linux\n";
|
fout << "# For 'make man': sudo apt-get install xsltproc docbook-xsl docbook-xml on Linux\n";
|
||||||
|
@ -390,6 +351,10 @@ int main(int argc, char **argv)
|
||||||
for (size_t i = 1; i < libfiles.size(); ++i)
|
for (size_t i = 1; i < libfiles.size(); ++i)
|
||||||
fout << " \\\n" << std::string(14, ' ') << objfile(libfiles[i]);
|
fout << " \\\n" << std::string(14, ' ') << objfile(libfiles[i]);
|
||||||
fout << "\n\n";
|
fout << "\n\n";
|
||||||
|
fout << "EXTOBJ = " << objfile(extfiles[0]);
|
||||||
|
for (size_t i = 1; i < extfiles.size(); ++i)
|
||||||
|
fout << " \\\n" << std::string(14, ' ') << objfile(extfiles[i]);
|
||||||
|
fout << "\n\n";
|
||||||
fout << "CLIOBJ = " << objfile(clifiles[0]);
|
fout << "CLIOBJ = " << objfile(clifiles[0]);
|
||||||
for (size_t i = 1; i < clifiles.size(); ++i)
|
for (size_t i = 1; i < clifiles.size(); ++i)
|
||||||
fout << " \\\n" << std::string(14, ' ') << objfile(clifiles[i]);
|
fout << " \\\n" << std::string(14, ' ') << objfile(clifiles[i]);
|
||||||
|
@ -399,8 +364,6 @@ int main(int argc, char **argv)
|
||||||
fout << " \\\n" << std::string(14, ' ') << objfile(testfiles[i]);
|
fout << " \\\n" << std::string(14, ' ') << objfile(testfiles[i]);
|
||||||
fout << "\n\n";
|
fout << "\n\n";
|
||||||
|
|
||||||
makeExtObj(fout, externalfiles);
|
|
||||||
|
|
||||||
fout << ".PHONY: run-dmake\n\n";
|
fout << ".PHONY: run-dmake\n\n";
|
||||||
fout << "\n###### Targets\n\n";
|
fout << "\n###### Targets\n\n";
|
||||||
fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n";
|
fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n";
|
||||||
|
@ -418,10 +381,10 @@ int main(int argc, char **argv)
|
||||||
fout << "\t$(CXX) $(CXXFLAGS) -o dmake tools/dmake.o cli/filelister.o cli/pathmatch.o lib/path.o -Ilib $(LDFLAGS)\n\n";
|
fout << "\t$(CXX) $(CXXFLAGS) -o dmake tools/dmake.o cli/filelister.o cli/pathmatch.o lib/path.o -Ilib $(LDFLAGS)\n\n";
|
||||||
fout << "run-dmake: dmake\n";
|
fout << "run-dmake: dmake\n";
|
||||||
fout << "\t./dmake\n\n";
|
fout << "\t./dmake\n\n";
|
||||||
fout << "reduce:\ttools/reduce.o externals/tinyxml/tinyxml2.o $(LIBOBJ)\n";
|
fout << "reduce:\ttools/reduce.o $(LIBOBJ) $(EXTOBJ)\n";
|
||||||
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o reduce tools/reduce.o -Ilib -Iexternals/tinyxml $(LIBOBJ) $(LIBS) externals/tinyxml/tinyxml2.o $(LDFLAGS) $(RDYNAMIC)\n\n";
|
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o reduce tools/reduce.o $(INCLUDE_FOR_LIB) $(LIBOBJ) $(LIBS) $(EXTOBJ) $(LDFLAGS) $(RDYNAMIC)\n\n";
|
||||||
fout << "clean:\n";
|
fout << "clean:\n";
|
||||||
fout << "\trm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/tinyxml/*.o testrunner reduce dmake cppcheck cppcheck.1\n\n";
|
fout << "\trm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner reduce dmake cppcheck cppcheck.1\n\n";
|
||||||
fout << "man:\tman/cppcheck.1\n\n";
|
fout << "man:\tman/cppcheck.1\n\n";
|
||||||
fout << "man/cppcheck.1:\t$(MAN_SOURCE)\n\n";
|
fout << "man/cppcheck.1:\t$(MAN_SOURCE)\n\n";
|
||||||
fout << "\t$(XP) $(DB2MAN) $(MAN_SOURCE)\n\n";
|
fout << "\t$(XP) $(DB2MAN) $(MAN_SOURCE)\n\n";
|
||||||
|
@ -443,7 +406,7 @@ int main(int argc, char **argv)
|
||||||
compilefiles(fout, libfiles, "${INCLUDE_FOR_LIB}");
|
compilefiles(fout, libfiles, "${INCLUDE_FOR_LIB}");
|
||||||
compilefiles(fout, clifiles, "${INCLUDE_FOR_CLI}");
|
compilefiles(fout, clifiles, "${INCLUDE_FOR_CLI}");
|
||||||
compilefiles(fout, testfiles, "${INCLUDE_FOR_TEST}");
|
compilefiles(fout, testfiles, "${INCLUDE_FOR_TEST}");
|
||||||
compilefiles(fout, externalfiles, "${INCLUDE_FOR_LIB}");
|
compilefiles(fout, extfiles, "");
|
||||||
compilefiles(fout, toolsfiles, "${INCLUDE_FOR_LIB}");
|
compilefiles(fout, toolsfiles, "${INCLUDE_FOR_LIB}");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue