Skip to content
Snippets Groups Projects
Commit dcb96227 authored by Oswald Buddenhagen's avatar Oswald Buddenhagen
Browse files

implement actual evaluation of conditions.

without that, the auto-included highly complex files from mkspecs/ make
it spew out oodles of warnings.
by default, the user-provided files are still scanned in "cumulative"
mode (ignoring conditionals), so we collect as many files as possible.
(ported from qt)
parent da348854
No related branches found
No related tags found
No related merge requests found
......@@ -131,6 +131,12 @@ class ProFileEvaluator::Private : public AbstractProItemVisitor
public:
Private(ProFileEvaluator *q_);
ProFileEvaluator *q;
int m_lineNo; // Error reporting
bool m_verbose;
/////////////// Reading pro file
bool read(ProFile *pro);
ProBlock *currentBlock();
......@@ -143,6 +149,17 @@ public:
void leaveScope();
void finalizeBlock();
QStack<ProBlock *> m_blockstack;
ProBlock *m_block;
ProItem *m_commentItem;
QString m_proitem;
QString m_pendingComment;
bool m_syntaxError;
bool m_contNextLine;
/////////////// Evaluating pro file contents
// implementation of AbstractProItemVisitor
bool visitBeginProBlock(ProBlock *block);
bool visitEndProBlock(ProBlock *block);
......@@ -180,21 +197,16 @@ public:
QStringList qmakeFeaturePaths();
ProFileEvaluator *q;
QStack<ProBlock *> m_blockstack;
ProBlock *m_block;
ProItem *m_commentItem;
QString m_proitem;
QString m_pendingComment;
bool m_syntaxError;
bool m_contNextLine;
bool m_condition;
enum { ConditionTrue, ConditionFalse, ConditionElse };
int m_condition;
int m_prevCondition;
bool m_updateCondition;
bool m_invertNext;
int m_skipLevel;
bool m_cumulative;
QString m_lastVarName;
ProVariable::VariableOperator m_variableOperator;
int m_lineNo; // Error reporting
QString m_origfile;
QString m_oldPath; // To restore the current path to the path
QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri'
......@@ -202,12 +214,9 @@ public:
QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file
QHash<QString, QString> m_properties;
QString m_outputDir;
QString m_origfile;
int m_prevLineNo; // Checking whether we're assigning the same TARGET
ProFile *m_prevProFile; // See m_prevLineNo
bool m_verbose;
};
ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
......@@ -221,6 +230,11 @@ ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
m_syntaxError = 0;
m_lineNo = 0;
m_contNextLine = false;
m_cumulative = true;
m_updateCondition = false;
m_condition = ConditionFalse;
m_invertNext = false;
m_skipLevel = 0;
}
bool ProFileEvaluator::Private::read(ProFile *pro)
......@@ -512,15 +526,25 @@ void ProFileEvaluator::Private::updateItem()
bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
{
if (block->blockKind() == ProBlock::ScopeKind) {
m_invertNext = false;
m_condition = false;
m_updateCondition = true;
if (!m_skipLevel) {
m_prevCondition = m_condition;
m_condition = ConditionFalse;
}
} else if (block->blockKind() & ProBlock::ScopeContentsKind) {
m_updateCondition = false;
if (m_condition != ConditionTrue)
++m_skipLevel;
}
return true;
}
bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block)
{
Q_UNUSED(block);
if (block->blockKind() & ProBlock::ScopeContentsKind) {
if (m_skipLevel)
--m_skipLevel;
}
return true;
}
......@@ -546,12 +570,16 @@ bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
{
if (!m_condition) {
if (m_invertNext)
m_condition |= !isActiveConfig(cond->text(), true);
else
m_condition |= isActiveConfig(cond->text(), true);
if (!m_skipLevel) {
if (cond->text().toLower() == QLatin1String("else")) {
if (m_prevCondition == ConditionTrue)
m_condition = ConditionElse;
} else if (m_condition == ConditionFalse) {
if (isActiveConfig(cond->text(), true) ^ m_invertNext)
m_condition = ConditionTrue;
}
}
m_invertNext = false;
return true;
}
......@@ -574,10 +602,13 @@ bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
if (!mkspecDirectory.isEmpty()) {
bool cumulative = m_cumulative;
m_cumulative = false;
// This is what qmake does, everything set in the mkspec is also set
// But this also creates a lot of problems
evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf"), &ok);
evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf"), &ok);
m_cumulative = cumulative;
}
QString fn = pro->fileName();
......@@ -595,6 +626,9 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) {
const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
if (!mkspecDirectory.isEmpty()) {
bool cumulative = m_cumulative;
m_cumulative = false;
evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf"), &ok);
QSet<QString> processed;
......@@ -616,6 +650,8 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
if (finished)
break;
}
m_cumulative = cumulative;
}
m_profileStack.pop();
......@@ -624,6 +660,24 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
return ok;
}
static void replaceInList(QStringList *varlist,
const QRegExp &regexp, const QString &replace, bool global)
{
for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
if ((*varit).contains(regexp)) {
(*varit).replace(regexp, replace);
if ((*varit).isEmpty())
varit = varlist->erase(varit);
else
++varit;
if(!global)
break;
} else {
++varit;
}
}
}
bool ProFileEvaluator::Private::visitProValue(ProValue *value)
{
PRE(value);
......@@ -675,37 +729,53 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value)
}
switch (m_variableOperator) {
case ProVariable::UniqueAddOperator: // *
insertUnique(&m_valuemap, varName, v, true);
insertUnique(&m_filevaluemap[currentProFile()], varName, v, true);
break;
case ProVariable::SetOperator: // =
case ProVariable::AddOperator: // +
insertUnique(&m_valuemap, varName, v, false);
insertUnique(&m_filevaluemap[currentProFile()], varName, v, false);
if (!m_cumulative) {
if (!m_skipLevel) {
m_valuemap[varName] = v;
m_filevaluemap[currentProFile()][varName] = v;
}
} else {
// We are greedy for values.
m_valuemap[varName] += v;
m_filevaluemap[currentProFile()][varName] += v;
}
break;
case ProVariable::RemoveOperator: // -
// fix me: interaction between AddOperator and RemoveOperator
insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false);
insertUnique(&m_filevaluemap[currentProFile()],
varName.prepend(QLatin1Char('-')), v, false);
case ProVariable::UniqueAddOperator: // *=
if (!m_skipLevel || m_cumulative) {
insertUnique(&m_valuemap, varName, v);
insertUnique(&m_filevaluemap[currentProFile()], varName, v);
}
break;
case ProVariable::ReplaceOperator: // ~
case ProVariable::AddOperator: // +=
if (!m_skipLevel || m_cumulative) {
m_valuemap[varName] += v;
m_filevaluemap[currentProFile()][varName] += v;
}
break;
case ProVariable::RemoveOperator: // -=
if (!m_cumulative) {
if (!m_skipLevel) {
removeEach(&m_valuemap, varName, v);
removeEach(&m_filevaluemap[currentProFile()], varName, v);
}
} else {
// We are stingy with our values, too.
}
break;
case ProVariable::ReplaceOperator: // ~=
{
// DEFINES ~= s/a/b/?[gqi]
/* Create a superset by executing replacement + adding items that have changed
to original list. We're not sure if this is really the right approach, so for
the time being we will just do nothing ...
// FIXME: qmake variable-expands val first.
if (val.length() < 4 || val[0] != QLatin1Char('s')) {
q->logMessage(format("the ~= operator can handle only the s/// function."));
return false;
}
QChar sep = val.at(1);
QStringList func = val.split(sep);
if (func.count() < 3 || func.count() > 4) {
q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments."));
return false;
}
if (func[0] != QLatin1String("s")) {
q->logMessage(format("~= operator can only handle s/// function."));
q->logMessage(format("the s/// function expects 3 or 4 arguments."));
return false;
}
......@@ -722,19 +792,12 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value)
QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace,
global);
// Add changed entries to list
foreach (const QString &entry, replaceList)
if (!m_valuemap.value(varName).contains(entry))
insertUnique(&m_valuemap, varName, QStringList() << entry, false);
replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp,
replace, global);
foreach (const QString &entry, replaceList)
if (!m_filevaluemap[currentProFile()].value(varName).contains(entry))
insertUnique(&m_filevaluemap[currentProFile()], varName,
QStringList() << entry, false); */
if (!m_skipLevel || m_cumulative) {
// We could make a union of modified and unmodified values,
// but this will break just as much as it fixes, so leave it as is.
replaceInList(&m_valuemap[varName], regexp, replace, global);
replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global);
}
}
break;
......@@ -744,18 +807,22 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value)
bool ProFileEvaluator::Private::visitProFunction(ProFunction *func)
{
m_lineNo = func->lineNumber();
bool result = true;
bool ok = true;
QString text = func->text();
int lparen = text.indexOf(QLatin1Char('('));
int rparen = text.lastIndexOf(QLatin1Char(')'));
QTC_ASSERT(lparen < rparen, return false);
QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
QString funcName = text.left(lparen);
ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result);
return ok;
if (!m_skipLevel && (!m_updateCondition || m_condition == ConditionFalse)) {
QString text = func->text();
int lparen = text.indexOf(QLatin1Char('('));
int rparen = text.lastIndexOf(QLatin1Char(')'));
QTC_ASSERT(lparen < rparen, return false);
QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
QString funcName = text.left(lparen);
m_lineNo = func->lineNumber();
bool result = false;
if (!evaluateConditionalFunction(funcName.trimmed(), arguments, &result))
return false;
if (result ^ m_invertNext)
m_condition = ConditionTrue;
}
m_invertNext = false;
return true;
}
......@@ -2083,18 +2150,20 @@ void ProFileEvaluator::addProperties(const QHash<QString, QString> &properties)
void ProFileEvaluator::logMessage(const QString &message)
{
if (d->m_verbose)
if (d->m_verbose && !d->m_skipLevel)
qWarning("%s", qPrintable(message));
}
void ProFileEvaluator::fileMessage(const QString &message)
{
qWarning("%s", qPrintable(message));
if (!d->m_skipLevel)
qWarning("%s", qPrintable(message));
}
void ProFileEvaluator::errorMessage(const QString &message)
{
qWarning("%s", qPrintable(message));
if (!d->m_skipLevel)
qWarning("%s", qPrintable(message));
}
// This function is unneeded and still retained. See log message for reason.
......@@ -2116,6 +2185,11 @@ void ProFileEvaluator::setVerbose(bool on)
d->m_verbose = on;
}
void ProFileEvaluator::setCumulative(bool on)
{
d->m_cumulative = on;
}
void ProFileEvaluator::setOutputDir(const QString &dir)
{
d->m_outputDir = dir;
......
......@@ -69,6 +69,7 @@ public:
QStringList absFileNames(const QString &variableName);
QStringList absFileName(const QString &name);
void setVerbose(bool on); // Default is false
void setCumulative(bool on); // Default is true!
void setOutputDir(const QString &dir); // Default is empty
bool queryProFile(ProFile *pro);
......
......@@ -132,17 +132,20 @@ static void unquote(QString *string)
}
static void insertUnique(QHash<QString, QStringList> *map,
const QString &key, const QStringList &value, bool unique = true)
const QString &key, const QStringList &value)
{
QStringList &sl = (*map)[key];
if (!unique) {
sl += value;
} else {
for (int i = 0; i < value.count(); ++i) {
if (!sl.contains(value.at(i)))
sl.append(value.at(i));
}
}
foreach (const QString &str, value)
if (!sl.contains(str))
sl.append(str);
}
static void removeEach(QHash<QString, QStringList> *map,
const QString &key, const QStringList &value)
{
QStringList &sl = (*map)[key];
foreach (const QString &str, value)
sl.removeAll(str);
}
/*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment