implement qmake language and deprecation warnings

Change-Id: Ia5dd0c408ace4e779da898ffb60e9ca12a383225
Reviewed-by: Daniel Teske <daniel.teske@nokia.com>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
This commit is contained in:
Oswald Buddenhagen
2012-07-06 20:34:29 +02:00
parent 0af96c128a
commit a93e24fd0d
6 changed files with 85 additions and 32 deletions

View File

@@ -216,8 +216,11 @@ ProStringList QMakeEvaluator::evaluateExpandFunction(
if (func_t == 0) { if (func_t == 0) {
const QString &fn = func.toQString(m_tmp1); const QString &fn = func.toQString(m_tmp1);
const QString &lfn = fn.toLower(); const QString &lfn = fn.toLower();
if (!fn.isSharedWith(lfn)) if (!fn.isSharedWith(lfn)) {
func_t = ExpandFunc(statics.expands.value(ProString(lfn))); func_t = ExpandFunc(statics.expands.value(ProString(lfn)));
if (func_t)
deprecationWarning(fL1S("Using uppercased builtin functions is deprecated."));
}
} }
ProStringList ret; ProStringList ret;
@@ -974,23 +977,25 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
case T_INCLUDE: { case T_INCLUDE: {
if (m_skipLevel && !m_cumulative) if (m_skipLevel && !m_cumulative)
return ReturnFalse; return ReturnFalse;
QString parseInto; if (args.count() < 1 || args.count() > 3) {
// the third optional argument to include() controls warnings evalError(fL1S("include(file, [into, [silent]]) requires one, two or three arguments."));
// and is not used here
if ((args.count() == 2) || (args.count() == 3) ) {
parseInto = args.at(1).toQString(m_tmp2);
} else if (args.count() != 1) {
evalError(fL1S("include(file, into, silent) requires one, two or three arguments."));
return ReturnFalse; return ReturnFalse;
} }
QString parseInto;
LoadFlags flags = 0;
if (args.count() >= 2) {
parseInto = args.at(1).toQString(m_tmp2);
if (args.count() >= 3 && isTrue(args.at(2), m_tmp3))
flags = LoadSilent;
}
QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1))); QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
fn.detach(); fn.detach();
bool ok; bool ok;
if (parseInto.isEmpty()) { if (parseInto.isEmpty()) {
ok = evaluateFile(fn, QMakeHandler::EvalIncludeFile, LoadProOnly); ok = evaluateFile(fn, QMakeHandler::EvalIncludeFile, LoadProOnly | flags);
} else { } else {
ProValueMap symbols; ProValueMap symbols;
if ((ok = evaluateFileInto(fn, QMakeHandler::EvalAuxFile, &symbols, LoadAll))) { if ((ok = evaluateFileInto(fn, QMakeHandler::EvalAuxFile, &symbols, LoadAll | flags))) {
ProValueMap newMap; ProValueMap newMap;
for (ProValueMap::ConstIterator for (ProValueMap::ConstIterator
it = m_valuemapStack.top().constBegin(), it = m_valuemapStack.top().constBegin(),
@@ -1011,20 +1016,20 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
m_valuemapStack.top() = newMap; m_valuemapStack.top() = newMap;
} }
} }
return returnBool(ok); return returnBool(ok || (flags & LoadSilent));
} }
case T_LOAD: { case T_LOAD: {
if (m_skipLevel && !m_cumulative) if (m_skipLevel && !m_cumulative)
return ReturnFalse; return ReturnFalse;
// bool ignore_error = false; bool ignore_error = false;
if (args.count() == 2) { if (args.count() == 2) {
// ignore_error = isTrue(args.at(1), m_tmp2); ignore_error = isTrue(args.at(1), m_tmp2);
} else if (args.count() != 1) { } else if (args.count() != 1) {
evalError(fL1S("load(feature) requires one or two arguments.")); evalError(fL1S("load(feature) requires one or two arguments."));
return ReturnFalse; return ReturnFalse;
} }
// XXX ignore_error unused return returnBool(evaluateFeatureFile(m_option->expandEnvVars(args.at(0).toQString()),
return returnBool(evaluateFeatureFile(m_option->expandEnvVars(args.at(0).toQString()))); ignore_error) || ignore_error);
} }
case T_DEBUG: case T_DEBUG:
// Yup - do nothing. Nothing is going to enable debug output anyway. // Yup - do nothing. Nothing is going to enable debug output anyway.

