Fixed #4408 (Force inclusion of files (a la -include /.../ in GCC))

This commit is contained in:
Simon Kagstrom 2012-12-27 16:52:31 +01:00 committed by Daniel Marjamäki
parent 2e0a9c4b33
commit ef28bde3e4
5 changed files with 122 additions and 3 deletions

View File

@ -414,6 +414,13 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
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) {
// open this file and read every input file (1 file name per line)
AddInclPathsToList(16 + argv[i], _settings->_includePaths);
@ -772,6 +779,10 @@ void CmdLineParser::PrintHelp()
" First given path is searched for contained header\n"
" files first. If paths are relative to source files,\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"
" from the check. This applies only to source files so\n"
" header files included by source files are not matched.\n"

View File

@ -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)
{
std::map<std::string, std::string> defs;
std::string forcedIncludes;
if (file0.empty())
file0 = 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(...)
removeAsm(processedFile);
@ -827,8 +882,6 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
}
if (_settings && !_settings->userDefines.empty()) {
std::map<std::string, std::string> defs;
// TODO: break out this code. There is other similar code.
std::string::size_type pos1 = 0;
while (pos1 != std::string::npos) {
@ -855,7 +908,7 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
}
processedFile = handleIncludes(processedFile, filename, includePaths, defs);
if (_settings->userDefines.empty()) // TODO: How can it be empty?
if (_settings->userIncludes.empty())
resultConfigurations = getcfgs(processedFile, filename);
} 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)
includeguard = false;
if (line.compare(0, 5, "#line") == 0)
continue;
if (line.empty() || line[0] != '#')
continue;
@ -1723,6 +1779,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
} else if (line.compare(0, 7, "#file \"") == 0 ||
line.compare(0, 8, "#endfile") == 0 ||
line.compare(0, 8, "#define ") == 0 ||
line.compare(0, 6, "#line ") == 0 ||
line.compare(0, 6, "#undef") == 0) {
// We must not remove #file tags or line numbers
// are corrupted. File tags are removed by the tokenizer.

View File

@ -168,6 +168,9 @@ public:
/** @brief undefines given by the user */
std::set<std::string> userUndefs;
/** @brief forced includes given by the user */
std::list<std::string> userIncludes;
/** @brief --report-progress */
bool reportProgress;

View File

@ -287,6 +287,16 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0)
if (CurrentToken == "#file") {
// Handle this where strings are handled
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") {
if (lineNumbers.empty() || fileIndexes.empty()) { // error
deallocateTokens();

View File

@ -284,6 +284,8 @@ private:
TEST_CASE(file2);
TEST_CASE(file3);
TEST_CASE(line1); // Ticket #4408
TEST_CASE(doublesharp);
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() {