Fixed #4408 (Force inclusion of files (a la -include /.../ in GCC))
This commit is contained in:
parent
2e0a9c4b33
commit
ef28bde3e4
|
@ -414,6 +414,13 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
|
||||||
path += '/';
|
path += '/';
|
||||||
|
|
||||||
_settings->_includePaths.push_back(path);
|
_settings->_includePaths.push_back(path);
|
||||||
|
} else if (std::strncmp(argv[i], "--include=", 10) == 0) {
|
||||||
|
std::string path = argv[i] + 10;
|
||||||
|
|
||||||
|
path = Path::fromNativeSeparators(path);
|
||||||
|
|
||||||
|
_settings->userIncludes.push_back(path);
|
||||||
|
_settings->userDefines += ";";
|
||||||
} else if (std::strncmp(argv[i], "--includes-file=", 16) == 0) {
|
} else if (std::strncmp(argv[i], "--includes-file=", 16) == 0) {
|
||||||
// open this file and read every input file (1 file name per line)
|
// open this file and read every input file (1 file name per line)
|
||||||
AddInclPathsToList(16 + argv[i], _settings->_includePaths);
|
AddInclPathsToList(16 + argv[i], _settings->_includePaths);
|
||||||
|
@ -772,6 +779,10 @@ void CmdLineParser::PrintHelp()
|
||||||
" First given path is searched for contained header\n"
|
" First given path is searched for contained header\n"
|
||||||
" files first. If paths are relative to source files,\n"
|
" files first. If paths are relative to source files,\n"
|
||||||
" this is not needed.\n"
|
" this is not needed.\n"
|
||||||
|
" --include=<file>\n"
|
||||||
|
" Force inclusion of a file. Can be used for example when\n"
|
||||||
|
" checking the Linux kernel, where autoconf.h needs to be\n"
|
||||||
|
" included for every file compiled.\n"
|
||||||
" -i <dir or file> Give a source file or source file directory to exclude\n"
|
" -i <dir or file> Give a source file or source file directory to exclude\n"
|
||||||
" from the check. This applies only to source files so\n"
|
" from the check. This applies only to source files so\n"
|
||||||
" header files included by source files are not matched.\n"
|
" header files included by source files are not matched.\n"
|
||||||
|
|
|
@ -796,11 +796,66 @@ void Preprocessor::preprocessWhitespaces(std::string &processedFile)
|
||||||
|
|
||||||
void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processedFile, std::list<std::string> &resultConfigurations, const std::string &filename, const std::list<std::string> &includePaths)
|
void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processedFile, std::list<std::string> &resultConfigurations, const std::string &filename, const std::list<std::string> &includePaths)
|
||||||
{
|
{
|
||||||
|
std::map<std::string, std::string> defs;
|
||||||
|
std::string forcedIncludes;
|
||||||
|
|
||||||
if (file0.empty())
|
if (file0.empty())
|
||||||
file0 = filename;
|
file0 = filename;
|
||||||
|
|
||||||
processedFile = read(srcCodeStream, filename);
|
processedFile = read(srcCodeStream, filename);
|
||||||
|
|
||||||
|
if (_settings && !_settings->userIncludes.empty()) {
|
||||||
|
for (std::list<std::string>::iterator it = _settings->userIncludes.begin();
|
||||||
|
it != _settings->userIncludes.end();
|
||||||
|
it++) {
|
||||||
|
std::string cur = *it;
|
||||||
|
|
||||||
|
// try to open file
|
||||||
|
std::ifstream fin;
|
||||||
|
|
||||||
|
fin.open(cur.c_str());
|
||||||
|
if (!fin.is_open()) {
|
||||||
|
if (_settings && !_settings->nomsg.isSuppressed("missingInclude", cur, 1)) {
|
||||||
|
std::string path = "";
|
||||||
|
|
||||||
|
std::size_t pos = cur.find_last_of("\\/");
|
||||||
|
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
path = cur.substr(0, 1 + pos);
|
||||||
|
|
||||||
|
missingIncludeFlag = true;
|
||||||
|
missingInclude(Path::toNativeSeparators(path),
|
||||||
|
1,
|
||||||
|
cur,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string fileData = read(fin, filename);
|
||||||
|
|
||||||
|
fin.close();
|
||||||
|
|
||||||
|
//handleIncludes("#include \"" + cur + "\"\n", cur, includePaths, defs);
|
||||||
|
forcedIncludes =
|
||||||
|
forcedIncludes +
|
||||||
|
"#file \"" + cur + "\"\n" +
|
||||||
|
"#line 1\n" +
|
||||||
|
fileData + "\n" +
|
||||||
|
"#endfile\n"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!forcedIncludes.empty()) {
|
||||||
|
processedFile =
|
||||||
|
forcedIncludes +
|
||||||
|
"#file \"" + filename + "\"\n" +
|
||||||
|
"#line 1\n" +
|
||||||
|
processedFile +
|
||||||
|
"#endfile\n"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove asm(...)
|
// Remove asm(...)
|
||||||
removeAsm(processedFile);
|
removeAsm(processedFile);
|
||||||
|
|
||||||
|
@ -827,8 +882,6 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings && !_settings->userDefines.empty()) {
|
if (_settings && !_settings->userDefines.empty()) {
|
||||||
std::map<std::string, std::string> defs;
|
|
||||||
|
|
||||||
// TODO: break out this code. There is other similar code.
|
// TODO: break out this code. There is other similar code.
|
||||||
std::string::size_type pos1 = 0;
|
std::string::size_type pos1 = 0;
|
||||||
while (pos1 != std::string::npos) {
|
while (pos1 != std::string::npos) {
|
||||||
|
@ -855,7 +908,7 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
|
||||||
}
|
}
|
||||||
|
|
||||||
processedFile = handleIncludes(processedFile, filename, includePaths, defs);
|
processedFile = handleIncludes(processedFile, filename, includePaths, defs);
|
||||||
if (_settings->userDefines.empty()) // TODO: How can it be empty?
|
if (_settings->userIncludes.empty())
|
||||||
resultConfigurations = getcfgs(processedFile, filename);
|
resultConfigurations = getcfgs(processedFile, filename);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1043,6 +1096,9 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
|
||||||
if (!line.empty() && line.compare(0, 3, "#if") != 0)
|
if (!line.empty() && line.compare(0, 3, "#if") != 0)
|
||||||
includeguard = false;
|
includeguard = false;
|
||||||
|
|
||||||
|
if (line.compare(0, 5, "#line") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (line.empty() || line[0] != '#')
|
if (line.empty() || line[0] != '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1723,6 +1779,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
|
||||||
} else if (line.compare(0, 7, "#file \"") == 0 ||
|
} else if (line.compare(0, 7, "#file \"") == 0 ||
|
||||||
line.compare(0, 8, "#endfile") == 0 ||
|
line.compare(0, 8, "#endfile") == 0 ||
|
||||||
line.compare(0, 8, "#define ") == 0 ||
|
line.compare(0, 8, "#define ") == 0 ||
|
||||||
|
line.compare(0, 6, "#line ") == 0 ||
|
||||||
line.compare(0, 6, "#undef") == 0) {
|
line.compare(0, 6, "#undef") == 0) {
|
||||||
// We must not remove #file tags or line numbers
|
// We must not remove #file tags or line numbers
|
||||||
// are corrupted. File tags are removed by the tokenizer.
|
// are corrupted. File tags are removed by the tokenizer.
|
||||||
|
|
|
@ -168,6 +168,9 @@ public:
|
||||||
/** @brief undefines given by the user */
|
/** @brief undefines given by the user */
|
||||||
std::set<std::string> userUndefs;
|
std::set<std::string> userUndefs;
|
||||||
|
|
||||||
|
/** @brief forced includes given by the user */
|
||||||
|
std::list<std::string> userIncludes;
|
||||||
|
|
||||||
/** @brief --report-progress */
|
/** @brief --report-progress */
|
||||||
bool reportProgress;
|
bool reportProgress;
|
||||||
|
|
||||||
|
|
|
@ -287,6 +287,16 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0)
|
||||||
if (CurrentToken == "#file") {
|
if (CurrentToken == "#file") {
|
||||||
// Handle this where strings are handled
|
// Handle this where strings are handled
|
||||||
continue;
|
continue;
|
||||||
|
} else if (CurrentToken == "#line") {
|
||||||
|
// Read to end of line
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
std::getline(code, line);
|
||||||
|
|
||||||
|
// Update the current line number
|
||||||
|
std::stringstream(line) >> lineno;
|
||||||
|
CurrentToken.clear();
|
||||||
|
continue;
|
||||||
} else if (CurrentToken == "#endfile") {
|
} else if (CurrentToken == "#endfile") {
|
||||||
if (lineNumbers.empty() || fileIndexes.empty()) { // error
|
if (lineNumbers.empty() || fileIndexes.empty()) { // error
|
||||||
deallocateTokens();
|
deallocateTokens();
|
||||||
|
|
|
@ -284,6 +284,8 @@ private:
|
||||||
TEST_CASE(file2);
|
TEST_CASE(file2);
|
||||||
TEST_CASE(file3);
|
TEST_CASE(file3);
|
||||||
|
|
||||||
|
TEST_CASE(line1); // Ticket #4408
|
||||||
|
|
||||||
TEST_CASE(doublesharp);
|
TEST_CASE(doublesharp);
|
||||||
|
|
||||||
TEST_CASE(macrodoublesharp);
|
TEST_CASE(macrodoublesharp);
|
||||||
|
@ -4609,6 +4611,42 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void line1() {
|
||||||
|
// Test for Ticket #4408
|
||||||
|
const char code[] = "#file \"c:\\a.h\"\n"
|
||||||
|
"first\n"
|
||||||
|
"#line 5\n"
|
||||||
|
"second\n"
|
||||||
|
"#line not-a-number\n"
|
||||||
|
"third\n"
|
||||||
|
"#line 100 \"i.h\"\n"
|
||||||
|
"fourth\n"
|
||||||
|
"fifth\n"
|
||||||
|
"#endfile\n";
|
||||||
|
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
|
||||||
|
TokenList tokenList(&settings);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
bool res = tokenList.createTokens(istr, "a.cpp");
|
||||||
|
ASSERT_EQUALS(res, true);
|
||||||
|
|
||||||
|
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
|
||||||
|
if (tok->str() == "first")
|
||||||
|
ASSERT_EQUALS(1, tok->linenr());
|
||||||
|
if (tok->str() == "second")
|
||||||
|
ASSERT_EQUALS(5, tok->linenr());
|
||||||
|
if (tok->str() == "third")
|
||||||
|
TODO_ASSERT_EQUALS(7, 0, tok->linenr());
|
||||||
|
if (tok->str() == "fourth")
|
||||||
|
ASSERT_EQUALS(100, tok->linenr());
|
||||||
|
if (tok->str() == "fifth")
|
||||||
|
ASSERT_EQUALS(101, tok->linenr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void doublesharp() {
|
void doublesharp() {
|
||||||
|
|
Loading…
Reference in New Issue