View File

@@ -138,7 +138,11 @@ void QMakeEvaluator::initStatics()
const ProString &QMakeEvaluator::map(const ProString &var) const ProString &QMakeEvaluator::map(const ProString &var)
{ {
QHash<ProString, ProString>::ConstIterator it = statics.varMap.constFind(var); QHash<ProString, ProString>::ConstIterator it = statics.varMap.constFind(var);
return (it != statics.varMap.constEnd()) ? it.value() : var; if (it == statics.varMap.constEnd())
return var;
deprecationWarning(fL1S("Variable %s is deprecated; use %s instead.")
.arg(var.toQString(), it.value().toQString()));
return it.value();
} }
@@ -239,7 +243,8 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil
ushort unicode; ushort unicode;
const QChar *vals_data = vals.data(); const QChar *vals_data = vals.data();
const int vals_len = vals.length(); const int vals_len = vals.length();
for (int x = 0, parens = 0; x < vals_len; x++) { int parens = 0;
for (int x = 0; x < vals_len; x++) {
unicode = vals_data[x].unicode(); unicode = vals_data[x].unicode();
if (x != (int)vals_len-1 && unicode == BACKSLASH && if (x != (int)vals_len-1 && unicode == BACKSLASH &&
(vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) { (vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) {
@@ -263,6 +268,8 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil
} }
if (!build.isEmpty()) if (!build.isEmpty())
ret << ProString(build, NoHash).setSource(source); ret << ProString(build, NoHash).setSource(source);
if (parens)
deprecationWarning(fL1S("Unmatched parentheses are deprecated."));
return ret; return ret;
} }
@@ -780,6 +787,8 @@ void QMakeEvaluator::visitProVariable(
if (!m_cumulative) { if (!m_cumulative) {
if (!m_skipLevel) { if (!m_skipLevel) {
zipEmpty(&varVal); zipEmpty(&varVal);
// FIXME: add check+warning about accidental value removal.
// This may be a bit too noisy, though.
m_valuemapStack.top()[varName] = varVal; m_valuemapStack.top()[varName] = varVal;
} }
} else { } else {
@@ -1210,7 +1219,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
if (!processed.contains(config)) { if (!processed.contains(config)) {
config.detach(); config.detach();
processed.insert(config); processed.insert(config);
if (evaluateFeatureFile(config)) { if (evaluateFeatureFile(config, true)) {
finished = false; finished = false;
break; break;
} }
@@ -1892,6 +1901,8 @@ bool QMakeEvaluator::evaluateFileDirect(
#endif #endif
return ok; return ok;
} else { } else {
if (!(flags & LoadSilent) && IoUtils::exists(fileName))
languageWarning(fL1S("Include file %1 not found").arg(fileName));
return false; return false;
} }
} }
@@ -1909,7 +1920,7 @@ bool QMakeEvaluator::evaluateFile(
return evaluateFileDirect(fileName, type, flags); return evaluateFileDirect(fileName, type, flags);
} }
bool QMakeEvaluator::evaluateFeatureFile(const QString &fileName) bool QMakeEvaluator::evaluateFeatureFile(const QString &fileName, bool silent)
{ {
QString fn = fileName; QString fn = fileName;
if (!fn.endsWith(QLatin1String(".prf"))) if (!fn.endsWith(QLatin1String(".prf")))
@@ -1938,13 +1949,18 @@ bool QMakeEvaluator::evaluateFeatureFile(const QString &fileName)
if (QFileInfo(fn).exists()) if (QFileInfo(fn).exists())
goto cool; goto cool;
#endif #endif
if (!silent)
languageWarning(fL1S("Cannot find feature %1").arg(fileName));
return false; return false;
cool: cool:
ProStringList &already = valuesRef(ProString("QMAKE_INTERNAL_INCLUDED_FEATURES")); ProStringList &already = valuesRef(ProString("QMAKE_INTERNAL_INCLUDED_FEATURES"));
ProString afn(fn, NoHash); ProString afn(fn, NoHash);
if (already.contains(afn)) if (already.contains(afn)) {
if (!silent)
languageWarning(fL1S("Feature %1 already included").arg(fileName));
return true; return true;
}
already.append(afn); already.append(afn);
#ifdef PROEVALUATOR_CUMULATIVE #ifdef PROEVALUATOR_CUMULATIVE

View File

@@ -53,6 +53,9 @@ public:
enum { enum {
SourceEvaluator = 0x10, SourceEvaluator = 0x10,
EvalWarnLanguage = SourceEvaluator | WarningMessage | WarnLanguage,
EvalWarnDeprecated = SourceEvaluator | WarningMessage | WarnDeprecated,
EvalError = ErrorMessage | SourceEvaluator EvalError = ErrorMessage | SourceEvaluator
}; };
@@ -71,7 +74,8 @@ public:
LoadProOnly = 0, LoadProOnly = 0,
LoadPreFiles = 1, LoadPreFiles = 1,
LoadPostFiles = 2, LoadPostFiles = 2,
LoadAll = LoadPreFiles|LoadPostFiles LoadAll = LoadPreFiles|LoadPostFiles,
LoadSilent = 0x10
}; };
Q_DECLARE_FLAGS(LoadFlags, LoadFlag) Q_DECLARE_FLAGS(LoadFlags, LoadFlag)
@@ -120,7 +124,7 @@ public:
void visitProFunctionDef(ushort tok, const ProString &name, const ushort *tokPtr); void visitProFunctionDef(ushort tok, const ProString &name, const ushort *tokPtr);
void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr); void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
static const ProString &map(const ProString &var); const ProString &map(const ProString &var);
ProValueMap *findValues(const ProString &variableName, ProValueMap::Iterator *it); ProValueMap *findValues(const ProString &variableName, ProValueMap::Iterator *it);
void setTemplate(); void setTemplate();
@@ -139,13 +143,17 @@ public:
LoadFlags flags); LoadFlags flags);
bool evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type, bool evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
LoadFlags flags); LoadFlags flags);
bool evaluateFeatureFile(const QString &fileName); bool evaluateFeatureFile(const QString &fileName, bool silent = false);
bool evaluateFileInto(const QString &fileName, QMakeHandler::EvalFileType type, bool evaluateFileInto(const QString &fileName, QMakeHandler::EvalFileType type,
ProValueMap *values, // output-only ProValueMap *values, // output-only
LoadFlags flags); LoadFlags flags);
void message(int type, const QString &msg) const; void message(int type, const QString &msg) const;
void evalError(const QString &msg) const void evalError(const QString &msg) const
{ message(QMakeHandler::EvalError, msg); } { message(QMakeHandler::EvalError, msg); }
void languageWarning(const QString &msg) const
{ message(QMakeHandler::EvalWarnLanguage, msg); }
void deprecationWarning(const QString &msg) const
{ message(QMakeHandler::EvalWarnDeprecated, msg); }
QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr); QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
QList<ProStringList> prepareFunctionArgs(const ProString &arguments); QList<ProStringList> prepareFunctionArgs(const ProString &arguments);

