QmakeProjectManager: Improve renaming functionality

This was implemented rather sloppily: The file was removed from all
variables, but only added to one. Also, no care was taken to insert the
new file name into the same block the old one was removed from.

Fixes: QTCREATORBUG-19257
Change-Id: Ib309389ba7647189112d5c7dd7b3e784f921d2c3
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Christian Kandeler
2019-10-29 17:11:00 +01:00
parent 5e4d13f343
commit 03a52b9c87
4 changed files with 75 additions and 42 deletions

View File

@@ -638,8 +638,7 @@ bool QmakePriFile::canRenameFile(const QString &filePath, const QString &newFile
if (changeProFileOptional) if (changeProFileOptional)
return true; return true;
const Utils::MimeType mt = Utils::mimeTypeForFile(newFilePath); return renameFile(filePath, newFilePath, Change::TestOnly);
return renameFile(filePath, newFilePath, mt.name(), Change::TestOnly);
} }
bool QmakePriFile::renameFile(const QString &filePath, const QString &newFilePath) bool QmakePriFile::renameFile(const QString &filePath, const QString &newFilePath)
@@ -648,9 +647,7 @@ bool QmakePriFile::renameFile(const QString &filePath, const QString &newFilePat
return false; return false;
bool changeProFileOptional = deploysFolder(QFileInfo(filePath).absolutePath()); bool changeProFileOptional = deploysFolder(QFileInfo(filePath).absolutePath());
const Utils::MimeType mt = Utils::mimeTypeForFile(newFilePath); if (renameFile(filePath, newFilePath, Change::Save))
if (renameFile(filePath, newFilePath, mt.name()))
return true; return true;
return changeProFileOptional; return changeProFileOptional;
} }
@@ -806,10 +803,7 @@ bool QmakePriFile::prepareForChange()
return saveModifiedEditors() && ensureWriteableProFile(filePath().toString()); return saveModifiedEditors() && ensureWriteableProFile(filePath().toString());
} }
bool QmakePriFile::renameFile(const QString &oldName, bool QmakePriFile::renameFile(const QString &oldName, const QString &newName, Change mode)
const QString &newName,
const QString &mimeType,
Change mode)
{ {
if (!prepareForChange()) if (!prepareForChange())
return false; return false;
@@ -822,27 +816,46 @@ bool QmakePriFile::renameFile(const QString &oldName,
return false; return false;
QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString()); QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString());
QStringList notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir, ProWriter::VarLocations removedLocations;
QStringList(oldName), varNamesForRemoving()); const QStringList notChanged = ProWriter::removeFiles(
includeFile,
&lines,
priFileDir,
QStringList(oldName),
varNamesForRemoving(),
&removedLocations
);
includeFile->deref(); includeFile->deref();
if (!notChanged.isEmpty()) if (!notChanged.isEmpty())
return false; return false;
QTC_ASSERT(!removedLocations.isEmpty(), return false);
// We need to re-parse here: The file has changed. int endLine = lines.count();
QMakeParser parser(nullptr, nullptr, nullptr); reverseForeach(removedLocations,
QString contents = lines.join(QLatin1Char('\n')); [this, &newName, &lines, &endLine](const ProWriter::VarLocation &loc) {
includeFile = parser.parsedProBlock(QStringRef(&contents), QStringList currentLines = lines.mid(loc.second, endLine - loc.second);
0, filePath().toString(), 1, QMakeParser::FullGrammar); const QString currentContents = currentLines.join('\n');
QTC_ASSERT(includeFile, return false); // The file should still be valid after what we did.
// Reparse necessary due to changed contents.
QMakeParser parser(nullptr, nullptr, nullptr);
ProFile * const proFile = parser.parsedProBlock(
QStringRef(&currentContents),
0,
filePath().toString(),
1,
QMakeParser::FullGrammar
);
QTC_ASSERT(proFile, return); // The file should still be valid after what we did.
ProWriter::addFiles(proFile, &currentLines, {newName}, loc.first, continuationIndent());
lines = lines.mid(0, loc.second) + currentLines + lines.mid(endLine);
endLine = loc.second;
proFile->deref();
});
ProWriter::addFiles(includeFile, &lines,
QStringList(newName),
varNameForAdding(mimeType),
continuationIndent());
if (mode == Change::Save) if (mode == Change::Save)
save(lines); save(lines);
includeFile->deref();
return true; return true;
} }

View File

