forked from qt-creator/qt-creator
C++ Refactoring: Fix the include macros in header files after renaming
Fixes: QTCREATORBUG-4686 Change-Id: If22078bb183910941d8e2a94b0e8629baa2fa8de Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
committed by
Miklós Márton
parent
795ccfbffc
commit
3299239095
@@ -29,10 +29,12 @@
|
||||
#include <coreplugin/documentmanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/iversioncontrol.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <coreplugin/vcsmanager.h>
|
||||
#include <utils/consoleprocess.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/textfileformat.h>
|
||||
#include <utils/unixutils.h>
|
||||
|
||||
#include <QApplication>
|
||||
@@ -40,6 +42,9 @@
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QTextStream>
|
||||
#include <QTextCodec>
|
||||
#include <QWidget>
|
||||
|
||||
using namespace Utils;
|
||||
@@ -178,7 +183,8 @@ static inline bool fileSystemRenameFile(const QString &orgFilePath,
|
||||
return QFile::rename(orgFilePath, newFilePath);
|
||||
}
|
||||
|
||||
bool FileUtils::renameFile(const QString &orgFilePath, const QString &newFilePath)
|
||||
bool FileUtils::renameFile(const QString &orgFilePath, const QString &newFilePath,
|
||||
HandleIncludeGuards handleGuards)
|
||||
{
|
||||
if (orgFilePath == newFilePath)
|
||||
return false;
|
||||
@@ -195,7 +201,159 @@ bool FileUtils::renameFile(const QString &orgFilePath, const QString &newFilePat
|
||||
// yeah we moved, tell the filemanager about it
|
||||
DocumentManager::renamedFile(orgFilePath, newFilePath);
|
||||
}
|
||||
|
||||
if (result && handleGuards == HandleIncludeGuards::Yes) {
|
||||
QFileInfo fi(orgFilePath);
|
||||
bool headerUpdateSuccess = updateHeaderFileGuardAfterRename(newFilePath, fi.baseName());
|
||||
if (!headerUpdateSuccess) {
|
||||
Core::MessageManager::write(QCoreApplication::translate(
|
||||
"Core::FileUtils",
|
||||
"Failed to rename the include guard in file \"%1\".")
|
||||
.arg(newFilePath));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FileUtils::updateHeaderFileGuardAfterRename(const QString &headerPath,
|
||||
const QString &oldHeaderBaseName)
|
||||
{
|
||||
bool ret = true;
|
||||
QFile headerFile(headerPath);
|
||||
if (!headerFile.open(QFile::ReadOnly | QFile::Text))
|
||||
return false;
|
||||
|
||||
QRegularExpression guardConditionRegExp(
|
||||
QString("(#ifndef)(\\s*)(_*)%1_H(_*)(\\s*)").arg(oldHeaderBaseName.toUpper()));
|
||||
QRegularExpression guardDefineRegexp, guardCloseRegExp;
|
||||
QRegularExpressionMatch guardConditionMatch, guardDefineMatch, guardCloseMatch;
|
||||
int guardStartLine = -1;
|
||||
int guardCloseLine = -1;
|
||||
|
||||
QByteArray data = headerFile.readAll();
|
||||
headerFile.close();
|
||||
|
||||
const auto headerFileTextFormat = Utils::TextFileFormat::detect(data);
|
||||
QTextStream inStream(&data);
|
||||
int lineCounter = 0;
|
||||
QString line;
|
||||
while (!inStream.atEnd()) {
|
||||
// use trimmed line to get rid from the maunder leading spaces
|
||||
inStream.readLineInto(&line);
|
||||
line = line.trimmed();
|
||||
if (line == QStringLiteral("#pragma once")) {
|
||||
// if pragma based guard found skip reading the whole file
|
||||
break;
|
||||
}
|
||||
|
||||
if (guardStartLine == -1) {
|
||||
// we are still looking for the guard condition
|
||||
guardConditionMatch = guardConditionRegExp.match(line);
|
||||
if (guardConditionMatch.hasMatch()) {
|
||||
guardDefineRegexp.setPattern(QString("(#define\\s*%1)%2(_H%3\\s*)")
|
||||
.arg(guardConditionMatch.captured(3),
|
||||
oldHeaderBaseName.toUpper(),
|
||||
guardConditionMatch.captured(4)));
|
||||
// read the next line for the guard define
|
||||
line = inStream.readLine();
|
||||
if (!inStream.atEnd()) {
|
||||
guardDefineMatch = guardDefineRegexp.match(line);
|
||||
if (guardDefineMatch.hasMatch()) {
|
||||
// if a proper guard define present in the next line store the line number
|
||||
guardCloseRegExp
|
||||
.setPattern(
|
||||
QString("(#endif\\s*)(\\/\\/|\\/\\*)(\\s*%1)%2(_H%3\\s*)((\\*\\/)?)")
|
||||
.arg(
|
||||
guardConditionMatch.captured(3),
|
||||
oldHeaderBaseName.toUpper(),
|
||||
guardConditionMatch.captured(4)));
|
||||
guardStartLine = lineCounter;
|
||||
lineCounter++;
|
||||
}
|
||||
} else {
|
||||
// it the line after the guard opening is not something what we expect
|
||||
// then skip the whole guard replacing process
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// guard start found looking for the guard closing endif
|
||||
guardCloseMatch = guardCloseRegExp.match(line);
|
||||
if (guardCloseMatch.hasMatch()) {
|
||||
guardCloseLine = lineCounter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lineCounter++;
|
||||
}
|
||||
|
||||
if (guardStartLine != -1) {
|
||||
// At least the guard have been found ->
|
||||
// copy the contents of the header to a temporary file with the updated guard lines
|
||||
inStream.seek(0);
|
||||
|
||||
QFileInfo fi(headerFile);
|
||||
const auto guardCondition = QString("#ifndef%1%2%3_H%4%5").arg(
|
||||
guardConditionMatch.captured(2),
|
||||
guardConditionMatch.captured(3),
|
||||
fi.baseName().toUpper(),
|
||||
guardConditionMatch.captured(4),
|
||||
guardConditionMatch.captured(5));
|
||||
// guardDefineRegexp.setPattern(QString("(#define\\s*%1)%2(_H%3\\s*)")
|
||||
const auto guardDefine = QString("%1%2%3").arg(
|
||||
guardDefineMatch.captured(1),
|
||||
fi.baseName().toUpper(),
|
||||
guardDefineMatch.captured(2));
|
||||
const auto guardClose = QString("%1%2%3%4%5%6").arg(
|
||||
guardCloseMatch.captured(1),
|
||||
guardCloseMatch.captured(2),
|
||||
guardCloseMatch.captured(3),
|
||||
fi.baseName().toUpper(),
|
||||
guardCloseMatch.captured(4),
|
||||
guardCloseMatch.captured(5));
|
||||
|
||||
QFile tmpHeader(headerPath + ".tmp");
|
||||
if (tmpHeader.open(QFile::WriteOnly)) {
|
||||
const auto lineEnd =
|
||||
headerFileTextFormat.lineTerminationMode
|
||||
== Utils::TextFileFormat::LFLineTerminator
|
||||
? QStringLiteral("\n") : QStringLiteral("\r\n");
|
||||
QTextStream outStream(&tmpHeader);
|
||||
if (headerFileTextFormat.codec == nullptr)
|
||||
outStream.setCodec("UTF-8");
|
||||
else
|
||||
outStream.setCodec(headerFileTextFormat.codec->name());
|
||||
int lineCounter = 0;
|
||||
while (!inStream.atEnd()) {
|
||||
inStream.readLineInto(&line);
|
||||
if (lineCounter == guardStartLine) {
|
||||
outStream << guardCondition << lineEnd;
|
||||
outStream << guardDefine << lineEnd;
|
||||
inStream.readLine();
|
||||
lineCounter++;
|
||||
} else if (lineCounter == guardCloseLine) {
|
||||
outStream << guardClose << lineEnd;
|
||||
} else {
|
||||
outStream << line << lineEnd;
|
||||
}
|
||||
lineCounter++;
|
||||
}
|
||||
tmpHeader.close();
|
||||
} else {
|
||||
// if opening the temp file failed report error
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && guardStartLine != -1) {
|
||||
// if the guard was found (and updated updated properly) swap the temp and the target file
|
||||
ret = QFile::remove(headerPath);
|
||||
if (ret)
|
||||
ret = QFile::rename(headerPath + ".tmp", headerPath);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
Reference in New Issue
Block a user