Merge simplecpp branch
This commit is contained in:
parent
a68da1a725
commit
03d2829fb9
28
Makefile
28
Makefile
|
@ -107,15 +107,15 @@ ifndef PREFIX
|
|||
endif
|
||||
|
||||
ifndef INCLUDE_FOR_LIB
|
||||
INCLUDE_FOR_LIB=-Ilib -Iexternals/tinyxml
|
||||
INCLUDE_FOR_LIB=-Ilib -Iexternals/simplecpp -Iexternals/tinyxml
|
||||
endif
|
||||
|
||||
ifndef INCLUDE_FOR_CLI
|
||||
INCLUDE_FOR_CLI=-Ilib -Iexternals/tinyxml
|
||||
INCLUDE_FOR_CLI=-Ilib -Iexternals/simplecpp -Iexternals/tinyxml
|
||||
endif
|
||||
|
||||
ifndef INCLUDE_FOR_TEST
|
||||
INCLUDE_FOR_TEST=-Ilib -Icli -Iexternals/tinyxml
|
||||
INCLUDE_FOR_TEST=-Ilib -Icli -Iexternals/simplecpp -Iexternals/tinyxml
|
||||
endif
|
||||
|
||||
BIN=$(DESTDIR)$(PREFIX)/bin
|
||||
|
@ -171,6 +171,9 @@ LIBOBJ = $(SRCDIR)/astutils.o \
|
|||
$(SRCDIR)/tokenlist.o \
|
||||
$(SRCDIR)/valueflow.o
|
||||
|
||||
EXTOBJ = externals/simplecpp/simplecpp.o \
|
||||
externals/tinyxml/tinyxml2.o
|
||||
|
||||
CLIOBJ = cli/cmdlineparser.o \
|
||||
cli/cppcheckexecutor.o \
|
||||
cli/filelister.o \
|
||||
|
@ -236,12 +239,6 @@ TESTOBJ = test/options.o \
|
|||
test/testvalueflow.o \
|
||||
test/testvarid.o
|
||||
|
||||
ifndef TINYXML
|
||||
TINYXML = externals/tinyxml/tinyxml2.o
|
||||
endif
|
||||
|
||||
|
||||
EXTOBJ += $(TINYXML)
|
||||
.PHONY: run-dmake
|
||||
|
||||
|
||||
|
@ -270,11 +267,11 @@ dmake: tools/dmake.o cli/filelister.o cli/pathmatch.o lib/path.o
|
|||
run-dmake: dmake
|
||||
./dmake
|
||||
|
||||
reduce: tools/reduce.o externals/tinyxml/tinyxml2.o $(LIBOBJ)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o reduce tools/reduce.o -Ilib -Iexternals/tinyxml $(LIBOBJ) $(LIBS) externals/tinyxml/tinyxml2.o $(LDFLAGS) $(RDYNAMIC)
|
||||
reduce: tools/reduce.o $(LIBOBJ) $(EXTOBJ)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o reduce tools/reduce.o $(INCLUDE_FOR_LIB) $(LIBOBJ) $(LIBS) $(EXTOBJ) $(LDFLAGS) $(RDYNAMIC)
|
||||
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
$(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
|
||||
|
||||
$(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
|
||||
$(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
|
||||
$(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
|
||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o tools/dmake.o tools/dmake.cpp
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\lib;..\externals;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\lib;..\externals\simplecpp;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<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 CWE398(398U); // Indicator of Poor Code Quality
|
||||
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 CWE563(563U); // Assignment to Variable without Use ('Unused Variable')
|
||||
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()
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -88,7 +88,6 @@ public:
|
|||
checkOther.checkMisusedScopedObject();
|
||||
checkOther.checkMemsetZeroBytes();
|
||||
checkOther.checkMemsetInvalid2ndParam();
|
||||
checkOther.checkSwitchCaseFallThrough();
|
||||
checkOther.checkPipeParameterSize();
|
||||
|
||||
checkOther.checkInvalidFree();
|
||||
|
@ -143,9 +142,6 @@ public:
|
|||
/** @brief %Check for code like 'case A||B:'*/
|
||||
void checkSuspiciousEqualityComparison();
|
||||
|
||||
/** @brief %Check for switch case fall through without comment */
|
||||
void checkSwitchCaseFallThrough();
|
||||
|
||||
/** @brief %Check for objects that are destroyed immediately */
|
||||
void checkMisusedScopedObject();
|
||||
|
||||
|
@ -230,7 +226,6 @@ private:
|
|||
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 redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
|
||||
void switchCaseFallThrough(const Token *tok);
|
||||
void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString);
|
||||
void suspiciousEqualityComparisonError(const Token* tok);
|
||||
void selfAssignmentError(const Token *tok, const std::string &varname);
|
||||
|
@ -287,7 +282,6 @@ private:
|
|||
c.variableScopeError(nullptr, "varname");
|
||||
c.redundantAssignmentInSwitchError(nullptr, 0, "var");
|
||||
c.redundantCopyInSwitchError(nullptr, 0, "var");
|
||||
c.switchCaseFallThrough(nullptr);
|
||||
c.suspiciousCaseInSwitchError(nullptr, "||");
|
||||
c.suspiciousEqualityComparisonError(nullptr);
|
||||
c.selfAssignmentError(nullptr, "varname");
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "cppcheck.h"
|
||||
|
||||
#include "preprocessor.h" // Preprocessor
|
||||
#include "simplecpp.h"
|
||||
#include "tokenize.h" // Tokenizer
|
||||
|
||||
#include "check.h"
|
||||
|
@ -99,43 +100,62 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
|||
bool internalErrorFound(false);
|
||||
try {
|
||||
Preprocessor preprocessor(_settings, this);
|
||||
std::list<std::string> configurations;
|
||||
std::string filedata;
|
||||
std::set<std::string> configurations;
|
||||
|
||||
{
|
||||
Timer t("Preprocessor::preprocess", _settings.showtime, &S_timerResults);
|
||||
preprocessor.preprocess(fileStream, filedata, configurations, filename, _settings.includePaths);
|
||||
simplecpp::OutputList outputList;
|
||||
std::vector<std::string> files;
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Run define rules on raw code
|
||||
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
|
||||
if (it->tokenlist == "define") {
|
||||
Tokenizer tokenizer2(&_settings, this);
|
||||
std::istringstream istr2(filedata);
|
||||
tokenizer2.list.createTokens(istr2, filename);
|
||||
if (it->tokenlist != "define")
|
||||
continue;
|
||||
|
||||
for (const Token *tok = tokenizer2.list.front(); tok; tok = tok->next()) {
|
||||
if (tok->str() == "#define") {
|
||||
std::string code = std::string(tok->linenr()-1U, '\n');
|
||||
for (const Token *tok2 = tok; tok2 && tok2->linenr() == tok->linenr(); tok2 = tok2->next())
|
||||
code += " " + tok2->str();
|
||||
Tokenizer tokenizer3(&_settings, this);
|
||||
std::istringstream istr3(code);
|
||||
tokenizer3.list.createTokens(istr3, tokenizer2.list.file(tok));
|
||||
executeRules("define", tokenizer3);
|
||||
}
|
||||
for (const simplecpp::Token *tok = tokens1.cbegin(); tok; tok = tok->next) {
|
||||
if (tok->op != '#')
|
||||
continue;
|
||||
if (tok->previous && tok->previous->location.sameline(tok->location))
|
||||
continue;
|
||||
|
||||
std::string directive;
|
||||
for (const simplecpp::Token *tok2 = tok; tok2 && tok->location.sameline(tok2->location); tok2 = tok2->next) {
|
||||
if (tok2->comment)
|
||||
continue;
|
||||
while (directive.size() < tok2->location.col)
|
||||
directive += ' ';
|
||||
directive += tok2->str;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_settings.userDefines.empty() && _settings.maxConfigs==1U) {
|
||||
configurations.clear();
|
||||
configurations.push_back(_settings.userDefines);
|
||||
if (directive.compare(0,8,"#define ") != 0)
|
||||
continue;
|
||||
|
||||
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) {
|
||||
|
@ -159,7 +179,7 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
|||
|
||||
std::set<unsigned long long> checksums;
|
||||
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
|
||||
if (_settings.terminated())
|
||||
break;
|
||||
|
@ -184,10 +204,11 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
|||
cfg = _settings.userDefines + cfg;
|
||||
}
|
||||
|
||||
Timer t("Preprocessor::getcode", _settings.showtime, &S_timerResults);
|
||||
std::string codeWithoutCfg = preprocessor.getcode(filedata, cfg, filename);
|
||||
t.Stop();
|
||||
|
||||
std::string codeWithoutCfg;
|
||||
{
|
||||
Timer t("Preprocessor::getcode", _settings.showtime, &S_timerResults);
|
||||
codeWithoutCfg = preprocessor.getcode(tokens1, cfg, files, true);
|
||||
}
|
||||
codeWithoutCfg += _settings.append();
|
||||
|
||||
if (_settings.preprocessOnly) {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp" />
|
||||
<ClCompile Include="..\externals\tinyxml\tinyxml2.cpp" />
|
||||
<ClCompile Include="astutils.cpp" />
|
||||
<ClCompile Include="check.cpp">
|
||||
|
@ -264,7 +265,7 @@
|
|||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>CPPCHECKLIB_EXPORT;TINYXML2_EXPORT;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalIncludeDirectories>..\externals;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\externals\simplecpp;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4251;4482;4512</DisableSpecificWarnings>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
|
|
|
@ -140,6 +140,9 @@
|
|||
<ClCompile Include="checkfunctions.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="checkbufferoverrun.h">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# no manual edits - this file is autogenerated by dmake
|
||||
|
||||
include($$PWD/pcrerules.pri)
|
||||
include($$PWD/../externals/tinyxml/tinyxml.pri)
|
||||
INCLUDEPATH += $$PWD $$PWD/../externals/tinyxml
|
||||
include($$PWD/../externals/externals.pri)
|
||||
INCLUDEPATH += $$PWD
|
||||
HEADERS += $${PWD}/check.h \
|
||||
$${PWD}/astutils.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
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "config.h"
|
||||
#include "simplecpp.h"
|
||||
|
||||
#include <map>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include "config.h"
|
||||
|
||||
class ErrorLogger;
|
||||
class Settings;
|
||||
|
@ -79,10 +81,17 @@ public:
|
|||
static char macroChar;
|
||||
|
||||
Preprocessor(Settings& settings, ErrorLogger *errorLogger = nullptr);
|
||||
virtual ~Preprocessor();
|
||||
|
||||
static bool missingIncludeFlag;
|
||||
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
|
||||
* @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);
|
||||
|
||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||
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);
|
||||
std::string getcode(const simplecpp::TokenList &tokens1, const std::string &cfg, std::vector<std::string> &files, const bool writeLocations);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param processedFile The data to be processed
|
||||
|
@ -155,8 +149,6 @@ public:
|
|||
bool validateCfg(const std::string &code, const std::string &cfg);
|
||||
void validateCfgError(const std::string &cfg, const std::string ¯o);
|
||||
|
||||
void handleUndef(std::list<std::string> &configurations) const;
|
||||
|
||||
/**
|
||||
* report error
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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().
|
||||
* @param str Code processed by read().
|
||||
|
@ -236,40 +195,9 @@ private:
|
|||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
file0 = f;
|
||||
}
|
||||
|
@ -284,25 +212,14 @@ private:
|
|||
|
||||
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;
|
||||
ErrorLogger *_errorLogger;
|
||||
|
||||
/** list of all directives met while preprocessing file */
|
||||
std::list<Directive> directives;
|
||||
|
||||
std::map<std::string, simplecpp::TokenList *> tokenlists;
|
||||
|
||||
/** filename for cpp/c file - useful when reporting errors */
|
||||
std::string file0;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
int main()
|
||||
{
|
||||
#ifndef A
|
||||
#ifdef A
|
||||
}
|
||||
#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
|
||||
strcasestr("test", NULL);
|
||||
|
||||
//
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
// cppcheck-suppress duplicateExpression
|
||||
if (42 == __builtin_expect(42, 0))
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,6 @@ private:
|
|||
TEST_CASE(switchRedundantAssignmentTest);
|
||||
TEST_CASE(switchRedundantOperationTest);
|
||||
TEST_CASE(switchRedundantBitwiseOperationTest);
|
||||
TEST_CASE(switchFallThroughCase);
|
||||
TEST_CASE(unreachableCode);
|
||||
|
||||
TEST_CASE(suspiciousCase);
|
||||
|
@ -221,41 +220,6 @@ private:
|
|||
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() {
|
||||
check("{\n"
|
||||
"}");
|
||||
|
@ -2163,307 +2127,6 @@ private:
|
|||
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() {
|
||||
check("void foo(int a) {\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\pathmatch.cpp" />
|
||||
<ClCompile Include="..\cli\threadexecutor.cpp" />
|
||||
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp" />
|
||||
<ClCompile Include="options.cpp" />
|
||||
<ClCompile Include="test64bit.cpp" />
|
||||
<ClCompile Include="testassert.cpp" />
|
||||
|
@ -168,7 +169,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\cli;..\lib;..\externals;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\cli;..\lib;..\externals\simplecpp;..\externals\tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>Disabled</Optimization>
|
||||
|
|
|
@ -202,6 +202,9 @@
|
|||
<ClCompile Include="testfunctions.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="options.h">
|
||||
|
|
|
@ -112,45 +112,6 @@ static void makeConditionalVariable(std::ostream &os, const std::string &variabl
|
|||
<< "\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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
getCppFiles(clifiles, "cli/", false);
|
||||
|
||||
|
@ -173,18 +138,14 @@ int main(int argc, char **argv)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::vector<std::string> externalfiles;
|
||||
getCppFiles(externalfiles, "externals/", true);
|
||||
|
||||
|
||||
// QMAKE - lib/lib.pri
|
||||
{
|
||||
std::ofstream fout1("lib/lib.pri");
|
||||
if (fout1.is_open()) {
|
||||
fout1 << "# no manual edits - this file is autogenerated by dmake\n\n";
|
||||
fout1 << "include($$PWD/pcrerules.pri)\n";
|
||||
fout1 << "include($$PWD/../externals/tinyxml/tinyxml.pri)\n";
|
||||
fout1 << "INCLUDEPATH += $$PWD $$PWD/../externals/tinyxml\n";
|
||||
fout1 << "include($$PWD/../externals/externals.pri)\n";
|
||||
fout1 << "INCLUDEPATH += $$PWD\n";
|
||||
fout1 << "HEADERS += $${PWD}/check.h \\\n";
|
||||
for (unsigned int i = 0; i < libfiles.size(); ++i) {
|
||||
std::string fname(libfiles[i].substr(4));
|
||||
|
@ -375,9 +336,9 @@ int main(int argc, char **argv)
|
|||
<< "endif\n\n";
|
||||
|
||||
makeConditionalVariable(fout, "PREFIX", "/usr");
|
||||
makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals/tinyxml");
|
||||
makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals/tinyxml");
|
||||
makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals/tinyxml");
|
||||
makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals/simplecpp -Iexternals/tinyxml");
|
||||
makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals/simplecpp -Iexternals/tinyxml");
|
||||
makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals/simplecpp -Iexternals/tinyxml");
|
||||
|
||||
fout << "BIN=$(DESTDIR)$(PREFIX)/bin\n\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)
|
||||
fout << " \\\n" << std::string(14, ' ') << objfile(libfiles[i]);
|
||||
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]);
|
||||
for (size_t i = 1; i < clifiles.size(); ++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\n";
|
||||
|
||||
makeExtObj(fout, externalfiles);
|
||||
|
||||
fout << ".PHONY: run-dmake\n\n";
|
||||
fout << "\n###### Targets\n\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 << "run-dmake: dmake\n";
|
||||
fout << "\t./dmake\n\n";
|
||||
fout << "reduce:\ttools/reduce.o externals/tinyxml/tinyxml2.o $(LIBOBJ)\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 << "reduce:\ttools/reduce.o $(LIBOBJ) $(EXTOBJ)\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 << "\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/cppcheck.1:\t$(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, clifiles, "${INCLUDE_FOR_CLI}");
|
||||
compilefiles(fout, testfiles, "${INCLUDE_FOR_TEST}");
|
||||
compilefiles(fout, externalfiles, "${INCLUDE_FOR_LIB}");
|
||||
compilefiles(fout, extfiles, "");
|
||||
compilefiles(fout, toolsfiles, "${INCLUDE_FOR_LIB}");
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue