qmake: make argument validation of built-ins data driven

at the time this patch was conceived, it was meant as an exercise in
getting rid of usages of ProString::toQString(m_tmp). however, this was
meanwhile superseded by use of toQStringView().
but the change itself should have been done a long time ago already, and
there is no harm in going through with it.

on the way, this also unifies and fixes some of the error messages.

Change-Id: I337aff994c508df783df4794c3fa0762d83a691b
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Oswald Buddenhagen 2017-08-11 19:22:58 +02:00
parent 10e5ec2557
commit 811d8b82b5
6 changed files with 666 additions and 823 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1762,12 +1762,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
const ProKey &func, const ushort *&tokPtr)
{
if (int func_t = statics.functions.value(func)) {
auto adef = statics.functions.constFind(func);
if (adef != statics.functions.constEnd()) {
//why don't the builtin functions just use args_list? --Sam
ProStringList args;
if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
return ReturnError;
return evaluateBuiltinConditional(func_t, func, args);
return evaluateBuiltinConditional(*adef, func, args);
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
@ -1788,12 +1789,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction(
const ProKey &func, const ushort *&tokPtr, ProStringList *ret)
{
if (int func_t = statics.expands.value(func)) {
auto adef = statics.expands.constFind(func);
if (adef != statics.expands.constEnd()) {
//why don't the builtin functions just use args_list? --Sam
ProStringList args;
if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
return ReturnError;
return evaluateBuiltinExpand(func_t, func, args, *ret);
return evaluateBuiltinExpand(*adef, func, args, *ret);
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =

View File

@ -105,6 +105,8 @@ public:
const ProValueMap &top() const { return last(); }
};
namespace QMakeInternal { struct QMakeBuiltin; }
class QMAKE_EXPORT QMakeEvaluator
{
public:
@ -214,8 +216,10 @@ public:
VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret);
VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
VisitReturn evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args, ProStringList &ret);
VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args);
VisitReturn evaluateBuiltinExpand(const QMakeInternal::QMakeBuiltin &adef,
const ProKey &function, const ProStringList &args, ProStringList &ret);
VisitReturn evaluateBuiltinConditional(const QMakeInternal::QMakeBuiltin &adef,
const ProKey &function, const ProStringList &args);
VisitReturn evaluateConditional(const QStringRef &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL

View File

@ -64,6 +64,22 @@ QT_BEGIN_NAMESPACE
namespace QMakeInternal {
struct QMakeBuiltinInit
{
const char *name;
int func;
enum { VarArgs = 1000 };
int min_args, max_args;
const char *args;
};
struct QMakeBuiltin
{
QMakeBuiltin(const QMakeBuiltinInit &data);
QString usage;
int index, minArgs, maxArgs;
};
struct QMakeStatics {
QString field_sep;
QString strtrue;
@ -83,8 +99,8 @@ struct QMakeStatics {
#ifdef PROEVALUATOR_FULL
ProKey strREQUIRES;
#endif
QHash<ProKey, int> expands;
QHash<ProKey, int> functions;
QHash<ProKey, QMakeBuiltin> expands;
QHash<ProKey, QMakeBuiltin> functions;
QHash<ProKey, ProKey> varMap;
ProStringList fakeValue;
};
@ -93,6 +109,8 @@ extern QMakeStatics statics;
}
Q_DECLARE_TYPEINFO(QMakeInternal::QMakeBuiltin, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QMAKEEVALUATOR_P_H

View File

@ -82,8 +82,9 @@ bool QMakeProject::test(const ProKey &func, const QList<ProStringList> &args)
{
m_current.clear();
if (int func_t = statics.functions.value(func))
return boolRet(evaluateBuiltinConditional(func_t, func, prepareBuiltinArgs(args)));
auto adef = statics.functions.constFind(func);
if (adef != statics.functions.constEnd())
return boolRet(evaluateBuiltinConditional(*adef, func, prepareBuiltinArgs(args)));
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.testFunctions.constFind(func);
@ -99,9 +100,10 @@ QStringList QMakeProject::expand(const ProKey &func, const QList<ProStringList>
{
m_current.clear();
if (int func_t = statics.expands.value(func)) {
auto adef = statics.expands.constFind(func);
if (adef != statics.expands.constEnd()) {
ProStringList ret;
if (evaluateBuiltinExpand(func_t, func, prepareBuiltinArgs(args), ret) == ReturnError)
if (evaluateBuiltinExpand(*adef, func, prepareBuiltinArgs(args), ret) == ReturnError)
exit(3);
return ret.toQStringList();
}

View File

@ -819,7 +819,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$member(): bad number of arguments")
<< "VAR = $$member(1, 2, 3, 4)"
<< "VAR ="
<< "##:1: member(var, start, end) requires one to three arguments."
<< "##:1: member(var, [start, [end]]) requires one to three arguments."
<< true;
QTest::newRow("$$member(): bad args (1)")
@ -1030,8 +1030,8 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$fromfile(): bad number of arguments")
<< "VAR = $$fromfile(1) \\\n$$fromfile(1, 2, 3)"
<< "VAR ="
<< "##:1: fromfile(file, variable) requires two arguments.\n"
"##:2: fromfile(file, variable) requires two arguments."
<< "##:1: fromfile(file, var) requires two arguments.\n"
"##:2: fromfile(file, var) requires two arguments."
<< true;
QTest::newRow("$$eval()")
@ -1043,7 +1043,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$eval(): bad number of arguments")
<< "VAR = $$eval(1, 2)"
<< "VAR ="
<< "##:1: eval(variable) requires one argument."
<< "##:1: eval(var) requires one argument."
<< true;
QTest::newRow("$$list()")
@ -1128,7 +1128,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$format_number(): bad number of arguments")
<< "VAR = $$format_number(13, 1, 2)"
<< "VAR ="
<< "##:1: format_number(number[, options...]) requires one or two arguments."
<< "##:1: format_number(number, [options...]) requires one or two arguments."
<< true;
QTest::newRow("$$format_number(): invalid option")
@ -1200,7 +1200,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$join(): bad number of arguments")
<< "VAR = $$join(1, 2, 3, 4, 5)"
<< "VAR ="
<< "##:1: join(var, glue, before, after) requires one to four arguments."
<< "##:1: join(var, [glue, [before, [after]]]) requires one to four arguments."
<< true;
QTest::newRow("$$split(): default sep")
@ -1296,8 +1296,8 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$section(): bad number of arguments")
<< "VAR = $$section(1, 2) \\\n$$section(1, 2, 3, 4, 5)"
<< "VAR ="
<< "##:1: section(var, sep, begin, end) requires three or four arguments.\n"
"##:2: section(var, sep, begin, end) requires three or four arguments."
<< "##:1: section(var, sep, begin, [end]) requires three or four arguments.\n"
"##:2: section(var, sep, begin, [end]) requires three or four arguments."
<< true;
QTest::newRow("$$find()")
@ -1333,7 +1333,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$cat(): bad number of arguments")
<< "VAR = $$cat(1, 2, 3)"
<< "VAR ="
<< "##:1: cat(file, singleline=true) requires one or two arguments."
<< "##:1: cat(file, [mode=true|blob|lines]) requires one or two arguments."
<< true;
QTest::newRow("$$system(): default mode")
@ -1473,7 +1473,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$files(): bad number of arguments")
<< "VAR = $$files(1, 2, 3)"
<< "VAR ="
<< "##:1: files(pattern, recursive=false) requires one or two arguments."
<< "##:1: files(pattern, [recursive=false]) requires one or two arguments."
<< true;
#if 0
@ -1639,7 +1639,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$absolute_path(): bad number of arguments")
<< "VAR = $$absolute_path(1, 2, 3)"
<< "VAR ="
<< "##:1: absolute_path(path[, base]) requires one or two arguments."
<< "##:1: absolute_path(path, [base]) requires one or two arguments."
<< true;
QTest::newRow("$$relative_path(): relative file")
@ -1683,7 +1683,7 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
QTest::newRow("$$relative_path(): bad number of arguments")
<< "VAR = $$relative_path(1, 2, 3)"
<< "VAR ="
<< "##:1: relative_path(path[, base]) requires one or two arguments."
<< "##:1: relative_path(path, [base]) requires one or two arguments."
<< true;
QTest::newRow("$$clean_path()")
@ -1847,7 +1847,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("defined(): bad number of arguments")
<< "defined(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: defined(function, [\"test\"|\"replace\"|\"var\"]) requires one or two arguments."
<< "##:1: defined(object, [\"test\"|\"replace\"|\"var\"]) requires one or two arguments."
<< true;
QTest::newRow("export()")
@ -1864,7 +1864,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("export(): bad number of arguments")
<< "export(1, 2): OK = 1"
<< "OK = UNDEF"
<< "##:1: export(variable) requires one argument."
<< "##:1: export(var) requires one argument."
<< true;
QTest::newRow("infile(): found")
@ -2006,7 +2006,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("CONFIG(): bad number of arguments")
<< "CONFIG(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: CONFIG(config) requires one or two arguments."
<< "##:1: CONFIG(config, [mutuals]) requires one or two arguments."
<< true;
QTest::newRow("contains(simple plain): true")
@ -2072,8 +2072,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("contains(): bad number of arguments")
<< "contains(1): OK = 1\ncontains(1, 2, 3, 4): OK = 1"
<< "OK = UNDEF"
<< "##:1: contains(var, val) requires two or three arguments.\n"
"##:2: contains(var, val) requires two or three arguments."
<< "##:1: contains(var, val, [mutuals]) requires two or three arguments.\n"
"##:2: contains(var, val, [mutuals]) requires two or three arguments."
<< true;
QTest::newRow("count(): true")
@ -2133,8 +2133,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("count(): bad number of arguments")
<< "count(1): OK = 1\ncount(1, 2, 3, 4): OK = 1"
<< "OK = UNDEF"
<< "##:1: count(var, count, op=\"equals\") requires two or three arguments.\n"
"##:2: count(var, count, op=\"equals\") requires two or three arguments."
<< "##:1: count(var, count, [op=operator]) requires two or three arguments.\n"
"##:2: count(var, count, [op=operator]) requires two or three arguments."
<< true;
QTest::newRow("greaterThan(int): true")
@ -2164,8 +2164,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("greaterThan(): bad number of arguments")
<< "greaterThan(1): OK = 1\ngreaterThan(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: greaterThan(variable, value) requires two arguments.\n"
"##:2: greaterThan(variable, value) requires two arguments."
<< "##:1: greaterThan(var, val) requires two arguments.\n"
"##:2: greaterThan(var, val) requires two arguments."
<< true;
QTest::newRow("lessThan(int): true")
@ -2195,8 +2195,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("lessThan(): bad number of arguments")
<< "lessThan(1): OK = 1\nlessThan(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: lessThan(variable, value) requires two arguments.\n"
"##:2: lessThan(variable, value) requires two arguments."
<< "##:1: lessThan(var, val) requires two arguments.\n"
"##:2: lessThan(var, val) requires two arguments."
<< true;
QTest::newRow("equals(): true")
@ -2214,8 +2214,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("equals(): bad number of arguments")
<< "equals(1): OK = 1\nequals(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: equals(variable, value) requires two arguments.\n"
"##:2: equals(variable, value) requires two arguments."
<< "##:1: equals(var, val) requires two arguments.\n"
"##:2: equals(var, val) requires two arguments."
<< true;
// That's just an alias, so don't test much.
@ -2240,8 +2240,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("versionAtLeast(): bad number of arguments")
<< "versionAtLeast(1): OK = 1\nversionAtLeast(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: versionAtLeast(variable, versionNumber) requires two arguments.\n"
"##:2: versionAtLeast(variable, versionNumber) requires two arguments."
<< "##:1: versionAtLeast(var, version) requires two arguments.\n"
"##:2: versionAtLeast(var, version) requires two arguments."
<< true;
QTest::newRow("versionAtMost(): true")
@ -2259,8 +2259,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("versionAtMost(): bad number of arguments")
<< "versionAtMost(1): OK = 1\nversionAtMost(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: versionAtMost(variable, versionNumber) requires two arguments.\n"
"##:2: versionAtMost(variable, versionNumber) requires two arguments."
<< "##:1: versionAtMost(var, version) requires two arguments.\n"
"##:2: versionAtMost(var, version) requires two arguments."
<< true;
QTest::newRow("clear(): top-level")
@ -2288,7 +2288,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("clear(): bad number of arguments")
<< "clear(1, 2): OK = 1"
<< "OK = UNDEF"
<< "##:1: clear(variable) requires one argument."
<< "##:1: clear(var) requires one argument."
<< true;
QTest::newRow("unset(): top-level")
@ -2316,7 +2316,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("unset(): bad number of arguments")
<< "unset(1, 2): OK = 1"
<< "OK = UNDEF"
<< "##:1: unset(variable) requires one argument."
<< "##:1: unset(var) requires one argument."
<< true;
// This function does not follow the established naming pattern.
@ -2362,8 +2362,8 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("parseJson(): bad number of arguments")
<< "parseJson(1): OK = 1\nparseJson(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: parseJson(variable, into) requires two arguments.\n"
"##:2: parseJson(variable, into) requires two arguments."
<< "##:1: parseJson(var, into) requires two arguments.\n"
"##:2: parseJson(var, into) requires two arguments."
<< true;
QTest::newRow("include()")
@ -2395,7 +2395,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("include(): bad number of arguments")
<< "include(1, 2, 3, 4): OK = 1"
<< "OK = UNDEF"
<< "##:1: include(file, [into, [silent]]) requires one, two or three arguments."
<< "##:1: include(file, [into, [silent]]) requires one to three arguments."
<< true;
QTest::newRow("load()")
@ -2419,7 +2419,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("load(): bad number of arguments")
<< "load(1, 2, 3): OK = 1"
<< "OK = UNDEF"
<< "##:1: load(feature) requires one or two arguments."
<< "##:1: load(feature, [ignore_errors=false]) requires one or two arguments."
<< true;
QTest::newRow("discard_from()")
@ -2668,7 +2668,7 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
QTest::newRow("mkpath(): bad number of arguments")
<< "mkpath(1, 2): OK = 1"
<< "OK = UNDEF"
<< "##:1: mkpath(file) requires one argument."
<< "##:1: mkpath(path) requires one argument."
<< true;
#if 0