From 014571b602f077e0d8575816bafc9d1bea97871a Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 13 May 2011 20:20:41 +0200 Subject: [PATCH] improve value source tracking - use the current file if a value is generated "out of nowhere" - preserve source through function calls Task-number: QTCREATORBUG-4897 --- src/shared/proparser/profileevaluator.cpp | 45 ++++++++++++++--------- src/shared/proparser/proitems.cpp | 11 ++++++ src/shared/proparser/proitems.h | 5 ++- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 3115f31f637..890bc7dd121 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -222,7 +222,7 @@ public: ProStringList values(const ProString &variableName) const; QString propertyValue(const QString &val, bool complain) const; - static ProStringList split_value_list(const QString &vals); + ProStringList split_value_list(const QString &vals, const ProFile *source = 0); bool isActiveConfig(const QString &config, bool regex = false); ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false); ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false); @@ -557,7 +557,7 @@ void ProFileEvaluator::Private::skipHashStr(const ushort *&tokPtr) // FIXME: this should not build new strings for direct sections. // Note that the E_SPRINTF and E_LIST implementations rely on the deep copy. -ProStringList ProFileEvaluator::Private::split_value_list(const QString &vals) +ProStringList ProFileEvaluator::Private::split_value_list(const QString &vals, const ProFile *source) { QString build; ProStringList ret; @@ -570,6 +570,9 @@ ProStringList ProFileEvaluator::Private::split_value_list(const QString &vals) const ushort DOUBLEQUOTE = '"'; const ushort BACKSLASH = '\\'; + if (!source) + source = currentProFile(); + ushort unicode; const QChar *vals_data = vals.data(); const int vals_len = vals.length(); @@ -589,14 +592,14 @@ ProStringList ProFileEvaluator::Private::split_value_list(const QString &vals) } if (!parens && quote.isEmpty() && vals_data[x] == SPACE) { - ret << ProString(build, NoHash); + ret << ProString(build, NoHash).setSource(source); build.clear(); } else { build += vals_data[x]; } } if (!build.isEmpty()) - ret << ProString(build, NoHash); + ret << ProString(build, NoHash).setSource(source); return ret; } @@ -639,7 +642,7 @@ static void replaceInList(ProStringList *varlist, if (val.isEmpty()) { varit = varlist->erase(varit); } else { - *varit = ProString(val); + (*varit).setValue(val, NoHash); ++varit; } if (!global) @@ -762,7 +765,8 @@ void ProFileEvaluator::Private::evaluateExpression( break; case TokProperty: addStr(ProString(propertyValue( - getStr(tokPtr).toQString(m_tmp1), true), NoHash), ret, pending, joined); + getStr(tokPtr).toQString(m_tmp1), true), NoHash).setSource(currentProFile()), + ret, pending, joined); break; case TokEnvVar: addStrList(split_value_list(m_option->getEnv(getStr(tokPtr).toQString(m_tmp1))), @@ -2145,12 +2149,12 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( QRegExp sepRx(sep); foreach (const ProString &str, values(map(var))) { const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end); - ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash)); + ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash).setSource(str)); } } else { foreach (const ProString &str, values(map(var))) { const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end); - ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash)); + ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash).setSource(str)); } } } @@ -2180,8 +2184,15 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( if (args.count() == 4) after = args[3]; const ProStringList &var = values(map(args.at(0))); - if (!var.isEmpty()) - ret.append(ProString(before + var.join(glue) + after, NoHash)); + if (!var.isEmpty()) { + const ProFile *src = currentProFile(); + foreach (const ProString &v, var) + if (const ProFile *s = v.sourceFile()) { + src = s; + break; + } + ret.append(ProString(before + var.join(glue) + after, NoHash).setSource(src)); + } } break; } @@ -2192,7 +2203,7 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep; foreach (const ProString &var, values(map(args.at(0)))) foreach (const QString &splt, var.toQString(m_tmp2).split(sep)) - ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt, NoHash)); + ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt, NoHash).setSource(var)); } break; case E_MEMBER: @@ -2310,7 +2321,7 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( ret = ProStringList(ProString(tmp, NoHash)); ProStringList lst; foreach (const ProString &arg, args) - lst += split_value_list(arg.toQString(m_tmp1)); // Relies on deep copy + lst += split_value_list(arg.toQString(m_tmp1), arg.sourceFile()); // Relies on deep copy m_valuemapStack.top()[ret.at(0)] = lst; break; } case E_FIND: @@ -2405,13 +2416,13 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( } } } - ret.append(ProString(QString(i_data, i_len), NoHash)); + ret.append(ProString(QString(i_data, i_len), NoHash).setSource(args.at(i))); } break; case E_RE_ESCAPE: for (int i = 0; i < args.size(); ++i) { const QString &rstr = QRegExp::escape(args.at(i).toQString(m_tmp1)); - ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash)); + ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash).setSource(args.at(i))); } break; case E_UPPER: @@ -2419,7 +2430,7 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( for (int i = 0; i < args.count(); ++i) { QString rstr = args.at(i).toQString(m_tmp1); rstr = (func_t == E_UPPER) ? rstr.toUpper() : rstr.toLower(); - ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash)); + ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash).setSource(args.at(i))); } break; case E_FILES: @@ -2459,7 +2470,7 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( dirs.append(fname + QDir::separator()); } if (regex.exactMatch(qdir[i])) - ret += ProString(fname, NoHash); + ret += ProString(fname, NoHash).setSource(currentProFile()); } } } @@ -2474,7 +2485,7 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction( QString rstr = val.toQString(m_tmp1); QString copy = rstr; // Force a detach on modify rstr.replace(before, after); - ret << (rstr.isSharedWith(m_tmp1) ? val : ProString(rstr, NoHash)); + ret << (rstr.isSharedWith(m_tmp1) ? val : ProString(rstr, NoHash).setSource(val)); } } break; diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 7886b6ec4f9..0b65126016f 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -105,6 +105,17 @@ ProString::ProString(const QString &str, int offset, int length, ProStringConsta { } +void ProString::setValue(const QString &str) +{ + m_string = str, m_offset = 0, m_length = str.length(); + updatedHash(); +} + +void ProString::setValue(const QString &str, OmitPreHashing) +{ + m_string = str, m_offset = 0, m_length = str.length(), m_hash = 0x80000000; +} + uint ProString::updatedHash() const { return (m_hash = hash(m_string.constData() + m_offset, m_length)); diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index d911a837a6a..9a77ae8b386 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -71,7 +71,10 @@ public: ProString(const QString &str, int offset, int length); ProString(const QString &str, int offset, int length, uint hash); ProString(const QString &str, int offset, int length, ProStringConstants::OmitPreHashing); - void setSource(const ProFile *pro) { m_file = pro; } + void setValue(const QString &str); + void setValue(const QString &str, ProStringConstants::OmitPreHashing); + ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; } + ProString &setSource(const ProFile *pro) { m_file = pro; return *this; } const ProFile *sourceFile() const { return m_file; } QString toQString() const; QString &toQString(QString &tmp) const;