View File

@@ -309,6 +309,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
int parens = 0; // Braces in value context int parens = 0; // Braces in value context
int argc = 0; int argc = 0;
int wordCount = 0; // Number of words in currently accumulated expression int wordCount = 0; // Number of words in currently accumulated expression
int lastIndent = 0; // Previous line's indentation, to detect accidental continuation abuse
bool putSpace = false; // Only ever true inside quoted string bool putSpace = false; // Only ever true inside quoted string
bool lineMarked = true; // For in-expression markers bool lineMarked = true; // For in-expression markers
ushort needSep = TokNewStr; // Complementary to putSpace: separator outside quotes ushort needSep = TokNewStr; // Complementary to putSpace: separator outside quotes
@@ -372,7 +373,8 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
ushort c; ushort c;
// First, skip leading whitespace // First, skip leading whitespace
for (;; ++cur) { int indent;
for (indent = 0; ; ++cur, ++indent) {
c = *cur; c = *cur;
if (c == '\n') { if (c == '\n') {
++cur; ++cur;
@@ -556,12 +558,14 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
needSep = 0; needSep = 0;
goto nextChr; goto nextChr;
} }
} else if (c == '\\' && cur != end) { } else if (c == '\\') {
static const char symbols[] = "[]{}()$\\'\""; static const char symbols[] = "[]{}()$\\'\"";
ushort c2 = *cur; ushort c2;
if (!(c2 & 0xff00) && strchr(symbols, c2)) { if (cur != end && !((c2 = *cur) & 0xff00) && strchr(symbols, c2)) {
c = c2; c = c2;
cur++; cur++;
} else {
deprecationWarning(fL1S("Unescaped backslashes are deprecated"));
} }
} else if (quote) { } else if (quote) {
if (c == quote) { if (c == quote) {
@@ -722,6 +726,9 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
goto closeScope; goto closeScope;
} }
--parens; --parens;
} else if (c == '=') {
if (indent < lastIndent)
languageWarning(fL1S("Possible accidental line continuation"));
} }
} }
if (putSpace) { if (putSpace) {
@@ -771,6 +778,8 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
} }
} else if (context == CtxValue) { } else if (context == CtxValue) {
FLUSH_VALUE_LIST(); FLUSH_VALUE_LIST();
if (parens)
languageWarning(fL1S("Possible braces mismatch"));
} else { } else {
finalizeCond(tokPtr, buf, ptr, wordCount); finalizeCond(tokPtr, buf, ptr, wordCount);
} }
@@ -780,6 +789,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
goto freshLine; goto freshLine;
} }
lastIndent = indent;
lineMarked = false; lineMarked = false;
ignore: ignore:
cur = cptr; cur = cptr;

