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 += '/';
|
||||
|
||||
_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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue