Merge branch 'master' into project
This commit is contained in:
commit
f0727f2148
3
AUTHORS
3
AUTHORS
|
@ -22,6 +22,7 @@ Armin Müller
|
||||||
Arpit Chaudhary
|
Arpit Chaudhary
|
||||||
August Sodora
|
August Sodora
|
||||||
Baris Demiray
|
Baris Demiray
|
||||||
|
Bartlomiej Grzeskowiak
|
||||||
Benjamin Bannier
|
Benjamin Bannier
|
||||||
Benjamin Goose
|
Benjamin Goose
|
||||||
Benjamin Kramer
|
Benjamin Kramer
|
||||||
|
@ -112,6 +113,7 @@ Massimo Paladin
|
||||||
Mateusz Pusz
|
Mateusz Pusz
|
||||||
Mathias De Maré
|
Mathias De Maré
|
||||||
Matthias Krüger
|
Matthias Krüger
|
||||||
|
Mavik
|
||||||
Miika-Petteri Matikainen
|
Miika-Petteri Matikainen
|
||||||
Mika Attila
|
Mika Attila
|
||||||
Mohit Mate
|
Mohit Mate
|
||||||
|
@ -170,6 +172,7 @@ Tobias Weibel
|
||||||
Toralf Förster
|
Toralf Förster
|
||||||
Troshin V.S.
|
Troshin V.S.
|
||||||
Valerii Lashmanov
|
Valerii Lashmanov
|
||||||
|
Vasily Maslyukov
|
||||||
WenChung Chiu
|
WenChung Chiu
|
||||||
Vesa Pikki
|
Vesa Pikki
|
||||||
Ville Skyttä
|
Ville Skyttä
|
||||||
|
|
|
@ -17,6 +17,7 @@ if (BUILD_TESTS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(externals/tinyxml)
|
add_subdirectory(externals/tinyxml)
|
||||||
|
add_subdirectory(externals/simplecpp)
|
||||||
add_subdirectory(lib) # CppCheck Library
|
add_subdirectory(lib) # CppCheck Library
|
||||||
add_subdirectory(cli) # Client application
|
add_subdirectory(cli) # Client application
|
||||||
add_subdirectory(test) # Tests
|
add_subdirectory(test) # Tests
|
||||||
|
|
31
cfg/std.cfg
31
cfg/std.cfg
|
@ -983,9 +983,7 @@
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="3"/>
|
<arg nr="3"/>
|
||||||
|
@ -998,9 +996,7 @@
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="3"/>
|
<arg nr="3"/>
|
||||||
|
@ -1149,9 +1145,7 @@
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr scan="true"/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="3"/>
|
<arg nr="3"/>
|
||||||
|
@ -1163,10 +1157,11 @@
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr scan="true"/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
<not-null/>
|
||||||
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
<arg nr="3"/>
|
||||||
</function>
|
</function>
|
||||||
<!-- int fseek(FILE* stream, long int offset, int origin); -->
|
<!-- int fseek(FILE* stream, long int offset, int origin); -->
|
||||||
<function name="fseek,std::fseek">
|
<function name="fseek,std::fseek">
|
||||||
|
@ -2586,9 +2581,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<function name="vprintf,std::vprintf">
|
<function name="vprintf,std::vprintf">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<leak-ignore/>
|
<leak-ignore/>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
<formatstr/>
|
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2"/>
|
<arg nr="2"/>
|
||||||
|
@ -2597,9 +2590,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<function name="vwprintf,std::vwprintf">
|
<function name="vwprintf,std::vwprintf">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<leak-ignore/>
|
<leak-ignore/>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
<formatstr/>
|
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2"/>
|
<arg nr="2"/>
|
||||||
|
@ -2821,9 +2812,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr scan="true"/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
@ -2837,9 +2826,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr scan="true"/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
@ -2849,9 +2836,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<function name="vscanf,std::vscanf">
|
<function name="vscanf,std::vscanf">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<leak-ignore/>
|
<leak-ignore/>
|
||||||
<formatstr scan="true"/>
|
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
@ -2861,9 +2846,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<function name="vwscanf,std::vwscanf">
|
<function name="vwscanf,std::vwscanf">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<leak-ignore/>
|
<leak-ignore/>
|
||||||
<formatstr scan="true"/>
|
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2"/>
|
<arg nr="2"/>
|
||||||
|
@ -3726,9 +3709,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<function name="vsprintf,std::vsprintf">
|
<function name="vsprintf,std::vsprintf">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<leak-ignore/>
|
<leak-ignore/>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
@ -3745,9 +3726,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="3">
|
<arg nr="3">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
@ -3796,9 +3775,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<formatstr/>
|
|
||||||
<arg nr="3">
|
<arg nr="3">
|
||||||
<formatstr/>
|
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
|
@ -4110,6 +4087,8 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<function name="count" action="find"/>
|
<function name="count" action="find"/>
|
||||||
<function name="find" action="find" yields="iterator"/>
|
<function name="find" action="find" yields="iterator"/>
|
||||||
<function name="emplace_hint" action="push"/>
|
<function name="emplace_hint" action="push"/>
|
||||||
|
<function name="try_emplace" action="push"/>
|
||||||
|
<function name="insert_or_assign" action="push"/>
|
||||||
<function name="rehash" action="change-internal"/>
|
<function name="rehash" action="change-internal"/>
|
||||||
<function name="lower_bound" yields="iterator"/>
|
<function name="lower_bound" yields="iterator"/>
|
||||||
<function name="upper_bound" yields="iterator"/>
|
<function name="upper_bound" yields="iterator"/>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/lib/)
|
include_directories(${PROJECT_SOURCE_DIR}/lib/)
|
||||||
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml/)
|
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml/)
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/externals/simplecpp/)
|
||||||
|
|
||||||
file(GLOB hdrs "*.h")
|
file(GLOB hdrs "*.h")
|
||||||
file(GLOB srcs "*.cpp")
|
file(GLOB srcs "*.cpp")
|
||||||
|
@ -7,7 +8,7 @@ file(GLOB mainfile "main.cpp")
|
||||||
list(REMOVE_ITEM srcs ${mainfile})
|
list(REMOVE_ITEM srcs ${mainfile})
|
||||||
|
|
||||||
add_library(cli_objs OBJECT ${hdrs} ${srcs})
|
add_library(cli_objs OBJECT ${hdrs} ${srcs})
|
||||||
add_executable(cppcheck ${hdrs} ${mainfile} $<TARGET_OBJECTS:cli_objs> $<TARGET_OBJECTS:lib_objs> $<TARGET_OBJECTS:tinyxml_objs>)
|
add_executable(cppcheck ${hdrs} ${mainfile} $<TARGET_OBJECTS:cli_objs> $<TARGET_OBJECTS:lib_objs> $<TARGET_OBJECTS:tinyxml_objs> $<TARGET_OBJECTS:simplecpp_objs>)
|
||||||
if (HAVE_RULES)
|
if (HAVE_RULES)
|
||||||
target_link_libraries(cppcheck pcre)
|
target_link_libraries(cppcheck pcre)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @mainpage Cppcheck
|
* @mainpage Cppcheck
|
||||||
* @version 1.74.99
|
* @version 1.75
|
||||||
*
|
*
|
||||||
* @section overview_sec Overview
|
* @section overview_sec Overview
|
||||||
* Cppcheck is a simple tool for static analysis of C/C++ code.
|
* Cppcheck is a simple tool for static analysis of C/C++ code.
|
||||||
|
|
|
@ -42,14 +42,6 @@
|
||||||
#
|
#
|
||||||
# Update download link on index.php main page
|
# Update download link on index.php main page
|
||||||
#
|
#
|
||||||
# Generate the manual.pdf, manual.html and version.txt
|
|
||||||
# make
|
|
||||||
# ./cppcheck --version > version.txt
|
|
||||||
# docbook2pdf man/manual.docbook
|
|
||||||
# xsltproc -o manual.html /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl man/manual.docbook
|
|
||||||
#
|
|
||||||
# Upload manual.pdf , manual.html and version.txt...
|
|
||||||
# sftp danielmarjamaki,cppcheck@web.sourceforge.net
|
|
||||||
#
|
#
|
||||||
# write a news
|
# write a news
|
||||||
#
|
#
|
||||||
|
@ -72,4 +64,13 @@ git archive --format=tar --prefix=$releasename/ $tag | gzip > ~/$releasename.tar
|
||||||
git archive --format=tar --prefix=$releasename/ $tag | bzip2 > ~/$releasename.tar.bz2
|
git archive --format=tar --prefix=$releasename/ $tag | bzip2 > ~/$releasename.tar.bz2
|
||||||
git archive --format=zip -9 --prefix=$releasename/ $tag > ~/$releasename.zip
|
git archive --format=zip -9 --prefix=$releasename/ $tag > ~/$releasename.zip
|
||||||
|
|
||||||
scp ../$releasename.* danielmarjamaki,cppcheck@frs.sourceforge.net:/home/frs/project/c/cp/cppcheck/cppcheck/$tag/
|
scp ~/$releasename.* danielmarjamaki,cppcheck@frs.sourceforge.net:/home/frs/project/c/cp/cppcheck/cppcheck/$tag/
|
||||||
|
|
||||||
|
# Generate the manual.pdf, manual.html and version.txt
|
||||||
|
make
|
||||||
|
./cppcheck --version > version.txt
|
||||||
|
scp version.txt danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/
|
||||||
|
docbook2pdf man/manual.docbook
|
||||||
|
scp manual.pdf danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/
|
||||||
|
xsltproc -o manual.html /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl man/manual.docbook
|
||||||
|
scp manual.html danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
file(GLOB hdrs "*.h")
|
||||||
|
file(GLOB srcs "*.cpp")
|
||||||
|
|
||||||
|
add_library(simplecpp_objs OBJECT ${srcs} ${hdrs})
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,10 @@ unsigned long long stringToULL(const std::string &s)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool startsWith(const std::string &str, const std::string &s) {
|
||||||
|
return (str.size() >= s.size() && str.compare(0, s.size(), s) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool endsWith(const std::string &s, const std::string &e) {
|
bool endsWith(const std::string &s, const std::string &e) {
|
||||||
return (s.size() >= e.size() && s.compare(s.size() - e.size(), e.size(), e) == 0);
|
return (s.size() >= e.size() && s.compare(s.size() - e.size(), e.size(), e) == 0);
|
||||||
}
|
}
|
||||||
|
@ -262,17 +266,16 @@ static unsigned char peekChar(std::istream &istr, unsigned int bom) {
|
||||||
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
|
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
|
||||||
// character is non-ASCII character then replace it with 0xff
|
// character is non-ASCII character then replace it with 0xff
|
||||||
if (bom == 0xfeff || bom == 0xfffe) {
|
if (bom == 0xfeff || bom == 0xfffe) {
|
||||||
|
(void)istr.get();
|
||||||
const unsigned char ch2 = (unsigned char)istr.peek();
|
const unsigned char ch2 = (unsigned char)istr.peek();
|
||||||
|
istr.unget();
|
||||||
const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch);
|
const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch);
|
||||||
ch = (unsigned char)((ch16 >= 0x80) ? 0xff : ch16);
|
ch = (unsigned char)((ch16 >= 0x80) ? 0xff : ch16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling of newlines..
|
// Handling of newlines..
|
||||||
if (ch == '\r') {
|
if (ch == '\r')
|
||||||
ch = '\n';
|
ch = '\n';
|
||||||
if (bom != 0)
|
|
||||||
(void)istr.peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
@ -294,11 +297,15 @@ static unsigned short getAndSkipBOM(std::istream &istr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch1 == 0xef && istr.peek() == 0xbb && istr.peek() == 0xbf) {
|
// Skip UTF-8 BOM 0xefbbbf
|
||||||
// Skip BOM 0xefbbbf
|
if (ch1 == 0xef) {
|
||||||
(void)istr.get();
|
istr.get();
|
||||||
(void)istr.get();
|
if (istr.get() == 0xbb && istr.peek() == 0xbf) {
|
||||||
(void)istr.get();
|
(void)istr.get();
|
||||||
|
} else {
|
||||||
|
istr.unget();
|
||||||
|
istr.unget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -335,6 +342,7 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
|
||||||
location.line += multiline + 1;
|
location.line += multiline + 1;
|
||||||
multiline = 0U;
|
multiline = 0U;
|
||||||
}
|
}
|
||||||
|
if (!multiline)
|
||||||
location.col = 1;
|
location.col = 1;
|
||||||
|
|
||||||
if (oldLastToken != cback()) {
|
if (oldLastToken != cback()) {
|
||||||
|
@ -400,11 +408,19 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
|
||||||
ch = readChar(istr,bom);
|
ch = readChar(istr,bom);
|
||||||
}
|
}
|
||||||
// multiline..
|
// multiline..
|
||||||
|
|
||||||
std::string::size_type pos = 0;
|
std::string::size_type pos = 0;
|
||||||
while ((pos = currentToken.find("\\\n",pos)) != std::string::npos) {
|
while ((pos = currentToken.find("\\\n",pos)) != std::string::npos) {
|
||||||
currentToken.erase(pos,2);
|
currentToken.erase(pos,2);
|
||||||
++multiline;
|
++multiline;
|
||||||
}
|
}
|
||||||
|
if (multiline || startsWith(lastLine(10),"# ")) {
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = currentToken.find("\n",pos)) != std::string::npos) {
|
||||||
|
currentToken.erase(pos,1);
|
||||||
|
++multiline;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// string / char literal
|
// string / char literal
|
||||||
|
@ -450,6 +466,10 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
|
||||||
}
|
}
|
||||||
|
|
||||||
push_back(new Token(currentToken, location));
|
push_back(new Token(currentToken, location));
|
||||||
|
|
||||||
|
if (multiline)
|
||||||
|
location.col += currentToken.size();
|
||||||
|
else
|
||||||
location.adjust(currentToken);
|
location.adjust(currentToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,7 +804,7 @@ std::string simplecpp::TokenList::readUntil(std::istream &istr, const Location &
|
||||||
clear();
|
clear();
|
||||||
if (outputList) {
|
if (outputList) {
|
||||||
Output err(files);
|
Output err(files);
|
||||||
err.type = Output::ERROR;
|
err.type = Output::SYNTAX_ERROR;
|
||||||
err.location = location;
|
err.location = location;
|
||||||
err.msg = std::string("No pair for character (") + start + "). Can't process file. File is either invalid or unicode, which is currently not supported.";
|
err.msg = std::string("No pair for character (") + start + "). Can't process file. File is either invalid or unicode, which is currently not supported.";
|
||||||
outputList->push_back(err);
|
outputList->push_back(err);
|
||||||
|
@ -861,13 +881,45 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand macro. This will recursively expand inner macros.
|
||||||
|
* @param output destination tokenlist
|
||||||
|
* @param rawtok macro token
|
||||||
|
* @param macros list of macros
|
||||||
|
* @param files the files
|
||||||
|
* @return token after macro
|
||||||
|
* @throw Can throw wrongNumberOfParameters or invalidHashHash
|
||||||
|
*/
|
||||||
const Token * expand(TokenList * const output,
|
const Token * expand(TokenList * const output,
|
||||||
const Token * rawtok,
|
const Token * rawtok,
|
||||||
const std::map<TokenString,Macro> ¯os,
|
const std::map<TokenString,Macro> ¯os,
|
||||||
std::vector<std::string> &files) const {
|
std::vector<std::string> &files) const {
|
||||||
std::set<TokenString> expandedmacros;
|
std::set<TokenString> expandedmacros;
|
||||||
|
|
||||||
TokenList output2(files);
|
TokenList output2(files);
|
||||||
|
|
||||||
|
if (functionLike() && rawtok->next && rawtok->next->op == '(') {
|
||||||
|
// Copy macro call to a new tokenlist with no linebreaks
|
||||||
|
const Token * const rawtok1 = rawtok;
|
||||||
|
TokenList rawtokens2(files);
|
||||||
|
rawtokens2.push_back(new Token(rawtok->str, rawtok1->location));
|
||||||
|
rawtok = rawtok->next;
|
||||||
|
rawtokens2.push_back(new Token(rawtok->str, rawtok1->location));
|
||||||
|
rawtok = rawtok->next;
|
||||||
|
int par = 1;
|
||||||
|
while (rawtok && par > 0) {
|
||||||
|
if (rawtok->op == '(')
|
||||||
|
++par;
|
||||||
|
else if (rawtok->op == ')')
|
||||||
|
--par;
|
||||||
|
rawtokens2.push_back(new Token(rawtok->str, rawtok1->location));
|
||||||
|
rawtok = rawtok->next;
|
||||||
|
}
|
||||||
|
if (expand(&output2, rawtok1->location, rawtokens2.cfront(), macros, expandedmacros))
|
||||||
|
rawtok = rawtok1->next;
|
||||||
|
} else {
|
||||||
rawtok = expand(&output2, rawtok->location, rawtok, macros, expandedmacros);
|
rawtok = expand(&output2, rawtok->location, rawtok, macros, expandedmacros);
|
||||||
|
}
|
||||||
while (output2.cback() && rawtok) {
|
while (output2.cback() && rawtok) {
|
||||||
unsigned int par = 0;
|
unsigned int par = 0;
|
||||||
Token* macro2tok = output2.back();
|
Token* macro2tok = output2.back();
|
||||||
|
@ -924,18 +976,22 @@ public:
|
||||||
return rawtok;
|
return rawtok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** macro name */
|
||||||
const TokenString &name() const {
|
const TokenString &name() const {
|
||||||
return nameToken->str;
|
return nameToken->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** location for macro definition */
|
||||||
const Location &defineLocation() const {
|
const Location &defineLocation() const {
|
||||||
return nameToken->location;
|
return nameToken->location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** how has this macro been used so far */
|
||||||
const std::list<Location> &usage() const {
|
const std::list<Location> &usage() const {
|
||||||
return usageList;
|
return usageList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** is this a function like macro */
|
||||||
bool functionLike() const {
|
bool functionLike() const {
|
||||||
return nameToken->next &&
|
return nameToken->next &&
|
||||||
nameToken->next->op == '(' &&
|
nameToken->next->op == '(' &&
|
||||||
|
@ -943,36 +999,31 @@ public:
|
||||||
nameToken->next->location.col == nameToken->location.col + nameToken->str.size();
|
nameToken->next->location.col == nameToken->location.col + nameToken->str.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** base class for errors */
|
||||||
struct Error {
|
struct Error {
|
||||||
Error(const Location &loc, const std::string &s) : location(loc), what(s) {}
|
Error(const Location &loc, const std::string &s) : location(loc), what(s) {}
|
||||||
Location location;
|
Location location;
|
||||||
std::string what;
|
std::string what;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Struct that is thrown when macro is expanded with wrong number of parameters */
|
||||||
struct wrongNumberOfParameters : public Error {
|
struct wrongNumberOfParameters : public Error {
|
||||||
wrongNumberOfParameters(const Location &loc, const std::string ¯oName) : Error(loc, "Syntax error. Wrong number of parameters for macro \'" + macroName + "\'.") {}
|
wrongNumberOfParameters(const Location &loc, const std::string ¯oName) : Error(loc, "Wrong number of parameters for macro \'" + macroName + "\'.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Struct that is thrown when there is invalid ## usage */
|
||||||
struct invalidHashHash : public Error {
|
struct invalidHashHash : public Error {
|
||||||
invalidHashHash(const Location &loc, const std::string ¯oName) : Error(loc, "Syntax error. Invalid ## usage when expanding \'" + macroName + "\'.") {}
|
invalidHashHash(const Location &loc, const std::string ¯oName) : Error(loc, "Invalid ## usage when expanding \'" + macroName + "\'.") {}
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
Token *newMacroToken(const TokenString &str, const Location &loc, bool rawCode) const {
|
/** Create new token where Token::macro is set for replaced tokens */
|
||||||
|
Token *newMacroToken(const TokenString &str, const Location &loc, bool replaced) const {
|
||||||
Token *tok = new Token(str,loc);
|
Token *tok = new Token(str,loc);
|
||||||
if (!rawCode)
|
if (replaced)
|
||||||
tok->macro = nameToken->str;
|
tok->macro = nameToken->str;
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMacroName(TokenList *output, Token *token1, const std::set<std::string> &expandedmacros1) const {
|
|
||||||
if (!expandedmacros1.empty())
|
|
||||||
return;
|
|
||||||
for (Token *tok = token1 ? token1->next : output->front(); tok; tok = tok->next) {
|
|
||||||
if (!tok->macro.empty())
|
|
||||||
tok->macro = nameToken->str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseDefine(const Token *nametoken) {
|
void parseDefine(const Token *nametoken) {
|
||||||
nameToken = nametoken;
|
nameToken = nametoken;
|
||||||
variadic = false;
|
variadic = false;
|
||||||
|
@ -1050,7 +1101,6 @@ private:
|
||||||
const Token *appendTokens(TokenList *tokens,
|
const Token *appendTokens(TokenList *tokens,
|
||||||
const Token *lpar,
|
const Token *lpar,
|
||||||
const std::map<TokenString,Macro> ¯os,
|
const std::map<TokenString,Macro> ¯os,
|
||||||
const std::set<TokenString> &expandedmacros1,
|
|
||||||
const std::set<TokenString> &expandedmacros,
|
const std::set<TokenString> &expandedmacros,
|
||||||
const std::vector<const Token*> ¶metertokens) const {
|
const std::vector<const Token*> ¶metertokens) const {
|
||||||
if (!lpar || lpar->op != '(')
|
if (!lpar || lpar->op != '(')
|
||||||
|
@ -1060,14 +1110,11 @@ private:
|
||||||
while (sameline(lpar, tok)) {
|
while (sameline(lpar, tok)) {
|
||||||
if (tok->op == '#' && sameline(tok,tok->next) && tok->next->op == '#' && sameline(tok,tok->next->next)) {
|
if (tok->op == '#' && sameline(tok,tok->next) && tok->next->op == '#' && sameline(tok,tok->next->next)) {
|
||||||
// A##B => AB
|
// A##B => AB
|
||||||
const std::string strB(expandArgStr(tok->next->next, parametertokens));
|
tok = expandHashHash(tokens, tok->location, tok, macros, expandedmacros, parametertokens);
|
||||||
if (variadic && strB.empty() && tok->previous->op == ',')
|
} else if (tok->op == '#' && sameline(tok, tok->next) && tok->next->op != '#') {
|
||||||
tokens->deleteToken(tokens->back());
|
tok = expandHash(tokens, tok->location, tok, macros, expandedmacros, parametertokens);
|
||||||
else
|
|
||||||
tokens->back()->setstr(tokens->back()->str + strB);
|
|
||||||
tok = tok->next->next->next;
|
|
||||||
} else {
|
} else {
|
||||||
if (!expandArg(tokens, tok, tok->location, macros, expandedmacros1, expandedmacros, parametertokens))
|
if (!expandArg(tokens, tok, tok->location, macros, expandedmacros, parametertokens))
|
||||||
tokens->push_back(new Token(*tok));
|
tokens->push_back(new Token(*tok));
|
||||||
if (tok->op == '(')
|
if (tok->op == '(')
|
||||||
++par;
|
++par;
|
||||||
|
@ -1083,7 +1130,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token * expand(TokenList * const output, const Location &loc, const Token * const nameToken, const std::map<TokenString,Macro> ¯os, std::set<TokenString> expandedmacros) const {
|
const Token * expand(TokenList * const output, const Location &loc, const Token * const nameToken, const std::map<TokenString,Macro> ¯os, std::set<TokenString> expandedmacros) const {
|
||||||
const std::set<TokenString> expandedmacros1(expandedmacros);
|
|
||||||
expandedmacros.insert(nameToken->str);
|
expandedmacros.insert(nameToken->str);
|
||||||
|
|
||||||
usageList.push_back(loc);
|
usageList.push_back(loc);
|
||||||
|
@ -1165,10 +1211,10 @@ private:
|
||||||
if (tok->op != '#') {
|
if (tok->op != '#') {
|
||||||
// A##B => AB
|
// A##B => AB
|
||||||
if (tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
|
if (tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
|
||||||
output->push_back(newMacroToken(expandArgStr(tok, parametertokens2), loc, !expandedmacros1.empty()));
|
output->push_back(newMacroToken(expandArgStr(tok, parametertokens2), loc, isReplaced(expandedmacros)));
|
||||||
tok = tok->next;
|
tok = tok->next;
|
||||||
} else {
|
} else {
|
||||||
tok = expandToken(output, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens2);
|
tok = expandToken(output, loc, tok, macros, expandedmacros, parametertokens2);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1180,47 +1226,18 @@ private:
|
||||||
}
|
}
|
||||||
if (tok->op == '#') {
|
if (tok->op == '#') {
|
||||||
// A##B => AB
|
// A##B => AB
|
||||||
Token *A = output->back();
|
tok = expandHashHash(output, loc, tok->previous, macros, expandedmacros, parametertokens2);
|
||||||
if (!A)
|
|
||||||
throw invalidHashHash(tok->location, name());
|
|
||||||
if (!sameline(tok, tok->next))
|
|
||||||
throw invalidHashHash(tok->location, name());
|
|
||||||
|
|
||||||
std::string strAB = A->str + expandArgStr(tok->next, parametertokens2);
|
|
||||||
|
|
||||||
bool removeComma = false;
|
|
||||||
if (variadic && strAB == "," && tok->previous->previous->str == "," && args.size() >= 1U && tok->next->str == args[args.size()-1U])
|
|
||||||
removeComma = true;
|
|
||||||
|
|
||||||
output->deleteToken(A);
|
|
||||||
|
|
||||||
if (!removeComma) {
|
|
||||||
TokenList tokens(files);
|
|
||||||
tokens.push_back(new Token(strAB, tok->location));
|
|
||||||
// TODO: For functionLike macros, push the (...)
|
|
||||||
expandToken(output, loc, tokens.cfront(), macros, expandedmacros1, expandedmacros, parametertokens2);
|
|
||||||
}
|
|
||||||
|
|
||||||
tok = tok->next->next;
|
|
||||||
} else {
|
} else {
|
||||||
// #123 => "123"
|
// #123 => "123"
|
||||||
TokenList tokenListHash(files);
|
tok = expandHash(output, loc, tok->previous, macros, expandedmacros, parametertokens2);
|
||||||
tok = expandToken(&tokenListHash, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens2);
|
|
||||||
std::ostringstream ostr;
|
|
||||||
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next) {
|
|
||||||
for (unsigned int i = 0; i < hashtok->str.size(); i++) {
|
|
||||||
unsigned char c = hashtok->str[i];
|
|
||||||
if (c == '\"' || c == '\\' || c == '\'')
|
|
||||||
ostr << '\\';
|
|
||||||
ostr << c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output->push_back(newMacroToken('\"' + ostr.str() + '\"', loc, expandedmacros1.empty()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!functionLike())
|
if (!functionLike()) {
|
||||||
setMacroName(output, output_end_1, expandedmacros1);
|
for (Token *tok = output_end_1 ? output_end_1->next : output->front(); tok; tok = tok->next) {
|
||||||
|
tok->macro = nameToken->str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!parametertokens1.empty())
|
if (!parametertokens1.empty())
|
||||||
parametertokens1.swap(parametertokens2);
|
parametertokens1.swap(parametertokens2);
|
||||||
|
@ -1228,17 +1245,17 @@ private:
|
||||||
return functionLike() ? parametertokens2.back()->next : nameToken->next;
|
return functionLike() ? parametertokens2.back()->next : nameToken->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString,Macro> ¯os, const std::set<TokenString> &expandedmacros1, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString,Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
// Not name..
|
// Not name..
|
||||||
if (!tok->name) {
|
if (!tok->name) {
|
||||||
output->push_back(newMacroToken(tok->str, loc, false));
|
output->push_back(newMacroToken(tok->str, loc, true));
|
||||||
return tok->next;
|
return tok->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Macro parameter..
|
// Macro parameter..
|
||||||
{
|
{
|
||||||
TokenList temp(files);
|
TokenList temp(files);
|
||||||
if (expandArg(&temp, tok, loc, macros, expandedmacros1, expandedmacros, parametertokens)) {
|
if (expandArg(&temp, tok, loc, macros, expandedmacros, parametertokens)) {
|
||||||
if (!(temp.cback() && temp.cback()->name && tok->next && tok->next->op == '(')) {
|
if (!(temp.cback() && temp.cback()->name && tok->next && tok->next->op == '(')) {
|
||||||
output->takeTokens(temp);
|
output->takeTokens(temp);
|
||||||
return tok->next;
|
return tok->next;
|
||||||
|
@ -1259,7 +1276,7 @@ private:
|
||||||
TokenList temp2(files);
|
TokenList temp2(files);
|
||||||
temp2.push_back(new Token(temp.cback()->str, tok->location));
|
temp2.push_back(new Token(temp.cback()->str, tok->location));
|
||||||
|
|
||||||
const Token *tok2 = appendTokens(&temp2, tok->next, macros, expandedmacros1, expandedmacros, parametertokens);
|
const Token *tok2 = appendTokens(&temp2, tok->next, macros, expandedmacros, parametertokens);
|
||||||
if (!tok2)
|
if (!tok2)
|
||||||
return tok->next;
|
return tok->next;
|
||||||
|
|
||||||
|
@ -1278,21 +1295,21 @@ private:
|
||||||
if (!calledMacro.functionLike())
|
if (!calledMacro.functionLike())
|
||||||
return calledMacro.expand(output, loc, tok, macros, expandedmacros);
|
return calledMacro.expand(output, loc, tok, macros, expandedmacros);
|
||||||
if (!sameline(tok, tok->next) || tok->next->op != '(') {
|
if (!sameline(tok, tok->next) || tok->next->op != '(') {
|
||||||
output->push_back(newMacroToken(tok->str, loc, false));
|
output->push_back(newMacroToken(tok->str, loc, true));
|
||||||
return tok->next;
|
return tok->next;
|
||||||
}
|
}
|
||||||
TokenList tokens(files);
|
TokenList tokens(files);
|
||||||
tokens.push_back(new Token(*tok));
|
tokens.push_back(new Token(*tok));
|
||||||
const Token *tok2 = appendTokens(&tokens, tok->next, macros, expandedmacros1, expandedmacros, parametertokens);
|
const Token *tok2 = appendTokens(&tokens, tok->next, macros, expandedmacros, parametertokens);
|
||||||
if (!tok2) {
|
if (!tok2) {
|
||||||
output->push_back(newMacroToken(tok->str, loc, false));
|
output->push_back(newMacroToken(tok->str, loc, true));
|
||||||
return tok->next;
|
return tok->next;
|
||||||
}
|
}
|
||||||
calledMacro.expand(output, loc, tokens.cfront(), macros, expandedmacros);
|
calledMacro.expand(output, loc, tokens.cfront(), macros, expandedmacros);
|
||||||
return tok2->next;
|
return tok2->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
output->push_back(newMacroToken(tok->str, loc, false));
|
output->push_back(newMacroToken(tok->str, loc, true));
|
||||||
return tok->next;
|
return tok->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,7 +1331,7 @@ private:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expandArg(TokenList *output, const Token *tok, const Location &loc, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros1, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
bool expandArg(TokenList *output, const Token *tok, const Location &loc, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
if (!tok->name)
|
if (!tok->name)
|
||||||
return false;
|
return false;
|
||||||
const unsigned int argnr = getArgNum(tok->str);
|
const unsigned int argnr = getArgNum(tok->str);
|
||||||
|
@ -1324,16 +1341,22 @@ private:
|
||||||
return true;
|
return true;
|
||||||
for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) {
|
for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) {
|
||||||
const std::map<TokenString, Macro>::const_iterator it = macros.find(partok->str);
|
const std::map<TokenString, Macro>::const_iterator it = macros.find(partok->str);
|
||||||
if (it != macros.end() && expandedmacros1.find(partok->str) == expandedmacros1.end())
|
if (it != macros.end() && (partok->str == name() || expandedmacros.find(partok->str) == expandedmacros.end()))
|
||||||
partok = it->second.expand(output, loc, partok, macros, expandedmacros);
|
partok = it->second.expand(output, loc, partok, macros, expandedmacros);
|
||||||
else {
|
else {
|
||||||
output->push_back(newMacroToken(partok->str, loc, expandedmacros1.empty()));
|
output->push_back(newMacroToken(partok->str, loc, isReplaced(expandedmacros)));
|
||||||
partok = partok->next;
|
partok = partok->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get string for token. If token is argument, the expanded string is returned.
|
||||||
|
* @param tok The token
|
||||||
|
* @param parametertokens parameters given when expanding this macro
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
std::string expandArgStr(const Token *tok, const std::vector<const Token *> ¶metertokens) const {
|
std::string expandArgStr(const Token *tok, const std::vector<const Token *> ¶metertokens) const {
|
||||||
TokenList tokens(files);
|
TokenList tokens(files);
|
||||||
if (expandArg(&tokens, tok, parametertokens)) {
|
if (expandArg(&tokens, tok, parametertokens)) {
|
||||||
|
@ -1345,27 +1368,110 @@ private:
|
||||||
return tok->str;
|
return tok->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMacro(Token *tok) const {
|
/**
|
||||||
while (tok) {
|
* Expand #X => "X"
|
||||||
if (!tok->macro.empty())
|
* @param output destination tokenlist
|
||||||
tok->macro = nameToken->str;
|
* @param loc location for expanded token
|
||||||
tok = tok->next;
|
* @param tok The # token
|
||||||
|
* @param macros all macros
|
||||||
|
* @param expandedmacros set with expanded macros, with this macro
|
||||||
|
* @param parametertokens parameters given when expanding this macro
|
||||||
|
* @return token after the X
|
||||||
|
*/
|
||||||
|
const Token *expandHash(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
|
TokenList tokenListHash(files);
|
||||||
|
tok = expandToken(&tokenListHash, loc, tok->next, macros, expandedmacros, parametertokens);
|
||||||
|
std::ostringstream ostr;
|
||||||
|
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next) {
|
||||||
|
for (unsigned int i = 0; i < hashtok->str.size(); i++) {
|
||||||
|
unsigned char c = hashtok->str[i];
|
||||||
|
if (c == '\"' || c == '\\' || c == '\'')
|
||||||
|
ostr << '\\';
|
||||||
|
ostr << c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
output->push_back(newMacroToken('\"' + ostr.str() + '\"', loc, isReplaced(expandedmacros)));
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand A##B => AB
|
||||||
|
* The A should already be expanded. Call this when you reach the first # token
|
||||||
|
* @param output destination tokenlist
|
||||||
|
* @param loc location for expanded token
|
||||||
|
* @param tok first # token
|
||||||
|
* @param macros all macros
|
||||||
|
* @param expandedmacros set with expanded macros, with this macro
|
||||||
|
* @param parametertokens parameters given when expanding this macro
|
||||||
|
* @return token after B
|
||||||
|
*/
|
||||||
|
const Token *expandHashHash(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
|
Token *A = output->back();
|
||||||
|
if (!A)
|
||||||
|
throw invalidHashHash(tok->location, name());
|
||||||
|
if (!sameline(tok, tok->next))
|
||||||
|
throw invalidHashHash(tok->location, name());
|
||||||
|
|
||||||
|
Token *B = tok->next->next;
|
||||||
|
const std::string strAB = A->str + expandArgStr(B, parametertokens);
|
||||||
|
|
||||||
|
bool removeComma = false;
|
||||||
|
if (variadic && strAB == "," && tok->previous->str == "," && args.size() >= 1U && B->str == args[args.size()-1U])
|
||||||
|
removeComma = true;
|
||||||
|
|
||||||
|
output->deleteToken(A);
|
||||||
|
|
||||||
|
if (!removeComma) {
|
||||||
|
TokenList tokens(files);
|
||||||
|
tokens.push_back(new Token(strAB, tok->location));
|
||||||
|
// TODO: For functionLike macros, push the (...)
|
||||||
|
expandToken(output, loc, tokens.cfront(), macros, expandedmacros, parametertokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isReplaced(const std::set<std::string> &expandedmacros) const {
|
||||||
|
// return true if size > 1
|
||||||
|
std::set<std::string>::const_iterator it = expandedmacros.begin();
|
||||||
|
if (it == expandedmacros.end())
|
||||||
|
return false;
|
||||||
|
++it;
|
||||||
|
return (it != expandedmacros.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** name token in definition */
|
||||||
const Token *nameToken;
|
const Token *nameToken;
|
||||||
|
|
||||||
|
/** arguments for macro */
|
||||||
std::vector<TokenString> args;
|
std::vector<TokenString> args;
|
||||||
|
|
||||||
|
/** is macro variadic? */
|
||||||
bool variadic;
|
bool variadic;
|
||||||
|
|
||||||
|
/** first token in replacement string */
|
||||||
const Token *valueToken;
|
const Token *valueToken;
|
||||||
|
|
||||||
|
/** token after replacement string */
|
||||||
const Token *endToken;
|
const Token *endToken;
|
||||||
|
|
||||||
|
/** files */
|
||||||
std::vector<std::string> &files;
|
std::vector<std::string> &files;
|
||||||
|
|
||||||
|
/** this is used for -D where the definition is not seen anywhere in code */
|
||||||
TokenList tokenListDefine;
|
TokenList tokenListDefine;
|
||||||
|
|
||||||
|
/** usage of this macro */
|
||||||
mutable std::list<Location> usageList;
|
mutable std::list<Location> usageList;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace simplecpp {
|
namespace simplecpp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* perform path simplifications for . and ..
|
||||||
|
*/
|
||||||
std::string simplifyPath(std::string path) {
|
std::string simplifyPath(std::string path) {
|
||||||
std::string::size_type pos;
|
std::string::size_type pos;
|
||||||
|
|
||||||
|
@ -1399,6 +1505,7 @@ std::string simplifyPath(std::string path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
/** Evaluate sizeof(type) */
|
||||||
void simplifySizeof(simplecpp::TokenList &expr, const std::map<std::string, std::size_t> &sizeOfType) {
|
void simplifySizeof(simplecpp::TokenList &expr, const std::map<std::string, std::size_t> &sizeOfType) {
|
||||||
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
|
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
|
||||||
if (tok->str != "sizeof")
|
if (tok->str != "sizeof")
|
||||||
|
@ -1551,6 +1658,25 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
|
||||||
|
|
||||||
std::list<const Token *> filelist;
|
std::list<const Token *> filelist;
|
||||||
|
|
||||||
|
// -include files
|
||||||
|
for (std::list<std::string>::const_iterator it = dui.includes.begin(); it != dui.includes.end(); ++it) {
|
||||||
|
if (ret.find(*it) != ret.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::ifstream fin(it->c_str());
|
||||||
|
if (!fin.is_open())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TokenList *tokenlist = new TokenList(fin, fileNumbers, *it, outputList);
|
||||||
|
if (!tokenlist->front()) {
|
||||||
|
delete tokenlist;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[*it] = tokenlist;
|
||||||
|
filelist.push_back(tokenlist->front());
|
||||||
|
}
|
||||||
|
|
||||||
for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : NULL) {
|
for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : NULL) {
|
||||||
if (rawtok == NULL) {
|
if (rawtok == NULL) {
|
||||||
rawtok = filelist.back();
|
rawtok = filelist.back();
|
||||||
|
@ -1646,7 +1772,14 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
|
|
||||||
std::set<std::string> pragmaOnce;
|
std::set<std::string> pragmaOnce;
|
||||||
|
|
||||||
for (const Token *rawtok = rawtokens.cfront(); rawtok || !includetokenstack.empty();) {
|
includetokenstack.push(rawtokens.cfront());
|
||||||
|
for (std::list<std::string>::const_iterator it = dui.includes.begin(); it != dui.includes.end(); ++it) {
|
||||||
|
const std::map<std::string, TokenList*>::const_iterator f = filedata.find(*it);
|
||||||
|
if (f != filedata.end())
|
||||||
|
includetokenstack.push(f->second->cfront());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Token *rawtok = NULL; rawtok || !includetokenstack.empty();) {
|
||||||
if (rawtok == NULL) {
|
if (rawtok == NULL) {
|
||||||
rawtok = includetokenstack.top();
|
rawtok = includetokenstack.top();
|
||||||
includetokenstack.pop();
|
includetokenstack.pop();
|
||||||
|
@ -1783,7 +1916,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
conditionIsTrue = (evaluate(expr, sizeOfType) != 0);
|
conditionIsTrue = (evaluate(expr, sizeOfType) != 0);
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
Output out(rawtok->location.files);
|
Output out(rawtok->location.files);
|
||||||
out.type = Output::ERROR;
|
out.type = Output::SYNTAX_ERROR;
|
||||||
out.location = rawtok->location;
|
out.location = rawtok->location;
|
||||||
out.msg = "failed to evaluate " + std::string(rawtok->str == IF ? "#if" : "#elif") + " condition";
|
out.msg = "failed to evaluate " + std::string(rawtok->str == IF ? "#if" : "#elif") + " condition";
|
||||||
if (outputList)
|
if (outputList)
|
||||||
|
@ -1851,7 +1984,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
rawtok = macro->second.expand(&tokens, rawtok, macros, files);
|
rawtok = macro->second.expand(&tokens, rawtok, macros, files);
|
||||||
} catch (const simplecpp::Macro::Error &err) {
|
} catch (const simplecpp::Macro::Error &err) {
|
||||||
Output out(err.location.files);
|
Output out(err.location.files);
|
||||||
out.type = Output::ERROR;
|
out.type = Output::SYNTAX_ERROR;
|
||||||
out.location = err.location;
|
out.location = err.location;
|
||||||
out.msg = err.what;
|
out.msg = err.what;
|
||||||
if (outputList)
|
if (outputList)
|
||||||
|
|
|
@ -271,6 +271,7 @@ struct SIMPLECPP_LIB DUI {
|
||||||
std::list<std::string> defines;
|
std::list<std::string> defines;
|
||||||
std::set<std::string> undefined;
|
std::set<std::string> undefined;
|
||||||
std::list<std::string> includePaths;
|
std::list<std::string> includePaths;
|
||||||
|
std::list<std::string> includes;
|
||||||
};
|
};
|
||||||
|
|
||||||
SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = 0);
|
SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = 0);
|
||||||
|
|
|
@ -21,7 +21,7 @@ if (BUILD_GUI)
|
||||||
QT4_ADD_RESOURCES(resources "gui.qrc")
|
QT4_ADD_RESOURCES(resources "gui.qrc")
|
||||||
QT4_ADD_TRANSLATION(qms ${tss})
|
QT4_ADD_TRANSLATION(qms ${tss})
|
||||||
|
|
||||||
add_executable(cppcheck-gui ${hdrs} ${srcs} ${uis_hdrs} ${resources} ${qms} $<TARGET_OBJECTS:lib_objs> $<TARGET_OBJECTS:tinyxml_objs>)
|
add_executable(cppcheck-gui ${hdrs} ${srcs} ${uis_hdrs} ${resources} ${qms} $<TARGET_OBJECTS:lib_objs> $<TARGET_OBJECTS:tinyxml_objs> $<TARGET_OBJECTS:simplecpp_objs>)
|
||||||
target_link_libraries(cppcheck-gui ${QT_LIBRARIES})
|
target_link_libraries(cppcheck-gui ${QT_LIBRARIES})
|
||||||
if (HAVE_RULES)
|
if (HAVE_RULES)
|
||||||
target_link_libraries(cppcheck-gui pcre)
|
target_link_libraries(cppcheck-gui pcre)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml/)
|
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml/)
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/externals/simplecpp/)
|
||||||
|
|
||||||
file(GLOB_RECURSE hdrs "*.h")
|
file(GLOB_RECURSE hdrs "*.h")
|
||||||
file(GLOB_RECURSE srcs "*.cpp")
|
file(GLOB_RECURSE srcs "*.cpp")
|
||||||
|
|
|
@ -168,7 +168,9 @@ void CheckStl::iterators()
|
||||||
// inserting iterator range..
|
// inserting iterator range..
|
||||||
if (tok2->strAt(2) == "insert") {
|
if (tok2->strAt(2) == "insert") {
|
||||||
const Token *par2 = itTok->nextArgument();
|
const Token *par2 = itTok->nextArgument();
|
||||||
while (par2 && par2->str() != ")") {
|
if (!par2 || par2->nextArgument())
|
||||||
|
continue;
|
||||||
|
while (par2->str() != ")") {
|
||||||
if (par2->varId() == container->declarationId())
|
if (par2->varId() == container->declarationId())
|
||||||
break;
|
break;
|
||||||
if (par2->str() == "(")
|
if (par2->str() == "(")
|
||||||
|
|
|
@ -382,14 +382,13 @@ static void splitcfg(const std::string &cfg, std::list<std::string> &defines, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preprocessor::loadFiles(const simplecpp::TokenList &rawtokens, std::vector<std::string> &files)
|
static simplecpp::DUI createDUI(const Settings &_settings, const std::string &cfg, const std::string &filename)
|
||||||
{
|
{
|
||||||
const std::string filename(files[0]);
|
|
||||||
|
|
||||||
// Create a map for the cfg for faster access to defines
|
|
||||||
simplecpp::DUI dui;
|
simplecpp::DUI dui;
|
||||||
|
|
||||||
splitcfg(_settings.userDefines, dui.defines, "1");
|
splitcfg(_settings.userDefines, dui.defines, "1");
|
||||||
|
if (!cfg.empty())
|
||||||
|
splitcfg(cfg, dui.defines, "");
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator it = _settings.library.defines.begin(); it != _settings.library.defines.end(); ++it) {
|
for (std::vector<std::string>::const_iterator it = _settings.library.defines.begin(); it != _settings.library.defines.end(); ++it) {
|
||||||
if (it->compare(0,8,"#define ")!=0)
|
if (it->compare(0,8,"#define ")!=0)
|
||||||
|
@ -411,9 +410,32 @@ void Preprocessor::loadFiles(const simplecpp::TokenList &rawtokens, std::vector<
|
||||||
if (Path::isCPP(filename))
|
if (Path::isCPP(filename))
|
||||||
dui.defines.push_back("__cplusplus");
|
dui.defines.push_back("__cplusplus");
|
||||||
|
|
||||||
dui.undefined = _settings.userUndefs;
|
dui.undefined = _settings.userUndefs; // -U
|
||||||
|
dui.includePaths = _settings.includePaths; // -I
|
||||||
|
dui.includes = _settings.userIncludes; // --include
|
||||||
|
return dui;
|
||||||
|
}
|
||||||
|
|
||||||
dui.includePaths = _settings.includePaths;
|
static bool hasErrors(const simplecpp::OutputList &outputList)
|
||||||
|
{
|
||||||
|
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
||||||
|
switch (it->type) {
|
||||||
|
case simplecpp::Output::ERROR:
|
||||||
|
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
|
||||||
|
case simplecpp::Output::SYNTAX_ERROR:
|
||||||
|
return true;
|
||||||
|
case simplecpp::Output::WARNING:
|
||||||
|
case simplecpp::Output::MISSING_HEADER:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Preprocessor::loadFiles(const simplecpp::TokenList &rawtokens, std::vector<std::string> &files)
|
||||||
|
{
|
||||||
|
const simplecpp::DUI dui = createDUI(_settings, "", files[0]);
|
||||||
|
|
||||||
simplecpp::OutputList outputList;
|
simplecpp::OutputList outputList;
|
||||||
|
|
||||||
|
@ -452,35 +474,7 @@ std::string Preprocessor::getcode(const simplecpp::TokenList &tokens1, const std
|
||||||
{
|
{
|
||||||
const std::string filename(files[0]);
|
const std::string filename(files[0]);
|
||||||
|
|
||||||
// Create a map for the cfg for faster access to defines
|
const simplecpp::DUI dui = createDUI(_settings, cfg, filename);
|
||||||
simplecpp::DUI dui;
|
|
||||||
|
|
||||||
splitcfg(_settings.userDefines, dui.defines, "1");
|
|
||||||
splitcfg(cfg, dui.defines, "");
|
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator it = _settings.library.defines.begin(); it != _settings.library.defines.end(); ++it) {
|
|
||||||
if (it->compare(0,8,"#define ")!=0)
|
|
||||||
continue;
|
|
||||||
std::string s = it->substr(8);
|
|
||||||
std::string::size_type pos = s.find_first_of(" (");
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
dui.defines.push_back(s);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (s[pos] == ' ') {
|
|
||||||
s[pos] = '=';
|
|
||||||
} else {
|
|
||||||
s[s.find(")")+1] = '=';
|
|
||||||
}
|
|
||||||
dui.defines.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Path::isCPP(filename))
|
|
||||||
dui.defines.push_back("__cplusplus");
|
|
||||||
|
|
||||||
dui.undefined = _settings.userUndefs;
|
|
||||||
|
|
||||||
dui.includePaths = _settings.includePaths;
|
|
||||||
|
|
||||||
simplecpp::OutputList outputList;
|
simplecpp::OutputList outputList;
|
||||||
std::list<simplecpp::MacroUsage> macroUsage;
|
std::list<simplecpp::MacroUsage> macroUsage;
|
||||||
|
@ -488,27 +482,9 @@ std::string Preprocessor::getcode(const simplecpp::TokenList &tokens1, const std
|
||||||
simplecpp::preprocess(tokens2, tokens1, files, tokenlists, dui, &outputList, ¯oUsage);
|
simplecpp::preprocess(tokens2, tokens1, files, tokenlists, dui, &outputList, ¯oUsage);
|
||||||
|
|
||||||
bool showerror = (!_settings.userDefines.empty() && !_settings.force);
|
bool showerror = (!_settings.userDefines.empty() && !_settings.force);
|
||||||
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
reportOutput(outputList, showerror);
|
||||||
switch (it->type) {
|
if (hasErrors(outputList))
|
||||||
case simplecpp::Output::ERROR:
|
|
||||||
if (it->msg.compare(0,6,"#error")!=0 || showerror)
|
|
||||||
error(it->location.file(), it->location.line, it->msg);
|
|
||||||
return "";
|
return "";
|
||||||
case simplecpp::Output::WARNING:
|
|
||||||
break;
|
|
||||||
case simplecpp::Output::MISSING_HEADER: {
|
|
||||||
const std::string::size_type pos1 = it->msg.find_first_of("<\"");
|
|
||||||
const std::string::size_type pos2 = it->msg.find_first_of(">\"", pos1 + 1U);
|
|
||||||
if (pos1 < pos2 && pos2 != std::string::npos)
|
|
||||||
missingInclude(it->location.file(), it->location.line, it->msg.substr(pos1+1, pos2-pos1-1), it->msg[pos1] == '\"' ? UserHeader : SystemHeader);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
|
|
||||||
case simplecpp::Output::SYNTAX_ERROR:
|
|
||||||
error(it->location.file(), it->location.line, it->msg);
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure that guessed define macros without value are not used in the code
|
// ensure that guessed define macros without value are not used in the code
|
||||||
if (!validateCfg(cfg, macroUsage))
|
if (!validateCfg(cfg, macroUsage))
|
||||||
|
@ -601,13 +577,22 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
|
||||||
removeComments();
|
removeComments();
|
||||||
setDirectives(tokens1);
|
setDirectives(tokens1);
|
||||||
|
|
||||||
|
reportOutput(outputList, true);
|
||||||
|
|
||||||
|
if (hasErrors(outputList))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return getcode(tokens1, cfg, files, filedata.find("#file") != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool showerror)
|
||||||
|
{
|
||||||
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
||||||
switch (it->type) {
|
switch (it->type) {
|
||||||
case simplecpp::Output::ERROR:
|
case simplecpp::Output::ERROR:
|
||||||
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
|
if (it->msg.compare(0,6,"#error")!=0 || showerror)
|
||||||
case simplecpp::Output::SYNTAX_ERROR:
|
|
||||||
error(it->location.file(), it->location.line, it->msg);
|
error(it->location.file(), it->location.line, it->msg);
|
||||||
return "";
|
break;
|
||||||
case simplecpp::Output::WARNING:
|
case simplecpp::Output::WARNING:
|
||||||
break;
|
break;
|
||||||
case simplecpp::Output::MISSING_HEADER: {
|
case simplecpp::Output::MISSING_HEADER: {
|
||||||
|
@ -617,10 +602,12 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
|
||||||
missingInclude(it->location.file(), it->location.line, it->msg.substr(pos1+1, pos2-pos1-1), it->msg[pos1] == '\"' ? UserHeader : SystemHeader);
|
missingInclude(it->location.file(), it->location.line, it->msg.substr(pos1+1, pos2-pos1-1), it->msg[pos1] == '\"' ? UserHeader : SystemHeader);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
|
||||||
|
case simplecpp::Output::SYNTAX_ERROR:
|
||||||
|
error(it->location.file(), it->location.line, it->msg);
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return getcode(tokens1, cfg, files, filedata.find("#file") != std::string::npos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preprocessor::error(const std::string &filename, unsigned int linenr, const std::string &msg)
|
void Preprocessor::error(const std::string &filename, unsigned int linenr, const std::string &msg)
|
||||||
|
|
|
@ -184,9 +184,10 @@ public:
|
||||||
*/
|
*/
|
||||||
void dump(std::ostream &out) const;
|
void dump(std::ostream &out) const;
|
||||||
|
|
||||||
|
void reportOutput(const simplecpp::OutputList &outputList, bool showerror);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, HeaderTypes headerType);
|
void missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, HeaderTypes headerType);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
Settings& _settings;
|
Settings& _settings;
|
||||||
|
|
|
@ -2781,10 +2781,12 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
||||||
return;
|
return;
|
||||||
} while (tok->str() != "," && tok->str() != ")" && tok->str() != "=");
|
} while (tok->str() != "," && tok->str() != ")" && tok->str() != "=");
|
||||||
|
|
||||||
const Token *typeTok = startTok->tokAt(startTok->str() == "const" ? 1 : 0);
|
const Token *typeTok = startTok;
|
||||||
if (typeTok->str() == "struct" || typeTok->str() == "enum")
|
// skip over stuff to get to type
|
||||||
|
while (Token::Match(typeTok, "const|enum|struct|::"))
|
||||||
typeTok = typeTok->next();
|
typeTok = typeTok->next();
|
||||||
if (Token::Match(typeTok, "%type% ::"))
|
// skip over qualification
|
||||||
|
while (Token::Match(typeTok, "%type% ::"))
|
||||||
typeTok = typeTok->tokAt(2);
|
typeTok = typeTok->tokAt(2);
|
||||||
|
|
||||||
// check for argument with no name or missing varid
|
// check for argument with no name or missing varid
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define CPPCHECK_MAJOR 1
|
#define CPPCHECK_MAJOR 1
|
||||||
#define CPPCHECK_MINOR 74
|
#define CPPCHECK_MINOR 75
|
||||||
#define CPPCHECK_DEVMINOR 75
|
#define CPPCHECK_DEVMINOR 75
|
||||||
|
|
||||||
#define STRINGIFY(x) STRING(x)
|
#define STRINGIFY(x) STRING(x)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||||
<book>
|
<book>
|
||||||
<bookinfo>
|
<bookinfo>
|
||||||
<title>Cppcheck 1.75 dev</title>
|
<title>Cppcheck 1.75</title>
|
||||||
|
|
||||||
<date>2016-07-27</date>
|
<date>2016-07-27</date>
|
||||||
</bookinfo>
|
</bookinfo>
|
||||||
|
@ -752,13 +752,13 @@ Checking pen1.c...
|
||||||
<dealloc>DeleteObject</dealloc>
|
<dealloc>DeleteObject</dealloc>
|
||||||
</resource>
|
</resource>
|
||||||
</def></programlisting>
|
</def></programlisting>
|
||||||
</section>
|
|
||||||
|
|
||||||
<para>The allocation and deallocation functions are organized in groups.
|
<para>The allocation and deallocation functions are organized in groups.
|
||||||
Each group is defined in a <literal><resource></literal> or
|
Each group is defined in a <literal><resource></literal> or
|
||||||
<literal><memory></literal> tag and is identified by its
|
<literal><memory></literal> tag and is identified by its
|
||||||
<literal><dealloc></literal> functions. This means, groups with
|
<literal><dealloc></literal> functions. This means, groups with
|
||||||
overlapping <literal><dealloc></literal> tags are merged.</para>
|
overlapping <literal><dealloc></literal> tags are merged.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>leak-ignore and use</title>
|
<title>leak-ignore and use</title>
|
||||||
|
|
|
@ -2,11 +2,12 @@ if (BUILD_TESTS)
|
||||||
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/lib/ ${PROJECT_SOURCE_DIR}/cli/)
|
include_directories(${PROJECT_SOURCE_DIR}/lib/ ${PROJECT_SOURCE_DIR}/cli/)
|
||||||
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml)
|
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml)
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/externals/simplecpp/)
|
||||||
|
|
||||||
file(GLOB hdrs "*.h")
|
file(GLOB hdrs "*.h")
|
||||||
file(GLOB srcs "*.cpp")
|
file(GLOB srcs "*.cpp")
|
||||||
|
|
||||||
add_executable(testrunner ${hdrs} ${srcs} $<TARGET_OBJECTS:lib_objs> $<TARGET_OBJECTS:cli_objs> $<TARGET_OBJECTS:tinyxml_objs>)
|
add_executable(testrunner ${hdrs} ${srcs} $<TARGET_OBJECTS:lib_objs> $<TARGET_OBJECTS:cli_objs> $<TARGET_OBJECTS:tinyxml_objs> $<TARGET_OBJECTS:simplecpp_objs>)
|
||||||
if (HAVE_RULES)
|
if (HAVE_RULES)
|
||||||
target_link_libraries(testrunner pcre)
|
target_link_libraries(testrunner pcre)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -53,21 +53,9 @@ public:
|
||||||
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI(), &outputList);
|
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI(), &outputList);
|
||||||
|
|
||||||
if (errorLogger) {
|
if (errorLogger) {
|
||||||
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
Settings settings;
|
||||||
const simplecpp::Output &msg = *it;
|
Preprocessor p(settings, errorLogger);
|
||||||
if (msg.type == simplecpp::Output::ERROR) {
|
p.reportOutput(outputList, true);
|
||||||
|
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
|
||||||
ErrorLogger::ErrorMessage::FileLocation loc(msg.location.file(), msg.location.line);
|
|
||||||
locationList.push_back(loc);
|
|
||||||
errorLogger->reportErr(ErrorLogger::ErrorMessage(locationList,
|
|
||||||
emptyString,
|
|
||||||
Severity::error,
|
|
||||||
msg.msg,
|
|
||||||
"preprocessorError",
|
|
||||||
false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokens2.stringify();
|
return tokens2.stringify();
|
||||||
|
@ -1661,7 +1649,7 @@ private:
|
||||||
// Compare results..
|
// Compare results..
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
||||||
ASSERT_EQUALS("", actual[""]);
|
ASSERT_EQUALS("", actual[""]);
|
||||||
ASSERT_EQUALS("[file.c:6]: (error) Syntax error. Wrong number of parameters for macro 'BC'.\n", errout.str());
|
ASSERT_EQUALS("[file.c:6]: (error) Wrong number of parameters for macro 'BC'.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void newline_in_macro() {
|
void newline_in_macro() {
|
||||||
|
|
|
@ -209,6 +209,23 @@ private:
|
||||||
" l2.insert(it, l1.end());\n"
|
" l2.insert(it, l1.end());\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
// only warn for insert when there are preciself 2 arguments.
|
||||||
|
check("void foo() {\n"
|
||||||
|
" list<int> l1;\n"
|
||||||
|
" list<int> l2;\n"
|
||||||
|
" list<int>::iterator it = l1.begin();\n"
|
||||||
|
" l2.insert(it);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
check("void foo() {\n"
|
||||||
|
" list<int> l1;\n"
|
||||||
|
" list<int> l2;\n"
|
||||||
|
" list<int>::iterator it = l1.begin();\n"
|
||||||
|
" l2.insert(it,0,1);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iterator4() {
|
void iterator4() {
|
||||||
|
|
|
@ -186,6 +186,7 @@ private:
|
||||||
TEST_CASE(functionArgs6); // #7651
|
TEST_CASE(functionArgs6); // #7651
|
||||||
TEST_CASE(functionArgs7); // #7652
|
TEST_CASE(functionArgs7); // #7652
|
||||||
TEST_CASE(functionArgs8); // #7653
|
TEST_CASE(functionArgs8); // #7653
|
||||||
|
TEST_CASE(functionArgs9); // #7657
|
||||||
|
|
||||||
TEST_CASE(namespaces1);
|
TEST_CASE(namespaces1);
|
||||||
TEST_CASE(namespaces2);
|
TEST_CASE(namespaces2);
|
||||||
|
@ -1732,6 +1733,28 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void functionArgs9() { // #7657
|
||||||
|
GET_SYMBOL_DB("struct A {\n"
|
||||||
|
" struct B {\n"
|
||||||
|
" enum C { };\n"
|
||||||
|
" };\n"
|
||||||
|
"};\n"
|
||||||
|
"void foo(A::B::C c) { }");
|
||||||
|
ASSERT_EQUALS(true, db != nullptr);
|
||||||
|
if (db) {
|
||||||
|
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo (");
|
||||||
|
ASSERT_EQUALS(true, f && f->function());
|
||||||
|
if (f && f->function()) {
|
||||||
|
const Function *func = f->function();
|
||||||
|
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
|
||||||
|
if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
|
||||||
|
const Type * type = func->argumentList.front().type();
|
||||||
|
ASSERT_EQUALS(true, type->isEnumType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void namespaces1() {
|
void namespaces1() {
|
||||||
GET_SYMBOL_DB("namespace fred {\n"
|
GET_SYMBOL_DB("namespace fred {\n"
|
||||||
" namespace barney {\n"
|
" namespace barney {\n"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Include>
|
<Include>
|
||||||
<?define ProductName = "Cppcheck $(var.Platform) 1.75 dev" ?>
|
<?define ProductName = "Cppcheck $(var.Platform) 1.75" ?>
|
||||||
<?define ProductNameShort = "Cppcheck" ?>
|
<?define ProductNameShort = "Cppcheck" ?>
|
||||||
<?define ProductVersion = "1.74.99" ?>
|
<?define ProductVersion = "1.75" ?>
|
||||||
|
|
||||||
<?define ProductManufacturer = "The Cppcheck team" ?>
|
<?define ProductManufacturer = "The Cppcheck team" ?>
|
||||||
<?define ProductDescription = "Cppcheck is a tool for static analysis of C/C++ code" ?>
|
<?define ProductDescription = "Cppcheck is a tool for static analysis of C/C++ code" ?>
|
||||||
|
|
Loading…
Reference in New Issue