View File

@@ -46,11 +46,19 @@ class QMAKE_EXPORT QMakeParserHandler
public: public:
enum { enum {
CategoryMask = 0xf00, CategoryMask = 0xf00,
WarningMessage = 0x000,
ErrorMessage = 0x100, ErrorMessage = 0x100,
SourceMask = 0xf0, SourceMask = 0xf0,
SourceParser = 0, SourceParser = 0,
CodeMask = 0xf,
WarnLanguage = 0,
WarnDeprecated,
ParserWarnLanguage = SourceParser | WarningMessage | WarnLanguage,
ParserWarnDeprecated = SourceParser | WarningMessage | WarnDeprecated,
ParserIoError = ErrorMessage | SourceParser, ParserIoError = ErrorMessage | SourceParser,
ParserError ParserError
}; };
@@ -123,6 +131,10 @@ private:
void message(int type, const QString &msg) const; void message(int type, const QString &msg) const;
void parseError(const QString &msg) const void parseError(const QString &msg) const
{ message(QMakeParserHandler::ParserError, msg); } { message(QMakeParserHandler::ParserError, msg); }
void languageWarning(const QString &msg) const
{ message(QMakeParserHandler::ParserWarnLanguage, msg); }
void deprecationWarning(const QString &msg) const
{ message(QMakeParserHandler::ParserWarnDeprecated, msg); }
// Current location // Current location
ProFile *m_proFile; ProFile *m_proFile;

View File

@@ -43,18 +43,20 @@
#include <QStringList> #include <QStringList>
#include <QTextCodec> #include <QTextCodec>
static void print(const QString &fileName, int lineNo, const QString &msg) static void print(const QString &fileName, int lineNo, int type, const QString &msg)
{ {
QString pfx = ((type & QMakeHandler::CategoryMask) == QMakeHandler::WarningMessage)
? QString::fromLatin1("WARNING: ") : QString();
if (lineNo) if (lineNo)
qWarning("%s(%d): %s", qPrintable(fileName), lineNo, qPrintable(msg)); qWarning("%s%s:%d: %s", qPrintable(pfx), qPrintable(fileName), lineNo, qPrintable(msg));
else else
qWarning("%s", qPrintable(msg)); qWarning("%s%s", qPrintable(pfx), qPrintable(msg));
} }
class EvalHandler : public QMakeHandler { class EvalHandler : public QMakeHandler {
public: public:
virtual void message(int /* type */, const QString &msg, const QString &fileName, int lineNo) virtual void message(int type, const QString &msg, const QString &fileName, int lineNo)
{ print(fileName, lineNo, msg); } { print(fileName, lineNo, type, msg); }
virtual void fileMessage(const QString &msg) virtual void fileMessage(const QString &msg)
{ qWarning("%s", qPrintable(msg)); } { qWarning("%s", qPrintable(msg)); }