Commit d8d9afef authored by Igor Kushnir's avatar Igor Kushnir
Browse files

Skip multi-line comments in findClose() and findCommaOrEnd()

An example of a fixed bug follows. For the macro
    #define m( /*a)b*/ x )x
- before this commit the tooltip contained:
    Function macro: m(/*a)
    Body: b*/ x )x
- at this commit the tooltip contains:
    Function macro: m(/*a)b*/ x)
    Body: x
parent 0ac447c1
......@@ -80,7 +80,26 @@ int skipStringOrCharLiteral(QStringView str, int pos)
}
return pos;
}
/// Skips multi-line comments.
/// No need to support single-line comments, because they cannot appear within a macro parameter list;
/// in other contexts libclang removes comments from each string that ends up here.
int skipComment(QStringView str, int pos)
{
Q_ASSERT(pos >= 0 && pos < str.size());
Q_ASSERT(str[pos] == QLatin1Char{'/'});
if (pos + 1 == str.size() || str[pos + 1] != QLatin1Char{'*'})
return pos; // not a comment
pos += 2;
while (pos < str.size() && (str[pos] != QLatin1Char{'/'} || str[pos - 1] != QLatin1Char{'*'})) {
++pos;
}
return pos;
}
} // unnamed namespace
namespace KDevelop {
class ParamIteratorPrivate
......@@ -162,6 +181,9 @@ int findClose(QStringView str, int pos)
case '\'':
a = skipStringOrCharLiteral(str, a);
break;
case '/':
a = skipComment(str, a);
break;
}
if (depth == 0) {
......@@ -183,6 +205,9 @@ int findCommaOrEnd(QStringView str, int pos, QChar validEnd)
case '\'':
a = skipStringOrCharLiteral(str, a);
break;
case '/':
a = skipComment(str, a);
break;
case '<':
if (isOperator(str, a))
break;
......
......@@ -130,11 +130,15 @@ void TestStringHelpers::benchFormatComment()
void TestStringHelpers::testParamIterator_data()
{
QTest::addColumn<QString>("parens");
QTest::addColumn<QString>("source");
QTest::addColumn<QStringList>("params");
auto addTest = [](const QString& source, const QStringList& params) {
QTest::addRow("%s", qPrintable(source)) << source << params;
QTest::addRow("%s", qPrintable(source)) << QStringLiteral("<>:") << source << params;
};
auto addMacroTest = [](const QString& source, const QStringList& params) {
QTest::addRow("%s", qPrintable(source)) << QStringLiteral("()") << source << params;
};
addTest("Empty", {});
......@@ -181,15 +185,16 @@ void TestStringHelpers::testParamIterator_data()
addTest("bogus<_Tp, _Up, invalid<decltype(<=(std::declval<_Tp>(), std::declval<_Up>()))>>", {"_Tp", "_Up", "invalid<decltype(<=(std::declval<_Tp>(), std::declval<_Up>()))>>"});
addTest("hardToParse<A<B>", {"A<B"});
addTest("hardToParse<(A>B)>", {"(A>B)"});
addMacroTest("( /*a)b*/ x , /*,*/y,z )", {"/*a)b*/ x", "/*,*/y", "z"});
}
void TestStringHelpers::testParamIterator()
{
QFETCH(QString, parens);
QFETCH(QString, source);
QFETCH(QStringList, params);
const auto parens = u"<>:";
auto it = KDevelop::ParamIterator(parens, source);
QEXPECT_FAIL("hardToParse<A<B>", "quasi impossible to parse without semantic knowledge of the types", Abort);
......
......@@ -278,6 +278,9 @@ void TestDUChain::testMacroDefinition_data()
addTest("m(x, y) x / y", "x / y", true, {"x", "y"});
addTest("M_N(X, ...) f(X __VA_OPT__(,) __VA_ARGS__)", "f(X __VA_OPT__(,) __VA_ARGS__)", true, {"X", "..."});
addTest("m( /*a)b*/ x )x", "x", true, {"/*a)b*/ x"});
addTest("_(\t/* u,v,*/c\t)\tc/3*(c-5)", "c/3*(c-5)", true, {"/* u,v,*/c"});
addTest("MM\t\\\n\t471", "\\\n\t471");
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment