From ad17a35853fe21a93fc34f7b2d9262c5ac992b29 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 13 May 2016 15:32:50 +0200 Subject: [PATCH] make QMakeParser take a QStringRef as input the only place where this actually saves a deep copy is the evaluation of if(), but as a side effect the parser is now able to deal with not null-terminated strings, which is kinda nice as well. Change-Id: Ib6d08617aa79d2f9eaecd4906d4d548f34bf377d Reviewed-by: Joerg Bornemann Reviewed-by: Oswald Buddenhagen --- qmake/library/qmakebuiltins.cpp | 5 ++-- qmake/library/qmakeevaluator.cpp | 6 ++-- qmake/library/qmakeevaluator.h | 2 +- qmake/library/qmakeparser.cpp | 36 +++++++++++++----------- qmake/library/qmakeparser.h | 6 ++-- qmake/project.cpp | 3 +- qmake/project.h | 2 +- tests/auto/tools/qmakelib/evaltest.cpp | 4 +-- tests/auto/tools/qmakelib/parsertest.cpp | 2 +- 9 files changed, 35 insertions(+), 31 deletions(-) diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index 9d35a31ffc..c5ea26977e 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -1210,7 +1210,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; // Another qmake breakage case T_EVAL: { VisitReturn ret = ReturnFalse; - ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), + QString contents = args.join(statics.field_sep); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents), m_current.pro->fileName(), m_current.line); if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current); @@ -1226,7 +1227,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( evalError(fL1S("if(condition) requires one argument.")); return ReturnFalse; } - return returnBool(evaluateConditional(args.at(0).toQString(), + return returnBool(evaluateConditional(args.at(0).toQStringRef(), m_current.pro->fileName(), m_current.line)); } case T_CONFIG: { diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 4ce7b0c4b8..6182e4bf3e 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -1277,7 +1277,7 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { if (!cmds.isEmpty()) { - ProFile *pro = m_parser->parsedProBlock(cmds, where, -1); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1); if (pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1760,7 +1760,7 @@ ProStringList QMakeEvaluator::evaluateExpandFunction( return ProStringList(); } -bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line) +bool QMakeEvaluator::evaluateConditional(const QStringRef &cond, const QString &where, int line) { bool ret = false; ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); @@ -1778,7 +1778,7 @@ void QMakeEvaluator::checkRequirements(const ProStringList &deps) { ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS")); for (const ProString &dep : deps) - if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line)) + if (!evaluateConditional(dep.toQStringRef(), m_current.pro->fileName(), m_current.line)) failed << dep; } #endif diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h index 8a87108c91..48dd631b19 100644 --- a/qmake/library/qmakeevaluator.h +++ b/qmake/library/qmakeevaluator.h @@ -216,7 +216,7 @@ public: ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args); VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args); - bool evaluateConditional(const QString &cond, const QString &where, int line = -1); + bool evaluateConditional(const QStringRef &cond, const QString &where, int line = -1); #ifdef PROEVALUATOR_FULL void checkRequirements(const ProStringList &deps); #endif diff --git a/qmake/library/qmakeparser.cpp b/qmake/library/qmakeparser.cpp index 2a48103147..90bc64bd2b 100644 --- a/qmake/library/qmakeparser.cpp +++ b/qmake/library/qmakeparser.cpp @@ -224,7 +224,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) } ProFile *QMakeParser::parsedProBlock( - const QString &contents, const QString &name, int line, SubGrammar grammar) + const QStringRef &contents, const QString &name, int line, SubGrammar grammar) { ProFile *pro = new ProFile(name); read(pro, contents, line, grammar); @@ -247,7 +247,7 @@ bool QMakeParser::read(ProFile *pro, ParseFlags flags) fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); return false; } - read(pro, content, 1, FullGrammar); + read(pro, QStringRef(&content), 1, FullGrammar); return true; } @@ -289,7 +289,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len) buf[-2] = (ushort)(hash >> 16); } -void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar) +void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar grammar) { m_proFile = pro; m_lineNo = line; @@ -334,8 +334,8 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra QStack xprStack; xprStack.reserve(10); - // We rely on QStrings being null-terminated, so don't maintain a global end pointer. const ushort *cur = (const ushort *)in.unicode(); + const ushort *inend = cur + in.length(); m_canElse = false; freshLine: m_state = StNew; @@ -418,7 +418,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra int indent; if (context == CtxPureValue) { - end = (const ushort *)in.unicode() + in.length(); + end = inend; cptr = 0; lineCont = false; indent = 0; // just gcc being stupid @@ -430,24 +430,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra // First, skip leading whitespace for (indent = 0; ; ++cur, ++indent) { + if (cur == inend) { + cur = 0; + goto flushLine; + } c = *cur; if (c == '\n') { ++cur; goto flushLine; - } else if (!c) { - cur = 0; - goto flushLine; - } else if (c != ' ' && c != '\t' && c != '\r') { - break; } + if (c != ' ' && c != '\t' && c != '\r') + break; } // Then strip comments. Yep - no escaping is possible. for (cptr = cur;; ++cptr) { + if (cptr == inend) { + end = cptr; + break; + } c = *cptr; if (c == '#') { - for (end = cptr; (c = *++cptr);) { - if (c == '\n') { + end = cptr; + while (++cptr < inend) { + if (*cptr == '\n') { ++cptr; break; } @@ -460,10 +466,6 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra } break; } - if (!c) { - end = cptr; - break; - } if (c == '\n') { end = cptr++; break; @@ -1215,7 +1217,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ushort **buf, QString *xprBuff, ushort **tokPtr, QString *tokBuff, - const ushort *cur, const QString &in) + const ushort *cur, const QStringRef &in) { QString out; m_tmp.setRawData((const QChar *)xprPtr, tlen); diff --git a/qmake/library/qmakeparser.h b/qmake/library/qmakeparser.h index f78b3215bb..f8ff2fc3cc 100644 --- a/qmake/library/qmakeparser.h +++ b/qmake/library/qmakeparser.h @@ -87,7 +87,7 @@ public: enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); - ProFile *parsedProBlock(const QString &contents, const QString &name, int line = 0, + ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0, SubGrammar grammar = FullGrammar); void discardFileFromCache(const QString &fileName); @@ -130,7 +130,7 @@ private: }; bool read(ProFile *pro, ParseFlags flags); - void read(ProFile *pro, const QString &content, int line, SubGrammar grammar); + void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len); @@ -141,7 +141,7 @@ private: ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ushort **buf, QString *xprBuff, ushort **tokPtr, QString *tokBuff, - const ushort *cur, const QString &in); + const ushort *cur, const QStringRef &in); void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount); void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc); void warnOperator(const char *msg); diff --git a/qmake/project.cpp b/qmake/project.cpp index 01adb7422c..28a6c72a46 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -120,7 +120,8 @@ QStringList QMakeProject::expand(const ProKey &func, const QList ProString QMakeProject::expand(const QString &expr, const QString &where, int line) { ProString ret; - ProFile *pro = m_parser->parsedProBlock(expr, where, line, QMakeParser::ValueGrammar); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&expr), where, line, + QMakeParser::ValueGrammar); if (pro->isOk()) { m_current.pro = pro; m_current.line = 0; diff --git a/qmake/project.h b/qmake/project.h index 9f3b9a56bc..4986c7c82d 100644 --- a/qmake/project.h +++ b/qmake/project.h @@ -55,7 +55,7 @@ public: ProString expand(const QString &v, const QString &file, int line); QStringList expand(const ProKey &func, const QList &args); bool test(const QString &v, const QString &file, int line) - { m_current.clear(); return evaluateConditional(v, file, line); } + { m_current.clear(); return evaluateConditional(QStringRef(&v), file, line); } bool test(const ProKey &func, const QList &args); bool isSet(const ProKey &v) const { return m_valuemapStack.first().contains(v); } diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp index aaa4bb3724..4642c822bc 100644 --- a/tests/auto/tools/qmakelib/evaltest.cpp +++ b/tests/auto/tools/qmakelib/evaltest.cpp @@ -2477,12 +2477,12 @@ void tst_qmakelib::proEval() globals.environment = m_env; globals.setProperties(m_prop); globals.setDirectories(m_indir, m_outdir); - ProFile *outPro = parser.parsedProBlock(out, "out", 1, QMakeParser::FullGrammar); + ProFile *outPro = parser.parsedProBlock(QStringRef(&out), "out", 1, QMakeParser::FullGrammar); if (!outPro->isOk()) { qWarning("Expected output is malformed"); verified = false; } - ProFile *pro = parser.parsedProBlock(in, infile, 1, QMakeParser::FullGrammar); + ProFile *pro = parser.parsedProBlock(QStringRef(&in), infile, 1, QMakeParser::FullGrammar); QMakeEvaluator visitor(&globals, &parser, &vfs, &handler); visitor.setOutputDir(m_outdir); #ifdef Q_OS_WIN diff --git a/tests/auto/tools/qmakelib/parsertest.cpp b/tests/auto/tools/qmakelib/parsertest.cpp index 5f345617db..6857334746 100644 --- a/tests/auto/tools/qmakelib/parsertest.cpp +++ b/tests/auto/tools/qmakelib/parsertest.cpp @@ -1955,7 +1955,7 @@ void tst_qmakelib::proParser() handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts)); QMakeVfs vfs; QMakeParser parser(0, &vfs, &handler); - ProFile *pro = parser.parsedProBlock(in, "in", 1, QMakeParser::FullGrammar); + ProFile *pro = parser.parsedProBlock(QStringRef(&in), "in", 1, QMakeParser::FullGrammar); if (handler.printedMessages()) { qWarning("Got unexpected message(s)"); verified = false;