@@ -192,10 +192,7 @@ protected:
}; };
enum class Change { Save, TestOnly }; enum class Change { Save, TestOnly };
bool renameFile(const QString &oldName, bool renameFile(const QString &oldName, const QString &newName, Change mode);
const QString &newName,
const QString &mimeType,
Change mode = Change::Save);
void changeFiles(const QString &mimeType, void changeFiles(const QString &mimeType,
const QStringList &filePaths, const QStringList &filePaths,
QStringList *notChanged, QStringList *notChanged,

View File

@@ -415,7 +415,7 @@ void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList
} }
static void findProVariables(const ushort *tokPtr, const QStringList &vars, static void findProVariables(const ushort *tokPtr, const QStringList &vars,
QList<int> *proVars, const uint firstLine = 0) ProWriter::VarLocations &proVars, const uint firstLine = 0)
{ {
int lineNo = firstLine; int lineNo = firstLine;
QString tmp; QString tmp;
@@ -433,8 +433,11 @@ static void findProVariables(const ushort *tokPtr, const QStringList &vars,
tokPtr += blockLen; tokPtr += blockLen;
} }
} else if (tok == TokAssign || tok == TokAppend || tok == TokAppendUnique) { } else if (tok == TokAssign || tok == TokAppend || tok == TokAppendUnique) {
if (getLiteral(lastXpr, tokPtr - 1, tmp) && vars.contains(tmp)) if (getLiteral(lastXpr, tokPtr - 1, tmp) && vars.contains(tmp)) {
*proVars << lineNo; QString varName = tmp;
varName.detach(); // tmp was constructed via setRawData()
proVars << qMakePair(varName, lineNo);
}
skipExpression(++tokPtr, lineNo); skipExpression(++tokPtr, lineNo);
} else { } else {
lastXpr = skipToken(tok, tokPtr, lineNo); lastXpr = skipToken(tok, tokPtr, lineNo);
@@ -443,21 +446,21 @@ static void findProVariables(const ushort *tokPtr, const QStringList &vars,
} }
QList<int> ProWriter::removeVarValues(ProFile *profile, QStringList *lines, QList<int> ProWriter::removeVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QStringList &vars) const QStringList &values, const QStringList &vars, VarLocations *removedLocations)
{ {
QList<int> notChanged; QList<int> notChanged;
// yeah, this is a bit silly // yeah, this is a bit silly
for (int i = 0; i < values.size(); i++) for (int i = 0; i < values.size(); i++)
notChanged << i; notChanged << i;
QList<int> varLines; VarLocations varLocations;
findProVariables(profile->tokPtr(), vars, &varLines); findProVariables(profile->tokPtr(), vars, varLocations);
// This code expects proVars to be sorted by the variables' appearance in the file. // This code expects proVars to be sorted by the variables' appearance in the file.
int delta = 1; int delta = 1;
for (int ln : qAsConst(varLines)) { for (const VarLocation &loc : qAsConst(varLocations)) {
bool first = true; bool first = true;
int lineNo = ln - delta; int lineNo = loc.second - delta;
typedef QPair<int, int> ContPos; typedef QPair<int, int> ContPos;
QList<ContPos> contPos; QList<ContPos> contPos;
while (lineNo < lines->count()) { while (lineNo < lines->count()) {
@@ -507,6 +510,8 @@ QList<int> ProWriter::removeVarValues(ProFile *profile, QStringList *lines,
const int pos = values.indexOf(fn); const int pos = values.indexOf(fn);
if (pos != -1) { if (pos != -1) {
notChanged.removeOne(pos); notChanged.removeOne(pos);
if (removedLocations)
*removedLocations << qMakePair(loc.first, loc.second - delta);
if (colNo < lineLen) if (colNo < lineLen)
colNo++; colNo++;
else if (varCol) else if (varCol)
@@ -559,8 +564,13 @@ QList<int> ProWriter::removeVarValues(ProFile *profile, QStringList *lines,
return notChanged; return notChanged;
} }
QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines, QStringList ProWriter::removeFiles(
const QDir &proFileDir, const QStringList &values, const QStringList &vars) ProFile *profile,
QStringList *lines,
const QDir &proFileDir,
const QStringList &values,
const QStringList &vars,
VarLocations *removedLocations)
{ {
// This is a tad stupid - basically, it can remove only entries which // This is a tad stupid - basically, it can remove only entries which
// the above code added. // the above code added.
@@ -569,7 +579,7 @@ QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines,
valuesToFind << proFileDir.relativeFilePath(absoluteFilePath); valuesToFind << proFileDir.relativeFilePath(absoluteFilePath);
const QStringList notYetChanged = const QStringList notYetChanged =
Utils::transform(removeVarValues(profile, lines, valuesToFind, vars), Utils::transform(removeVarValues(profile, lines, valuesToFind, vars, removedLocations),
[values](int i) { return values.at(i); }); [values](int i) { return values.at(i); });
if (!profile->fileName().endsWith(".pri")) if (!profile->fileName().endsWith(".pri"))
@@ -585,7 +595,7 @@ QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines,
valuesToFind << (prefixPwd + baseDir.relativeFilePath(absoluteFilePath)); valuesToFind << (prefixPwd + baseDir.relativeFilePath(absoluteFilePath));
const QStringList notChanged = const QStringList notChanged =
Utils::transform(removeVarValues(profile, lines, valuesToFind, vars), Utils::transform(removeVarValues(profile, lines, valuesToFind, vars, removedLocations),
[notYetChanged](int i) { return notYetChanged.at(i); }); [notYetChanged](int i) { return notYetChanged.at(i); });
return notChanged; return notChanged;

View File

@@ -52,13 +52,26 @@ public:
static void putVarValues(ProFile *profile, QStringList *lines, static void putVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QString &var, PutFlags flags, const QStringList &values, const QString &var, PutFlags flags,
const QString &scope, const QString &continuationIndent); const QString &scope, const QString &continuationIndent);
static QList<int> removeVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QStringList &vars); using VarLocation = QPair<QString, int>;
using VarLocations = QList<VarLocation>;
static QList<int> removeVarValues(
ProFile *profile,
QStringList *lines,
const QStringList &values,
const QStringList &vars,
VarLocations *removedLocations = nullptr
);
static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths, static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths,
const QString &var, const QString &continuationIndent); const QString &var, const QString &continuationIndent);
static QStringList removeFiles(ProFile *profile, QStringList *lines, static QStringList removeFiles(
const QDir &proFileDir, const QStringList &filePaths, const QStringList &vars); ProFile *profile,
QStringList *lines,
const QDir &proFileDir,
const QStringList &filePaths,
const QStringList &vars,
VarLocations *removedLocations = nullptr);
private: private:
static bool locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd, static bool locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd,