C++: do not strip trailing newlines in the preprocessor output.

Doing so resulted in an incorrect position for the EOF token when the
preprocessed output would be parsed. That in turn leads to incorrect
insertion positions for refactoring actions.

This is especially true when a file contains only preprocessor
directives: the EOF token would point to line 1 column 1, which is
usually not the place where code should be inserted.

Change-Id: I7d359aa7a6c04bc52c8b873fd49ad6afc3a77319
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
Erik Verbruggen
2013-05-30 15:03:54 +02:00
committed by Erik Verbruggen
parent 271a96b19a
commit f2631ad031
7 changed files with 101 additions and 29 deletions

View File

@@ -1332,19 +1332,6 @@ void Preprocessor::synchronizeOutputLines(const PPToken &tk, bool forceLine)
adjustForCommentOrStringNewlines(&m_env->currentLine, tk);
}
void Preprocessor::removeTrailingOutputLines()
{
QByteArray &buffer = currentOutputBuffer();
int i = buffer.size() - 1;
while (i >= 0 && buffer.at(i) == '\n')
--i;
const int mightChop = buffer.size() - i - 1;
if (mightChop > 1) {
// Keep one new line at end.
buffer.chop(mightChop - 1);
}
}
std::size_t Preprocessor::computeDistance(const Preprocessor::PPToken &tk, bool forceTillLine)
{
// Find previous non-space character or line begin.
@@ -1450,8 +1437,6 @@ void Preprocessor::preprocess(const QString &fileName, const QByteArray &source,
} while (tk.isNot(T_EOF_SYMBOL));
removeTrailingOutputLines();
if (includeGuardMacroName) {
if (m_state.m_includeGuardState == State::IncludeGuardState_AfterDefine
|| m_state.m_includeGuardState == State::IncludeGuardState_AfterEndif)

View File

@@ -237,7 +237,6 @@ private:
void maybeStartOutputLine();
void generateOutputLineMarker(unsigned lineno);
void synchronizeOutputLines(const PPToken &tk, bool forceLine = false);
void removeTrailingOutputLines();
void enforceSpacing(const PPToken &tk, bool forceSpacing = false);
static std::size_t computeDistance(const PPToken &tk, bool forceTillLine = false);

View File

@@ -844,9 +844,9 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_headerSource_namespace2()
original =
"#include \"file.h\"\n"
"using namespace N;\n"
"\n"
;
expected = original +
"\n"
"\n"
"Foo::Foo()\n"
"{\n\n"

View File

@@ -10,4 +10,3 @@ private:
public:
Test();
};

View File

@@ -1 +1,9 @@
# 1 "data/identifier-expansion.5.cpp"

View File

@@ -10,3 +10,8 @@ void thisFunctionIsEnabled();
void thisFunctionIsEnabled2();
# 31 "data/macro-test.cpp"
void thisFunctionIsEnabled3();

View File

@@ -353,6 +353,8 @@ private slots:
void skip_unknown_directives_data();
void include_guard();
void include_guard_data();
void empty_trailing_lines();
void empty_trailing_lines_data();
};
// Remove all #... lines, and 'simplify' string, to allow easily comparing the result
@@ -1507,7 +1509,13 @@ void tst_Preprocessor::skip_unknown_directives_data()
"# 10 \"file.cpp\"\n"
"# ()\n"
"#\n";
expected = "# 1 \"<stdin>\"\n";
expected =
"# 1 \"<stdin>\"\n"
"\n"
"\n"
"\n"
"\n"
;
QTest::newRow("case 1") << original << expected;
}
@@ -1593,6 +1601,74 @@ void tst_Preprocessor::include_guard_data()
;
}
void tst_Preprocessor::empty_trailing_lines()
{
compare_input_output();
}
void tst_Preprocessor::empty_trailing_lines_data()
{
// Test if the number of lines at the end of a file is correct. This is important to make the
// EOF token for the end up at the correct line.
QTest::addColumn<QByteArray>("input");
QTest::addColumn<QByteArray>("output");
QByteArray original;
QByteArray expected;
original =
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
;
expected = "# 1 \"<stdin>\"\n" + original;
QTest::newRow("9 empty lines") << original << expected;
original =
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
;
expected =
"# 1 \"<stdin>\"\n"
"# 11 \"<stdin>\"\n"
;
QTest::newRow("11 empty lines") << original << expected;
original =
"#include <something>\n"
;
expected =
"# 1 \"<stdin>\"\n"
"\n"
;
QTest::newRow("1 include") << original << expected;
original =
"#include <something>\n"
"\n"
;
expected =
"# 1 \"<stdin>\"\n"
"\n"
"\n"
;
QTest::newRow("1 empty line with 1 include") << original << expected;
}
void tst_Preprocessor::compare_input_output(bool keepComments)
{
QFETCH(QByteArray, input);
@@ -1602,7 +1678,7 @@ void tst_Preprocessor::compare_input_output(bool keepComments)
Preprocessor preprocess(0, &env);
preprocess.setKeepComments(keepComments);
QByteArray prep = preprocess.run(QLatin1String("<stdin>"), input);
QCOMPARE(output, prep);
QCOMPARE(prep.constData(), output.constData());
}
QTEST_APPLESS_MAIN(tst_Preprocessor)