Refactoring changes: Cleanup and improvements.

Previously RefactoringFiles were usually passed around by value.
However, since a RefactoringFile may sometimes own a QTextDocument
(when it was read from a file), that's not great and caused the
file to be reread after every copy.

With this change RefactoringFile becomes noncopyable and is always
owned by a shared pointer.

This change also allowed having const RefactoringFiles which is
useful because they can be safely used from other threads. See
CppRefactoringChanges::fileNoEditor.

Change-Id: I9045921d6d0f6349f9558ff2a3d8317ea172193b
Reviewed-on: http://codereview.qt.nokia.com/3084
Reviewed-by: Leandro T. C. Melo <leandro.melo@nokia.com>
This commit is contained in:
Christian Kamm
2011-08-17 11:35:57 +02:00
parent a07acad516
commit 8a6d767a8f
30 changed files with 609 additions and 500 deletions

View File

@@ -45,8 +45,8 @@ using namespace CPlusPlus;
QList<AST *> ASTPath::operator()(int line, int column) QList<AST *> ASTPath::operator()(int line, int column)
{ {
_nodes.clear(); _nodes.clear();
_line = line + 1; _line = line;
_column = column + 1; _column = column;
if (_doc) { if (_doc) {
if (TranslationUnit *unit = _doc->translationUnit()) if (TranslationUnit *unit = _doc->translationUnit())

View File

@@ -54,9 +54,9 @@ public:
{} {}
QList<AST *> operator()(const QTextCursor &cursor) QList<AST *> operator()(const QTextCursor &cursor)
{ return this->operator()(cursor.blockNumber(), cursor.positionInBlock()); } { return this->operator()(cursor.blockNumber() + 1, cursor.positionInBlock() + 1); }
/// line and column are 0-based! /// line and column are 1-based!
QList<AST *> operator()(int line, int column); QList<AST *> operator()(int line, int column);
#ifdef DEBUG_AST_PATH #ifdef DEBUG_AST_PATH

View File

@@ -116,15 +116,17 @@ public:
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile,
const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
int start = currentFile->endOf(compoundStatement->lbrace_token); int start = currentFile->endOf(compoundStatement->lbrace_token);
changes.insert(start, QLatin1String("\ncase ") changes.insert(start, QLatin1String("\ncase ")
+ values.join(QLatin1String(":\nbreak;\ncase ")) + values.join(QLatin1String(":\nbreak;\ncase "))
+ QLatin1String(":\nbreak;")); + QLatin1String(":\nbreak;"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(compoundStatement)); currentFile->appendIndentRange(currentFile->range(compoundStatement));
currentFile->apply();
} }
CompoundStatementAST *compoundStatement; CompoundStatementAST *compoundStatement;

View File

@@ -42,6 +42,7 @@
#include <cplusplus/TranslationUnit.h> #include <cplusplus/TranslationUnit.h>
#include <cplusplus/LookupContext.h> #include <cplusplus/LookupContext.h>
#include <cplusplus/Overview.h> #include <cplusplus/Overview.h>
#include <cpptools/cpprefactoringchanges.h>
#include <texteditor/refactoroverlay.h> #include <texteditor/refactoroverlay.h>
#include <texteditor/tooltip/tooltip.h> #include <texteditor/tooltip/tooltip.h>
#include <texteditor/tooltip/tipcontents.h> #include <texteditor/tooltip/tipcontents.h>
@@ -76,10 +77,11 @@ QTextCursor FunctionDeclDefLinkFinder::scannedSelection() const
} }
// parent is either a FunctionDefinitionAST or a SimpleDeclarationAST // parent is either a FunctionDefinitionAST or a SimpleDeclarationAST
static bool findDeclOrDef(const Document::Ptr &doc, const QTextCursor &cursor, // line and column are 1-based
static bool findDeclOrDef(const Document::Ptr &doc, int line, int column,
DeclarationAST **parent, FunctionDeclaratorAST **funcDecl) DeclarationAST **parent, FunctionDeclaratorAST **funcDecl)
{ {
QList<AST *> path = ASTPath(doc)(cursor); QList<AST *> path = ASTPath(doc)(line, column);
// for function definitions, simply scan for FunctionDefinitionAST not preceded // for function definitions, simply scan for FunctionDefinitionAST not preceded
// by CompoundStatement/CtorInitializer // by CompoundStatement/CtorInitializer
@@ -113,19 +115,19 @@ static bool findDeclOrDef(const Document::Ptr &doc, const QTextCursor &cursor,
return *funcDecl; return *funcDecl;
} }
static void declDefLinkStartEnd(const CppTools::CppRefactoringFile &file, static void declDefLinkStartEnd(const CppTools::CppRefactoringFileConstPtr &file,
DeclarationAST *parent, FunctionDeclaratorAST *funcDecl, DeclarationAST *parent, FunctionDeclaratorAST *funcDecl,
int *start, int *end) int *start, int *end)
{ {
*start = file.startOf(parent); *start = file->startOf(parent);
if (funcDecl->trailing_return_type) if (funcDecl->trailing_return_type)
*end = file.endOf(funcDecl->trailing_return_type); *end = file->endOf(funcDecl->trailing_return_type);
else if (funcDecl->exception_specification) else if (funcDecl->exception_specification)
*end = file.endOf(funcDecl->exception_specification); *end = file->endOf(funcDecl->exception_specification);
else if (funcDecl->cv_qualifier_list) else if (funcDecl->cv_qualifier_list)
*end = file.endOf(funcDecl->cv_qualifier_list->lastValue()); *end = file->endOf(funcDecl->cv_qualifier_list->lastValue());
else else
*end = file.endOf(funcDecl->rparen_token); *end = file->endOf(funcDecl->rparen_token);
} }
static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<FunctionDeclDefLink> link, CppTools::CppRefactoringChanges changes) static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<FunctionDeclDefLink> link, CppTools::CppRefactoringChanges changes)
@@ -152,15 +154,14 @@ static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<Functio
// parse the target file to get the linked decl/def // parse the target file to get the linked decl/def
const QString targetFileName = QString::fromUtf8( const QString targetFileName = QString::fromUtf8(
target->fileName(), target->fileNameLength()); target->fileName(), target->fileNameLength());
CppTools::CppRefactoringFile targetFile = changes.file(targetFileName); CppTools::CppRefactoringFileConstPtr targetFile = changes.fileNoEditor(targetFileName);
if (!targetFile.isValid()) if (!targetFile->isValid())
return noResult; return noResult;
QTextCursor tc(targetFile.cursor());
tc.setPosition(targetFile.position(target->line(), target->column()));
DeclarationAST *targetParent = 0; DeclarationAST *targetParent = 0;
FunctionDeclaratorAST *targetFuncDecl = 0; FunctionDeclaratorAST *targetFuncDecl = 0;
if (!findDeclOrDef(targetFile.cppDocument(), tc, &targetParent, &targetFuncDecl)) if (!findDeclOrDef(targetFile->cppDocument(), target->line(), target->column(),
&targetParent, &targetFuncDecl))
return noResult; return noResult;
// the parens are necessary for finding good places for changes // the parens are necessary for finding good places for changes
@@ -169,16 +170,14 @@ static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<Functio
int targetStart, targetEnd; int targetStart, targetEnd;
declDefLinkStartEnd(targetFile, targetParent, targetFuncDecl, &targetStart, &targetEnd); declDefLinkStartEnd(targetFile, targetParent, targetFuncDecl, &targetStart, &targetEnd);
QString targetInitial = targetFile.textOf( QString targetInitial = targetFile->textOf(
targetFile.startOf(targetParent), targetFile->startOf(targetParent),
targetEnd); targetEnd);
link->targetOffset = targetStart; link->targetOffset = targetStart;
link->targetInitial = targetInitial; link->targetInitial = targetInitial;
link->targetFile = QSharedPointer<CppTools::CppRefactoringFile>( link->targetFile = targetFile;
new CppTools::CppRefactoringFile(targetFile.document()->clone(), targetFile.fileName()));
link->targetFile->setCppDocument(targetFile.cppDocument());
link->targetFunction = targetFuncDecl->symbol; link->targetFunction = targetFuncDecl->symbol;
link->targetFunctionDeclarator = targetFuncDecl; link->targetFunctionDeclarator = targetFuncDecl;
link->targetDeclaration = targetParent; link->targetDeclaration = targetParent;
@@ -192,13 +191,13 @@ void FunctionDeclDefLinkFinder::startFindLinkAt(
// check if cursor is on function decl/def // check if cursor is on function decl/def
DeclarationAST *parent = 0; DeclarationAST *parent = 0;
FunctionDeclaratorAST *funcDecl = 0; FunctionDeclaratorAST *funcDecl = 0;
if (!findDeclOrDef(doc, cursor, &parent, &funcDecl)) if (!findDeclOrDef(doc, cursor.blockNumber() + 1, cursor.columnNumber() + 1, &parent, &funcDecl))
return; return;
// find the start/end offsets // find the start/end offsets
CppTools::CppRefactoringChanges refactoringChanges(snapshot); CppTools::CppRefactoringChanges refactoringChanges(snapshot);
CppTools::CppRefactoringFile sourceFile = refactoringChanges.file(doc->fileName()); CppTools::CppRefactoringFilePtr sourceFile = refactoringChanges.file(doc->fileName());
sourceFile.setCppDocument(doc); sourceFile->setCppDocument(doc);
int start, end; int start, end;
declDefLinkStartEnd(sourceFile, parent, funcDecl, &start, &end); declDefLinkStartEnd(sourceFile, parent, funcDecl, &start, &end);
@@ -242,7 +241,7 @@ FunctionDeclDefLink::~FunctionDeclDefLink()
bool FunctionDeclDefLink::isValid() const bool FunctionDeclDefLink::isValid() const
{ {
return targetFile; return !linkSelection.isNull();
} }
bool FunctionDeclDefLink::isMarkerVisible() const bool FunctionDeclDefLink::isMarkerVisible() const
@@ -274,18 +273,16 @@ void FunctionDeclDefLink::apply(CPPEditorWidget *editor, bool jumpToMatch)
// first verify the interesting region of the target file is unchanged // first verify the interesting region of the target file is unchanged
CppTools::CppRefactoringChanges refactoringChanges(snapshot); CppTools::CppRefactoringChanges refactoringChanges(snapshot);
CppTools::CppRefactoringFile newTargetFile = refactoringChanges.file(targetFile->fileName()); CppTools::CppRefactoringFilePtr newTargetFile = refactoringChanges.file(targetFile->fileName());
if (!newTargetFile.isValid()) if (!newTargetFile->isValid())
return; return;
const int targetEnd = targetOffset + targetInitial.size(); const int targetEnd = targetOffset + targetInitial.size();
if (targetInitial == newTargetFile.textOf(targetOffset, targetEnd)) { if (targetInitial == newTargetFile->textOf(targetOffset, targetEnd)) {
const Utils::ChangeSet changeset = changes(snapshot); const Utils::ChangeSet changeset = changes(snapshot);
newTargetFile.change(changeset, jumpToMatch); newTargetFile->setChangeSet(changeset);
if (jumpToMatch) { if (jumpToMatch)
QTextCursor tc = newTargetFile.cursor(); newTargetFile->setOpenEditor(true, targetOffset);
tc.setPosition(targetOffset + targetInitial.size()); newTargetFile->apply();
refactoringChanges.activateEditor(newTargetFile.fileName(), tc.blockNumber(), tc.columnNumber());
}
} else { } else {
TextEditor::ToolTip::instance()->show( TextEditor::ToolTip::instance()->show(
editor->toolTipPosition(linkSelection), editor->toolTipPosition(linkSelection),
@@ -361,8 +358,6 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
{ {
Utils::ChangeSet changes; Utils::ChangeSet changes;
QSharedPointer<CppTools::CppRefactoringFile> matchFile = targetFile;
// parse the current source declaration // parse the current source declaration
TypeOfExpression typeOfExpression; // ### just need to preprocess... TypeOfExpression typeOfExpression; // ### just need to preprocess...
typeOfExpression.init(sourceDocument, snapshot); typeOfExpression.init(sourceDocument, snapshot);
@@ -412,15 +407,15 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
if (SimpleDeclarationAST *simple = targetDeclaration->asSimpleDeclaration()) { if (SimpleDeclarationAST *simple = targetDeclaration->asSimpleDeclaration()) {
declarator = simple->declarator_list->value; declarator = simple->declarator_list->value;
if (simple->decl_specifier_list) if (simple->decl_specifier_list)
returnTypeStart = matchFile->startOf(simple->decl_specifier_list->value); returnTypeStart = targetFile->startOf(simple->decl_specifier_list->value);
else else
returnTypeStart = matchFile->startOf(declarator); returnTypeStart = targetFile->startOf(declarator);
} else if (FunctionDefinitionAST *def = targetDeclaration->asFunctionDefinition()) { } else if (FunctionDefinitionAST *def = targetDeclaration->asFunctionDefinition()) {
declarator = def->declarator; declarator = def->declarator;
if (def->decl_specifier_list) if (def->decl_specifier_list)
returnTypeStart = matchFile->startOf(def->decl_specifier_list->value); returnTypeStart = targetFile->startOf(def->decl_specifier_list->value);
else else
returnTypeStart = matchFile->startOf(declarator); returnTypeStart = targetFile->startOf(declarator);
} }
if (!newFunction->returnType().isEqualTo(sourceFunction->returnType()) if (!newFunction->returnType().isEqualTo(sourceFunction->returnType())
@@ -428,7 +423,7 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
FullySpecifiedType type = rewriteType(newFunction->returnType(), &env, control); FullySpecifiedType type = rewriteType(newFunction->returnType(), &env, control);
const QString replacement = overview(type, targetFunction->name()); const QString replacement = overview(type, targetFunction->name());
changes.replace(returnTypeStart, changes.replace(returnTypeStart,
matchFile->startOf(targetFunctionDeclarator->lparen_token), targetFile->startOf(targetFunctionDeclarator->lparen_token),
replacement); replacement);
} }
} }
@@ -478,35 +473,35 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
ParameterDeclarationAST *targetParamAst = targetParameterDeclIt->value; ParameterDeclarationAST *targetParamAst = targetParameterDeclIt->value;
int parameterNameEnd = 0; int parameterNameEnd = 0;
if (targetParamAst->declarator) if (targetParamAst->declarator)
parameterNameEnd = matchFile->endOf(targetParamAst->declarator); parameterNameEnd = targetFile->endOf(targetParamAst->declarator);
else if (targetParamAst->type_specifier_list) else if (targetParamAst->type_specifier_list)
parameterNameEnd = matchFile->endOf(targetParamAst->type_specifier_list->lastToken() - 1); parameterNameEnd = targetFile->endOf(targetParamAst->type_specifier_list->lastToken() - 1);
else else
parameterNameEnd = matchFile->startOf(targetParamAst); parameterNameEnd = targetFile->startOf(targetParamAst);
if (allowChangeType if (allowChangeType
&& !targetParam->type().isEqualTo(newParam->type())) { && !targetParam->type().isEqualTo(newParam->type())) {
FullySpecifiedType replacementType = rewriteType(newParam->type(), &env, control); FullySpecifiedType replacementType = rewriteType(newParam->type(), &env, control);
const QString replacement = overview(replacementType, replacementName); const QString replacement = overview(replacementType, replacementName);
changes.replace(matchFile->startOf(targetParamAst), changes.replace(targetFile->startOf(targetParamAst),
parameterNameEnd, parameterNameEnd,
replacement); replacement);
} else if (!namesEqual(targetParam->name(), replacementName)) { } else if (!namesEqual(targetParam->name(), replacementName)) {
DeclaratorIdAST *id = getDeclaratorId(targetParamAst->declarator); DeclaratorIdAST *id = getDeclaratorId(targetParamAst->declarator);
QString replacementNameStr = overview(replacementName); QString replacementNameStr = overview(replacementName);
if (id) { if (id) {
changes.replace(matchFile->range(id), replacementNameStr); changes.replace(targetFile->range(id), replacementNameStr);
} else { } else {
// add name to unnamed parameter // add name to unnamed parameter
replacementNameStr.prepend(QLatin1Char(' ')); replacementNameStr.prepend(QLatin1Char(' '));
int end; int end;
if (targetParamAst->equal_token) { if (targetParamAst->equal_token) {
end = matchFile->startOf(targetParamAst->equal_token); end = targetFile->startOf(targetParamAst->equal_token);
replacementNameStr.append(QLatin1Char(' ')); replacementNameStr.append(QLatin1Char(' '));
} else { } else {
// one past end on purpose // one past end on purpose
end = matchFile->startOf(targetParamAst->lastToken()); end = targetFile->startOf(targetParamAst->lastToken());
} }
changes.replace(parameterNameEnd, end, replacementNameStr); changes.replace(parameterNameEnd, end, replacementNameStr);
} }
@@ -516,15 +511,15 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
targetParameterDeclIt = firstTargetParameterDeclIt; targetParameterDeclIt = firstTargetParameterDeclIt;
if (targetParameterDeclIt) { if (targetParameterDeclIt) {
if (newArgCount == 0) { if (newArgCount == 0) {
changes.remove(matchFile->startOf(targetParameterDeclIt->firstToken()), changes.remove(targetFile->startOf(targetParameterDeclIt->firstToken()),
matchFile->endOf(targetParameterDeclIt->lastToken() - 1)); targetFile->endOf(targetParameterDeclIt->lastToken() - 1));
} else { } else {
// get the last valid argument // get the last valid argument
for (unsigned i = 0; i < newArgCount - 1 && targetParameterDeclIt; ++i) for (unsigned i = 0; i < newArgCount - 1 && targetParameterDeclIt; ++i)
targetParameterDeclIt = targetParameterDeclIt->next; targetParameterDeclIt = targetParameterDeclIt->next;
if (targetParameterDeclIt) { if (targetParameterDeclIt) {
const int start = matchFile->endOf(targetParameterDeclIt->value); const int start = targetFile->endOf(targetParameterDeclIt->value);
const int end = matchFile->endOf(targetParameterDecl->lastToken() - 1); const int end = targetFile->endOf(targetParameterDecl->lastToken() - 1);
changes.remove(start, end); changes.remove(start, end);
} }
} }
@@ -542,9 +537,9 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
if (targetParameterDeclIt) { if (targetParameterDeclIt) {
while (targetParameterDeclIt->next) while (targetParameterDeclIt->next)
targetParameterDeclIt = targetParameterDeclIt->next; targetParameterDeclIt = targetParameterDeclIt->next;
changes.insert(matchFile->endOf(targetParameterDeclIt->value), newParams); changes.insert(targetFile->endOf(targetParameterDeclIt->value), newParams);
} else { } else {
changes.insert(matchFile->endOf(targetFunctionDeclarator->lparen_token), newParams); changes.insert(targetFile->endOf(targetFunctionDeclarator->lparen_token), newParams);
} }
} }
} }
@@ -560,12 +555,12 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot)
cvString += QLatin1Char(' '); cvString += QLatin1Char(' ');
cvString += QLatin1String("volatile"); cvString += QLatin1String("volatile");
} }
const int rparenEnd = matchFile->endOf(targetFunctionDeclarator->rparen_token); const int rparenEnd = targetFile->endOf(targetFunctionDeclarator->rparen_token);
if (targetFunctionDeclarator->cv_qualifier_list) { if (targetFunctionDeclarator->cv_qualifier_list) {
const int cvEnd = matchFile->endOf(targetFunctionDeclarator->cv_qualifier_list->lastToken() - 1); const int cvEnd = targetFile->endOf(targetFunctionDeclarator->cv_qualifier_list->lastToken() - 1);
// if the qualifies changed, replace // if the qualifies changed, replace
if (!cvString.isEmpty()) { if (!cvString.isEmpty()) {
changes.replace(matchFile->startOf(targetFunctionDeclarator->cv_qualifier_list->firstToken()), changes.replace(targetFile->startOf(targetFunctionDeclarator->cv_qualifier_list->firstToken()),
cvEnd, cvString); cvEnd, cvString);
} else { } else {
// remove // remove

View File

@@ -100,7 +100,7 @@ public:
CPlusPlus::DeclarationAST *sourceDeclaration; CPlusPlus::DeclarationAST *sourceDeclaration;
CPlusPlus::FunctionDeclaratorAST *sourceFunctionDeclarator; CPlusPlus::FunctionDeclaratorAST *sourceFunctionDeclarator;
QSharedPointer<CppTools::CppRefactoringFile> targetFile; CppTools::CppRefactoringFileConstPtr targetFile;
CPlusPlus::Function *targetFunction; CPlusPlus::Function *targetFunction;
CPlusPlus::DeclarationAST *targetDeclaration; CPlusPlus::DeclarationAST *targetDeclaration;
CPlusPlus::FunctionDeclaratorAST *targetFunctionDeclarator; CPlusPlus::FunctionDeclaratorAST *targetFunctionDeclarator;

View File

@@ -80,25 +80,24 @@ public:
"Add %1 Declaration").arg(type)); "Add %1 Declaration").arg(type));
} }
void performChanges(CppRefactoringFile *, CppRefactoringChanges *refactoring) void performChanges(const CppRefactoringFilePtr &,
const CppRefactoringChanges &refactoring)
{ {
InsertionPointLocator locator(refactoring); InsertionPointLocator locator(refactoring);
const InsertionLocation loc = locator.methodDeclarationInClass( const InsertionLocation loc = locator.methodDeclarationInClass(
m_targetFileName, m_targetSymbol, m_xsSpec); m_targetFileName, m_targetSymbol, m_xsSpec);
Q_ASSERT(loc.isValid()); Q_ASSERT(loc.isValid());
CppRefactoringFile targetFile = refactoring->file(m_targetFileName); CppRefactoringFilePtr targetFile = refactoring.file(m_targetFileName);
int targetPosition1 = targetFile.position(loc.line(), loc.column()); int targetPosition1 = targetFile->position(loc.line(), loc.column());
int targetPosition2 = qMax(0, targetFile.position(loc.line(), 1) - 1); int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
Utils::ChangeSet target; Utils::ChangeSet target;
target.insert(targetPosition1, loc.prefix() + m_decl); target.insert(targetPosition1, loc.prefix() + m_decl);
targetFile.change(target); targetFile->setChangeSet(target);
targetFile.indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1)); targetFile->appendIndentRange(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
targetFile->setOpenEditor(true, targetPosition1);
const int prefixLineCount = loc.prefix().count(QLatin1Char('\n')); targetFile->apply();
refactoring->activateEditor(m_targetFileName, loc.line() + prefixLineCount,
qMax(((int) loc.column()) - 1, 0));
} }
private: private:
@@ -114,7 +113,7 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface) const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
{ {
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
FunctionDefinitionAST *funDef = 0; FunctionDefinitionAST *funDef = 0;
int idx = 0; int idx = 0;
@@ -122,7 +121,7 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(
AST *node = path.at(idx); AST *node = path.at(idx);
if (idx > 1) { if (idx > 1) {
if (DeclaratorIdAST *declId = node->asDeclaratorId()) { if (DeclaratorIdAST *declId = node->asDeclaratorId()) {
if (file.isCursorOn(declId)) { if (file->isCursorOn(declId)) {
if (FunctionDefinitionAST *candidate = path.at(idx - 2)->asFunctionDefinition()) { if (FunctionDefinitionAST *candidate = path.at(idx - 2)->asFunctionDefinition()) {
if (funDef) { if (funDef) {
return noResult(); return noResult();
@@ -230,12 +229,12 @@ public:
.arg(dir.relativeFilePath(m_loc.fileName()))); .arg(dir.relativeFilePath(m_loc.fileName())));
} }
void performChanges(CppRefactoringFile *, void performChanges(const CppRefactoringFilePtr &,
CppRefactoringChanges *refactoring) const CppRefactoringChanges &refactoring)
{ {
Q_ASSERT(m_loc.isValid()); Q_ASSERT(m_loc.isValid());
CppRefactoringFile targetFile = refactoring->file(m_loc.fileName()); CppRefactoringFilePtr targetFile = refactoring.file(m_loc.fileName());
Overview oo; Overview oo;
oo.setShowFunctionSignatures(true); oo.setShowFunctionSignatures(true);
@@ -243,7 +242,7 @@ public:
oo.setShowArgumentNames(true); oo.setShowArgumentNames(true);
// make target lookup context // make target lookup context
Document::Ptr targetDoc = targetFile.cppDocument(); Document::Ptr targetDoc = targetFile->cppDocument();
Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column()); Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column());
LookupContext targetContext(targetDoc, assistInterface()->snapshot()); LookupContext targetContext(targetDoc, assistInterface()->snapshot());
ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope); ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
@@ -272,18 +271,15 @@ public:
QString defText = oo.prettyType(tn, name) + "\n{\n}"; QString defText = oo.prettyType(tn, name) + "\n{\n}";
int targetPos = targetFile.position(m_loc.line(), m_loc.column()); int targetPos = targetFile->position(m_loc.line(), m_loc.column());
int targetPos2 = qMax(0, targetFile.position(m_loc.line(), 1) - 1); int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1);
Utils::ChangeSet target; Utils::ChangeSet target;
target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix()); target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix());
targetFile.change(target); targetFile->setChangeSet(target);
targetFile.indent(Utils::ChangeSet::Range(targetPos2, targetPos)); targetFile->appendIndentRange(Utils::ChangeSet::Range(targetPos2, targetPos));
targetFile->setOpenEditor(true, targetPos);
const int prefixLineCount = m_loc.prefix().count(QLatin1Char('\n')); targetFile->apply();
refactoring->activateEditor(m_loc.fileName(),
m_loc.line() + prefixLineCount,
0);
} }
private: private:
@@ -297,7 +293,7 @@ QList<CppQuickFixOperation::Ptr> DefFromDecl::match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface) const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
{ {
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
int idx = path.size() - 1; int idx = path.size() - 1;
for (; idx >= 0; --idx) { for (; idx >= 0; --idx) {
@@ -311,9 +307,9 @@ QList<CppQuickFixOperation::Ptr> DefFromDecl::match(
&& decl->enclosingScope() && decl->enclosingScope()
&& decl->enclosingScope()->isClass()) { && decl->enclosingScope()->isClass()) {
DeclaratorAST *declarator = simpleDecl->declarator_list->value; DeclaratorAST *declarator = simpleDecl->declarator_list->value;
if (file.isCursorOn(declarator->core_declarator)) { if (file->isCursorOn(declarator->core_declarator)) {
CppRefactoringChanges refactoring(interface->snapshot()); CppRefactoringChanges refactoring(interface->snapshot());
InsertionPointLocator locator(&refactoring); InsertionPointLocator locator(refactoring);
QList<CppQuickFixOperation::Ptr> results; QList<CppQuickFixOperation::Ptr> results;
foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) { foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
if (loc.isValid()) if (loc.isValid())

View File

@@ -71,24 +71,23 @@ QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(
if (!klass) if (!klass)
return noResult(); return noResult();
CppRefactoringChanges refactoring(interface->snapshot()); CppRefactoringFilePtr file = interface->currentFile();
const CppRefactoringFile &file = refactoring.file(interface->file()->fileName()); const QString propertyName = file->textOf(qtPropertyDeclaration->property_name);
const QString propertyName = file.textOf(qtPropertyDeclaration->property_name);
QString getterName; QString getterName;
QString setterName; QString setterName;
QString signalName; QString signalName;
int generateFlags = 0; int generateFlags = 0;
for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list; for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
it; it = it->next) { it; it = it->next) {
const QString tokenString = file.tokenAt(it->value->item_name_token).spell(); const QString tokenString = file->tokenAt(it->value->item_name_token).spell();
if (tokenString == QLatin1String("READ")) { if (tokenString == QLatin1String("READ")) {
getterName = file.textOf(it->value->expression); getterName = file->textOf(it->value->expression);
generateFlags |= GenerateGetter; generateFlags |= GenerateGetter;
} else if (tokenString == QLatin1String("WRITE")) { } else if (tokenString == QLatin1String("WRITE")) {
setterName = file.textOf(it->value->expression); setterName = file->textOf(it->value->expression);
generateFlags |= GenerateSetter; generateFlags |= GenerateSetter;
} else if (tokenString == QLatin1String("NOTIFY")) { } else if (tokenString == QLatin1String("NOTIFY")) {
signalName = file.textOf(it->value->expression); signalName = file->textOf(it->value->expression);
generateFlags |= GenerateSignal; generateFlags |= GenerateSignal;
} }
} }
@@ -143,7 +142,8 @@ InsertQtPropertyMembers::Operation::Operation(
setDescription(desc); setDescription(desc);
} }
void InsertQtPropertyMembers::Operation::performChanges(CppRefactoringFile *file, CppRefactoringChanges *refactoring) void InsertQtPropertyMembers::Operation::performChanges(const CppRefactoringFilePtr &file,
const CppRefactoringChanges &refactoring)
{ {
InsertionPointLocator locator(refactoring); InsertionPointLocator locator(refactoring);
Utils::ChangeSet declarations; Utils::ChangeSet declarations;
@@ -190,13 +190,14 @@ void InsertQtPropertyMembers::Operation::performChanges(CppRefactoringFile *file
insertAndIndent(file, &declarations, storageLoc, storageDeclaration); insertAndIndent(file, &declarations, storageLoc, storageDeclaration);
} }
file->change(declarations); file->setChangeSet(declarations);
file->apply();
} }
void InsertQtPropertyMembers::Operation::insertAndIndent(RefactoringFile *file, ChangeSet *changeSet, const InsertionLocation &loc, const QString &text) void InsertQtPropertyMembers::Operation::insertAndIndent(const RefactoringFilePtr &file, ChangeSet *changeSet, const InsertionLocation &loc, const QString &text)
{ {
int targetPosition1 = file->position(loc.line(), loc.column()); int targetPosition1 = file->position(loc.line(), loc.column());
int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1); int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix()); changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix());
file->indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1)); file->appendIndentRange(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
} }

View File

@@ -44,6 +44,7 @@ class Class;
namespace TextEditor { namespace TextEditor {
class RefactoringFile; class RefactoringFile;
typedef QSharedPointer<RefactoringFile> RefactoringFilePtr;
} }
namespace Utils { namespace Utils {
@@ -83,11 +84,11 @@ private:
const QString &getterName, const QString &setterName, const QString &signalName, const QString &getterName, const QString &setterName, const QString &signalName,
const QString &storageName); const QString &storageName);
virtual void performChanges(CppTools::CppRefactoringFile *file, virtual void performChanges(const CppTools::CppRefactoringFilePtr &file,
CppTools::CppRefactoringChanges *refactoring); const CppTools::CppRefactoringChanges &refactoring);
private: private:
void insertAndIndent(TextEditor::RefactoringFile *file, Utils::ChangeSet *changeSet, void insertAndIndent(const TextEditor::RefactoringFilePtr &file, Utils::ChangeSet *changeSet,
const CppTools::InsertionLocation &loc, const QString &text); const CppTools::InsertionLocation &loc, const QString &text);
CPlusPlus::QtPropertyDeclarationAST *m_declaration; CPlusPlus::QtPropertyDeclarationAST *m_declaration;

View File

@@ -70,9 +70,9 @@ CppQuickFixOperation::~CppQuickFixOperation()
void CppQuickFixOperation::perform() void CppQuickFixOperation::perform()
{ {
CppRefactoringChanges refactoring(m_interface->snapshot()); CppRefactoringChanges refactoring(m_interface->snapshot());
CppRefactoringFile current = refactoring.file(fileName()); CppRefactoringFilePtr current = refactoring.file(fileName());
performChanges(&current, &refactoring); performChanges(current, refactoring);
} }
const CppQuickFixAssistInterface *CppQuickFixOperation::assistInterface() const const CppQuickFixAssistInterface *CppQuickFixOperation::assistInterface() const

View File

@@ -40,6 +40,7 @@ namespace CppTools {
class CppModelManagerInterface; class CppModelManagerInterface;
class CppRefactoringFile; class CppRefactoringFile;
class CppRefactoringChanges; class CppRefactoringChanges;
typedef QSharedPointer<CppRefactoringFile> CppRefactoringFilePtr;
} // namespace CppTools } // namespace CppTools
namespace ExtensionSystem { namespace ExtensionSystem {
@@ -63,8 +64,8 @@ public:
virtual void perform(); virtual void perform();
protected: protected:
virtual void performChanges(CppTools::CppRefactoringFile *currentFile, virtual void performChanges(const CppTools::CppRefactoringFilePtr &currentFile,
CppTools::CppRefactoringChanges *refactoring) = 0; const CppTools::CppRefactoringChanges &refactoring) = 0;
QString fileName() const; QString fileName() const;

View File

@@ -105,6 +105,7 @@ CppQuickFixAssistInterface::CppQuickFixAssistInterface(CPPEditorWidget *editor,
, m_editor(editor) , m_editor(editor)
, m_semanticInfo(editor->semanticInfo()) , m_semanticInfo(editor->semanticInfo())
, m_snapshot(CPlusPlus::CppModelManagerInterface::instance()->snapshot()) , m_snapshot(CPlusPlus::CppModelManagerInterface::instance()->snapshot())
, m_currentFile(CppRefactoringChanges::file(editor, m_semanticInfo.doc))
, m_context(m_semanticInfo.doc, m_snapshot) , m_context(m_semanticInfo.doc, m_snapshot)
{ {
CPlusPlus::ASTPath astPath(m_semanticInfo.doc); CPlusPlus::ASTPath astPath(m_semanticInfo.doc);
@@ -136,19 +137,17 @@ CPPEditorWidget *CppQuickFixAssistInterface::editor() const
return m_editor; return m_editor;
} }
const CppRefactoringFile CppQuickFixAssistInterface::currentFile() const CppRefactoringFilePtr CppQuickFixAssistInterface::currentFile() const
{ {
CppRefactoringFile file(m_editor); return m_currentFile;
file.setCppDocument(m_semanticInfo.doc);
return file;
} }
bool CppQuickFixAssistInterface::isCursorOn(unsigned tokenIndex) const bool CppQuickFixAssistInterface::isCursorOn(unsigned tokenIndex) const
{ {
return currentFile().isCursorOn(tokenIndex); return currentFile()->isCursorOn(tokenIndex);
} }
bool CppQuickFixAssistInterface::isCursorOn(const CPlusPlus::AST *ast) const bool CppQuickFixAssistInterface::isCursorOn(const CPlusPlus::AST *ast) const
{ {
return currentFile().isCursorOn(ast); return currentFile()->isCursorOn(ast);
} }

View File

@@ -44,6 +44,7 @@
namespace CppTools { namespace CppTools {
class CppRefactoringFile; class CppRefactoringFile;
typedef QSharedPointer<CppRefactoringFile> CppRefactoringFilePtr;
} }
namespace CppEditor { namespace CppEditor {
@@ -62,7 +63,7 @@ public:
const CPlusPlus::LookupContext &context() const; const CPlusPlus::LookupContext &context() const;
CPPEditorWidget *editor() const; CPPEditorWidget *editor() const;
const CppTools::CppRefactoringFile currentFile() const; CppTools::CppRefactoringFilePtr currentFile() const;
bool isCursorOn(unsigned tokenIndex) const; bool isCursorOn(unsigned tokenIndex) const;
bool isCursorOn(const CPlusPlus::AST *ast) const; bool isCursorOn(const CPlusPlus::AST *ast) const;
@@ -71,6 +72,7 @@ private:
CPPEditorWidget *m_editor; CPPEditorWidget *m_editor;
CppEditor::Internal::SemanticInfo m_semanticInfo; CppEditor::Internal::SemanticInfo m_semanticInfo;
CPlusPlus::Snapshot m_snapshot; CPlusPlus::Snapshot m_snapshot;
CppTools::CppRefactoringFilePtr m_currentFile;
CPlusPlus::LookupContext m_context; CPlusPlus::LookupContext m_context;
QList<CPlusPlus::AST *> m_path; QList<CPlusPlus::AST *> m_path;
}; };

View File

@@ -89,7 +89,7 @@ public:
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface) virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{ {
QList<CppQuickFixOperation::Ptr> result; QList<CppQuickFixOperation::Ptr> result;
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
int index = path.size() - 1; int index = path.size() - 1;
@@ -100,7 +100,7 @@ public:
return result; return result;
Kind invertToken; Kind invertToken;
switch (file.tokenAt(binary->binary_op_token).kind()) { switch (file->tokenAt(binary->binary_op_token).kind()) {
case T_LESS_EQUAL: case T_LESS_EQUAL:
invertToken = T_GREATER; invertToken = T_GREATER;
break; break;
@@ -153,7 +153,7 @@ private:
// check for ! before parentheses // check for ! before parentheses
if (nested && priority - 2 >= 0) { if (nested && priority - 2 >= 0) {
negation = interface->path()[priority - 2]->asUnaryExpression(); negation = interface->path()[priority - 2]->asUnaryExpression();
if (negation && ! interface->currentFile().tokenAt(negation->unary_op_token).is(T_EXCLAIM)) if (negation && ! interface->currentFile()->tokenAt(negation->unary_op_token).is(T_EXCLAIM))
negation = 0; negation = 0;
} }
} }
@@ -163,7 +163,7 @@ private:
return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement); return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement);
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
if (negation) { if (negation) {
@@ -176,7 +176,8 @@ private:
changes.insert(currentFile->endOf(binary), ")"); changes.insert(currentFile->endOf(binary), ")");
} }
changes.replace(currentFile->range(binary->binary_op_token), replacement); changes.replace(currentFile->range(binary->binary_op_token), replacement);
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
}; };
}; };
@@ -197,7 +198,7 @@ public:
{ {
QList<QuickFixOperation::Ptr> result; QList<QuickFixOperation::Ptr> result;
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
int index = path.size() - 1; int index = path.size() - 1;
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression(); BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
@@ -207,7 +208,7 @@ public:
return result; return result;
Kind flipToken; Kind flipToken;
switch (file.tokenAt(binary->binary_op_token).kind()) { switch (file->tokenAt(binary->binary_op_token).kind()) {
case T_LESS_EQUAL: case T_LESS_EQUAL:
flipToken = T_GREATER_EQUAL; flipToken = T_GREATER_EQUAL;
break; break;
@@ -262,7 +263,7 @@ private:
return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement); return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement);
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -270,7 +271,8 @@ private:
if (! replacement.isEmpty()) if (! replacement.isEmpty())
changes.replace(currentFile->range(binary->binary_op_token), replacement); changes.replace(currentFile->range(binary->binary_op_token), replacement);
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
private: private:
@@ -296,7 +298,7 @@ public:
QList<QuickFixOperation::Ptr> result; QList<QuickFixOperation::Ptr> result;
BinaryExpressionAST *expression = 0; BinaryExpressionAST *expression = 0;
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
int index = path.size() - 1; int index = path.size() - 1;
for (; index != -1; --index) { for (; index != -1; --index) {
@@ -314,9 +316,9 @@ public:
QSharedPointer<Operation> op(new Operation(interface)); QSharedPointer<Operation> op(new Operation(interface));
if (expression->match(op->pattern, &matcher) && if (expression->match(op->pattern, &matcher) &&
file.tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) && file->tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) &&
file.tokenAt(op->left->unary_op_token).is(T_EXCLAIM) && file->tokenAt(op->left->unary_op_token).is(T_EXCLAIM) &&
file.tokenAt(op->right->unary_op_token).is(T_EXCLAIM)) { file->tokenAt(op->right->unary_op_token).is(T_EXCLAIM)) {
op->setDescription(QApplication::translate("CppTools::QuickFix", "Rewrite Condition Using ||")); op->setDescription(QApplication::translate("CppTools::QuickFix", "Rewrite Condition Using ||"));
op->setPriority(index); op->setPriority(index);
result.append(op); result.append(op);
@@ -343,7 +345,7 @@ private:
pattern = mk->BinaryExpression(left, right); pattern = mk->BinaryExpression(left, right);
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
changes.replace(currentFile->range(pattern->binary_op_token), QLatin1String("||")); changes.replace(currentFile->range(pattern->binary_op_token), QLatin1String("||"));
@@ -354,8 +356,9 @@ private:
changes.insert(start, QLatin1String("!(")); changes.insert(start, QLatin1String("!("));
changes.insert(end, QLatin1String(")")); changes.insert(end, QLatin1String(")"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(pattern)); currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply();
} }
}; };
@@ -408,7 +411,7 @@ public:
QList<CppQuickFixOperation::Ptr> result; QList<CppQuickFixOperation::Ptr> result;
CoreDeclaratorAST *core_declarator = 0; CoreDeclaratorAST *core_declarator = 0;
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
for (int index = path.size() - 1; index != -1; --index) { for (int index = path.size() - 1; index != -1; --index) {
AST *node = path.at(index); AST *node = path.at(index);
@@ -420,10 +423,10 @@ public:
if (checkDeclaration(simpleDecl)) { if (checkDeclaration(simpleDecl)) {
SimpleDeclarationAST *declaration = simpleDecl; SimpleDeclarationAST *declaration = simpleDecl;
const int cursorPosition = file.cursor().selectionStart(); const int cursorPosition = file->cursor().selectionStart();
const int startOfDeclSpecifier = file.startOf(declaration->decl_specifier_list->firstToken()); const int startOfDeclSpecifier = file->startOf(declaration->decl_specifier_list->firstToken());
const int endOfDeclSpecifier = file.endOf(declaration->decl_specifier_list->lastToken() - 1); const int endOfDeclSpecifier = file->endOf(declaration->decl_specifier_list->lastToken() - 1);
if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) { if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) {
// the AST node under cursor is a specifier. // the AST node under cursor is a specifier.
@@ -455,7 +458,7 @@ private:
"Split Declaration")); "Split Declaration"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -481,8 +484,9 @@ private:
prevDeclarator = declarator; prevDeclarator = declarator;
} }
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(declaration)); currentFile->appendIndentRange(currentFile->range(declaration));
currentFile->apply();
} }
private: private:
@@ -547,7 +551,7 @@ private:
"Add Curly Braces")); "Add Curly Braces"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -557,8 +561,9 @@ private:
const int end = currentFile->endOf(_statement->lastToken() - 1); const int end = currentFile->endOf(_statement->lastToken() - 1);
changes.insert(end, "\n}"); changes.insert(end, "\n}");
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(Utils::ChangeSet::Range(start, end)); currentFile->appendIndentRange(Utils::ChangeSet::Range(start, end));
currentFile->apply();
} }
private: private:
@@ -620,7 +625,7 @@ private:
pattern = mk.IfStatement(condition); pattern = mk.IfStatement(condition);
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -630,8 +635,9 @@ private:
changes.move(currentFile->range(condition), insertPos); changes.move(currentFile->range(condition), insertPos);
changes.insert(insertPos, QLatin1String(";\n")); changes.insert(insertPos, QLatin1String(";\n"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(pattern)); currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply();
} }
ASTMatcher matcher; ASTMatcher matcher;
@@ -704,7 +710,7 @@ private:
pattern = mk.WhileStatement(condition); pattern = mk.WhileStatement(condition);
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -717,8 +723,9 @@ private:
changes.copy(currentFile->range(core), insertPos); changes.copy(currentFile->range(core), insertPos);
changes.insert(insertPos, QLatin1String(";\n")); changes.insert(insertPos, QLatin1String(";\n"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(pattern)); currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply();
} }
ASTMatcher matcher; ASTMatcher matcher;
@@ -780,7 +787,7 @@ public:
if (! condition) if (! condition)
return noResult(); return noResult();
Token binaryToken = interface->currentFile().tokenAt(condition->binary_op_token); Token binaryToken = interface->currentFile()->tokenAt(condition->binary_op_token);
// only accept a chain of ||s or &&s - no mixing // only accept a chain of ||s or &&s - no mixing
if (! splitKind) { if (! splitKind) {
@@ -815,7 +822,7 @@ private:
"Split if Statement")); "Split if Statement"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
const Token binaryToken = currentFile->tokenAt(condition->binary_op_token); const Token binaryToken = currentFile->tokenAt(condition->binary_op_token);
@@ -825,7 +832,7 @@ private:
splitOrCondition(currentFile); splitOrCondition(currentFile);
} }
void splitAndCondition(CppRefactoringFile *currentFile) void splitAndCondition(CppRefactoringFilePtr currentFile)
{ {
ChangeSet changes; ChangeSet changes;
@@ -838,11 +845,12 @@ private:
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression)); changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
changes.insert(currentFile->endOf(pattern), QLatin1String("\n}")); changes.insert(currentFile->endOf(pattern), QLatin1String("\n}"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(pattern)); currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply();
} }
void splitOrCondition(CppRefactoringFile *currentFile) void splitOrCondition(CppRefactoringFilePtr currentFile)
{ {
ChangeSet changes; ChangeSet changes;
@@ -866,8 +874,9 @@ private:
const int lExprEnd = currentFile->endOf(condition->left_expression); const int lExprEnd = currentFile->endOf(condition->left_expression);
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression)); changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(currentFile->range(pattern)); currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply();
} }
private: private:
@@ -897,7 +906,7 @@ public:
ExpressionAST *literal = 0; ExpressionAST *literal = 0;
Type type = TypeNone; Type type = TypeNone;
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
if (path.isEmpty()) if (path.isEmpty())
return noResult(); // nothing to do return noResult(); // nothing to do
@@ -906,7 +915,7 @@ public:
if (! literal) { if (! literal) {
literal = path.last()->asNumericLiteral(); literal = path.last()->asNumericLiteral();
if (!literal || !file.tokenAt(literal->asNumericLiteral()->literal_token).is(T_CHAR_LITERAL)) if (!literal || !file->tokenAt(literal->asNumericLiteral()->literal_token).is(T_CHAR_LITERAL))
return noResult(); return noResult();
else else
type = TypeChar; type = TypeChar;
@@ -919,7 +928,7 @@ public:
if (call->base_expression) { if (call->base_expression) {
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) { if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) { if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
const QByteArray id(file.tokenAt(functionName->identifier_token).identifier->chars()); const QByteArray id(file->tokenAt(functionName->identifier_token).identifier->chars());
if (id == "QT_TRANSLATE_NOOP" || id == "tr" || id == "trUtf8" if (id == "QT_TRANSLATE_NOOP" || id == "tr" || id == "trUtf8"
|| (type == TypeString && (id == "QLatin1String" || id == "QLatin1Literal")) || (type == TypeString && (id == "QLatin1String" || id == "QLatin1Literal"))
@@ -932,7 +941,7 @@ public:
} }
if (type == TypeString) { if (type == TypeString) {
if (file.charAt(file.startOf(literal)) == QLatin1Char('@')) if (file->charAt(file->startOf(literal)) == QLatin1Char('@'))
type = TypeObjCString; type = TypeObjCString;
} }
return singleResult(new Operation(interface, return singleResult(new Operation(interface,
@@ -959,7 +968,7 @@ private:
"Enclose in QLatin1String(...)")); "Enclose in QLatin1String(...)"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -974,7 +983,8 @@ private:
changes.insert(currentFile->endOf(literal), ")"); changes.insert(currentFile->endOf(literal), ")");
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
private: private:
@@ -1019,7 +1029,7 @@ public:
if (call->base_expression) { if (call->base_expression) {
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) { if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) { if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
const QByteArray id(interface->currentFile().tokenAt(functionName->identifier_token).identifier->chars()); const QByteArray id(interface->currentFile()->tokenAt(functionName->identifier_token).identifier->chars());
if (id == "tr" || id == "trUtf8" if (id == "tr" || id == "trUtf8"
|| id == "translate" || id == "translate"
@@ -1083,7 +1093,7 @@ private:
setDescription(QApplication::translate("CppTools::QuickFix", "Mark as Translatable")); setDescription(QApplication::translate("CppTools::QuickFix", "Mark as Translatable"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -1100,7 +1110,8 @@ private:
changes.insert(startPos, replacement); changes.insert(startPos, replacement);
changes.insert(currentFile->endOf(m_literal), QLatin1String(")")); changes.insert(currentFile->endOf(m_literal), QLatin1String(")"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
private: private:
@@ -1125,7 +1136,7 @@ class CStringToNSString: public CppQuickFixFactory
public: public:
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface) virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{ {
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
if (interface->editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE) if (interface->editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
return noResult(); return noResult();
@@ -1142,7 +1153,7 @@ public:
if (! stringLiteral) if (! stringLiteral)
return noResult(); return noResult();
else if (file.charAt(file.startOf(stringLiteral)) == QLatin1Char('@')) else if (file->charAt(file->startOf(stringLiteral)) == QLatin1Char('@'))
return noResult(); // it's already an objc string literal. return noResult(); // it's already an objc string literal.
else if (path.size() > 1) { else if (path.size() > 1) {
@@ -1150,7 +1161,7 @@ public:
if (call->base_expression) { if (call->base_expression) {
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) { if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) { if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
const QByteArray id(interface->currentFile().tokenAt(functionName->identifier_token).identifier->chars()); const QByteArray id(interface->currentFile()->tokenAt(functionName->identifier_token).identifier->chars());
if (id == "QLatin1String" || id == "QLatin1Literal") if (id == "QLatin1String" || id == "QLatin1Literal")
qlatin1Call = call; qlatin1Call = call;
@@ -1176,7 +1187,7 @@ private:
"Convert to Objective-C String Literal")); "Convert to Objective-C String Literal"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
@@ -1187,7 +1198,8 @@ private:
changes.insert(currentFile->startOf(stringLiteral), "@"); changes.insert(currentFile->startOf(stringLiteral), "@");
} }
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
private: private:
@@ -1222,7 +1234,7 @@ public:
QList<QuickFixOperation::Ptr> result; QList<QuickFixOperation::Ptr> result;
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
if (path.isEmpty()) if (path.isEmpty())
return result; // nothing to do return result; // nothing to do
@@ -1232,7 +1244,7 @@ public:
if (! literal) if (! literal)
return result; return result;
Token token = file.tokenAt(literal->asNumericLiteral()->literal_token); Token token = file->tokenAt(literal->asNumericLiteral()->literal_token);
if (!token.is(T_NUMERIC_LITERAL)) if (!token.is(T_NUMERIC_LITERAL))
return result; return result;
const NumericLiteral *numeric = token.number; const NumericLiteral *numeric = token.number;
@@ -1254,7 +1266,7 @@ public:
return result; return result;
const int priority = path.size() - 1; // very high priority const int priority = path.size() - 1; // very high priority
const int start = file.startOf(literal); const int start = file->startOf(literal);
const char * const str = numeric->chars(); const char * const str = numeric->chars();
if (!numeric->isHex()) { if (!numeric->isHex()) {
@@ -1328,11 +1340,12 @@ private:
, replacement(replacement) , replacement(replacement)
{} {}
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile, const CppRefactoringChanges &)
{ {
ChangeSet changes; ChangeSet changes;
changes.replace(start, end, replacement); changes.replace(start, end, replacement);
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
protected: protected:
@@ -1407,7 +1420,8 @@ private:
"#include Header File")); "#include Header File"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile,
const CppRefactoringChanges &)
{ {
Q_ASSERT(fwdClass != 0); Q_ASSERT(fwdClass != 0);
@@ -1464,7 +1478,8 @@ private:
Utils::ChangeSet changes; Utils::ChangeSet changes;
changes.insert(pos, QString("#include <%1>\n").arg(QFileInfo(best).fileName())); changes.insert(pos, QString("#include <%1>\n").arg(QFileInfo(best).fileName()));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
} }
@@ -1488,15 +1503,15 @@ public:
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface) virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{ {
const QList<AST *> &path = interface->path(); const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile(); CppRefactoringFilePtr file = interface->currentFile();
for (int index = path.size() - 1; index != -1; --index) { for (int index = path.size() - 1; index != -1; --index) {
if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) { if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) {
if (binary->left_expression && binary->right_expression && file.tokenAt(binary->binary_op_token).is(T_EQUAL)) { if (binary->left_expression && binary->right_expression && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) {
IdExpressionAST *idExpr = binary->left_expression->asIdExpression(); IdExpressionAST *idExpr = binary->left_expression->asIdExpression();
if (interface->isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) { if (interface->isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
SimpleNameAST *nameAST = idExpr->name->asSimpleName(); SimpleNameAST *nameAST = idExpr->name->asSimpleName();
const QList<LookupItem> results = interface->context().lookup(nameAST->name, file.scopeAt(nameAST->firstToken())); const QList<LookupItem> results = interface->context().lookup(nameAST->name, file->scopeAt(nameAST->firstToken()));
Declaration *decl = 0; Declaration *decl = 0;
foreach (const LookupItem &r, results) { foreach (const LookupItem &r, results) {
if (! r.declaration()) if (! r.declaration())
@@ -1531,7 +1546,8 @@ private:
setDescription(QApplication::translate("CppTools::QuickFix", "Add Local Declaration")); setDescription(QApplication::translate("CppTools::QuickFix", "Add Local Declaration"));
} }
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &currentFile,
const CppRefactoringChanges &)
{ {
TypeOfExpression typeOfExpression; TypeOfExpression typeOfExpression;
typeOfExpression.init(assistInterface()->semanticInfo().doc, typeOfExpression.init(assistInterface()->semanticInfo().doc,
@@ -1565,7 +1581,8 @@ private:
Utils::ChangeSet changes; Utils::ChangeSet changes;
changes.insert(currentFile->startOf(binaryAST), ty); changes.insert(currentFile->startOf(binaryAST), ty);
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->apply();
} }
} }
} }
@@ -1626,7 +1643,8 @@ private:
"Convert to Camel Case")); "Convert to Camel Case"));
} }
virtual void performChanges(CppRefactoringFile *, CppRefactoringChanges *) virtual void performChanges(const CppRefactoringFilePtr &,
const CppRefactoringChanges &)
{ {
for (int i = 1; i < m_name.length(); ++i) { for (int i = 1; i < m_name.length(); ++i) {
QCharRef c = m_name[i]; QCharRef c = m_name[i];

View File

@@ -49,64 +49,101 @@ using namespace CPlusPlus;
using namespace CppTools; using namespace CppTools;
using namespace Utils; using namespace Utils;
CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot) class CppTools::CppRefactoringChangesData : public TextEditor::RefactoringChangesData
: m_snapshot(snapshot)
, m_modelManager(Internal::CppModelManager::instance())
{ {
Q_ASSERT(m_modelManager); public:
m_workingCopy = m_modelManager->workingCopy(); CppRefactoringChangesData(const Snapshot &snapshot)
: m_snapshot(snapshot)
, m_modelManager(Internal::CppModelManager::instance())
, m_workingCopy(m_modelManager->workingCopy())
{}
virtual void indentSelection(const QTextCursor &selection,
const QString &fileName,
const TextEditor::BaseTextEditorWidget *textEditor) const
{
// ### shares code with CPPEditor::indent()
QTextDocument *doc = selection.document();
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(fileName, textEditor);
// TODO: add similar method like above one
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
CppToolsSettings::instance()->cppCodeStylePreferences()->settings());
codeFormatter.updateStateUntil(block);
do {
int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
tabSettings.indentLine(block, indent + padding, padding);
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
}
virtual void fileChanged(const QString &fileName)
{
m_modelManager->updateSourceFiles(QStringList(fileName));
}
CPlusPlus::Snapshot m_snapshot;
CPlusPlus::CppModelManagerInterface *m_modelManager;
CPlusPlus::CppModelManagerInterface::WorkingCopy m_workingCopy;
};
CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
: RefactoringChanges(new CppRefactoringChangesData(snapshot))
{
}
CppRefactoringChangesData *CppRefactoringChanges::data() const
{
return static_cast<CppRefactoringChangesData *>(m_data.data());
}
CppRefactoringFilePtr CppRefactoringChanges::file(TextEditor::BaseTextEditorWidget *editor, const Document::Ptr &document)
{
CppRefactoringFilePtr result(new CppRefactoringFile(editor));
result->setCppDocument(document);
return result;
}
CppRefactoringFilePtr CppRefactoringChanges::file(const QString &fileName) const
{
CppRefactoringFilePtr result(new CppRefactoringFile(fileName, m_data));
return result;
}
CppRefactoringFileConstPtr CppRefactoringChanges::fileNoEditor(const QString &fileName) const
{
QTextDocument *document = 0;
if (data()->m_workingCopy.contains(fileName))
document = new QTextDocument(data()->m_workingCopy.source(fileName));
CppRefactoringFilePtr result(new CppRefactoringFile(document, fileName));
result->m_data = m_data;
Document::Ptr cppDocument = data()->m_snapshot.document(fileName);
if (cppDocument)
result->setCppDocument(cppDocument);
return result;
} }
const Snapshot &CppRefactoringChanges::snapshot() const const Snapshot &CppRefactoringChanges::snapshot() const
{ {
return m_snapshot; return data()->m_snapshot;
} }
CppRefactoringFile CppRefactoringChanges::file(const QString &fileName) CppRefactoringFile::CppRefactoringFile(const QString &fileName, const QSharedPointer<TextEditor::RefactoringChangesData> &data)
: RefactoringFile(fileName, data)
{ {
return CppRefactoringFile(fileName, this); const Snapshot &snapshot = this->data()->m_snapshot;
}
void CppRefactoringChanges::indentSelection(const QTextCursor &selection,
const QString &fileName,
const TextEditor::BaseTextEditorWidget *textEditor) const
{
// ### shares code with CPPEditor::indent()
QTextDocument *doc = selection.document();
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(fileName, textEditor);
// TODO: add similar method like above one
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
CppToolsSettings::instance()->cppCodeStylePreferences()->settings());
codeFormatter.updateStateUntil(block);
do {
int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
tabSettings.indentLine(block, indent + padding, padding);
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
}
void CppRefactoringChanges::fileChanged(const QString &fileName)
{
m_modelManager->updateSourceFiles(QStringList(fileName));
}
CppRefactoringFile::CppRefactoringFile()
{ }
CppRefactoringFile::CppRefactoringFile(const QString &fileName, CppRefactoringChanges *refactoringChanges)
: RefactoringFile(fileName, refactoringChanges)
{
const Snapshot &snapshot = refactoringChanges->snapshot();
m_cppDocument = snapshot.document(fileName); m_cppDocument = snapshot.document(fileName);
} }
@@ -124,7 +161,7 @@ Document::Ptr CppRefactoringFile::cppDocument() const
!m_cppDocument->translationUnit()->ast()) { !m_cppDocument->translationUnit()->ast()) {
const QString source = document()->toPlainText(); const QString source = document()->toPlainText();
const QString name = fileName(); const QString name = fileName();
const Snapshot &snapshot = refactoringChanges()->snapshot(); const Snapshot &snapshot = data()->m_snapshot;
const QByteArray contents = snapshot.preprocessedCode(source, name); const QByteArray contents = snapshot.preprocessedCode(source, name);
m_cppDocument = snapshot.documentFromSource(contents, name); m_cppDocument = snapshot.documentFromSource(contents, name);
@@ -233,7 +270,13 @@ const Token &CppRefactoringFile::tokenAt(unsigned index) const
return cppDocument()->translationUnit()->tokenAt(index); return cppDocument()->translationUnit()->tokenAt(index);
} }
CppRefactoringChanges *CppRefactoringFile::refactoringChanges() const CppRefactoringChangesData *CppRefactoringFile::data() const
{ {
return static_cast<CppRefactoringChanges *>(m_refactoringChanges); return static_cast<CppRefactoringChangesData *>(m_data.data());
}
void CppRefactoringFile::fileChanged()
{
m_cppDocument.clear();
RefactoringFile::fileChanged();
} }

View File

@@ -45,14 +45,14 @@
namespace CppTools { namespace CppTools {
class CppRefactoringChanges; class CppRefactoringChanges;
class CppRefactoringFile;
class CppRefactoringChangesData;
typedef QSharedPointer<CppRefactoringFile> CppRefactoringFilePtr;
typedef QSharedPointer<const CppRefactoringFile> CppRefactoringFileConstPtr;
class CPPTOOLS_EXPORT CppRefactoringFile: public TextEditor::RefactoringFile class CPPTOOLS_EXPORT CppRefactoringFile: public TextEditor::RefactoringFile
{ {
public: public:
CppRefactoringFile();
CppRefactoringFile(QTextDocument *document, const QString &fileName = QString());
CppRefactoringFile(TextEditor::BaseTextEditorWidget *editor);
CPlusPlus::Document::Ptr cppDocument() const; CPlusPlus::Document::Ptr cppDocument() const;
void setCppDocument(CPlusPlus::Document::Ptr document); void setCppDocument(CPlusPlus::Document::Ptr document);
@@ -78,10 +78,12 @@ public:
QString textOf(const CPlusPlus::AST *ast) const; QString textOf(const CPlusPlus::AST *ast) const;
protected: protected:
CppRefactoringFile(const QString &fileName, CppRefactoringChanges *refactoringChanges); CppRefactoringFile(const QString &fileName, const QSharedPointer<TextEditor::RefactoringChangesData> &data);
CppRefactoringFile(QTextDocument *document, const QString &fileName);
CppRefactoringFile(TextEditor::BaseTextEditorWidget *editor);
private: CppRefactoringChangesData *data() const;
CppRefactoringChanges *refactoringChanges() const; virtual void fileChanged();
mutable CPlusPlus::Document::Ptr m_cppDocument; mutable CPlusPlus::Document::Ptr m_cppDocument;
@@ -93,21 +95,16 @@ class CPPTOOLS_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChang
public: public:
CppRefactoringChanges(const CPlusPlus::Snapshot &snapshot); CppRefactoringChanges(const CPlusPlus::Snapshot &snapshot);
static CppRefactoringFilePtr file(TextEditor::BaseTextEditorWidget *editor,
const CPlusPlus::Document::Ptr &document);
CppRefactoringFilePtr file(const QString &fileName) const;
// safe to use from non-gui threads
CppRefactoringFileConstPtr fileNoEditor(const QString &fileName) const;
const CPlusPlus::Snapshot &snapshot() const; const CPlusPlus::Snapshot &snapshot() const;
CppRefactoringFile file(const QString &fileName);
private: private:
virtual void indentSelection(const QTextCursor &selection, CppRefactoringChangesData *data() const;
const QString &fileName,
const TextEditor::BaseTextEditorWidget *textEditor) const;
virtual void fileChanged(const QString &fileName);
private:
CPlusPlus::Document::Ptr m_thisDocument;
CPlusPlus::Snapshot m_snapshot;
CPlusPlus::LookupContext m_context;
CPlusPlus::CppModelManagerInterface *m_modelManager;
CPlusPlus::CppModelManagerInterface::WorkingCopy m_workingCopy;
}; };
} // namespace CppTools } // namespace CppTools

View File

@@ -287,7 +287,7 @@ InsertionLocation::InsertionLocation(const QString &fileName,
, m_column(column) , m_column(column)
{} {}
InsertionPointLocator::InsertionPointLocator(CppRefactoringChanges *refactoringChanges) InsertionPointLocator::InsertionPointLocator(const CppRefactoringChanges &refactoringChanges)
: m_refactoringChanges(refactoringChanges) : m_refactoringChanges(refactoringChanges)
{ {
} }
@@ -297,7 +297,7 @@ InsertionLocation InsertionPointLocator::methodDeclarationInClass(
const Class *clazz, const Class *clazz,
AccessSpec xsSpec) const AccessSpec xsSpec) const
{ {
const Document::Ptr doc = m_refactoringChanges->file(fileName).cppDocument(); const Document::Ptr doc = m_refactoringChanges.file(fileName)->cppDocument();
if (doc) { if (doc) {
FindInClass find(doc, clazz, xsSpec); FindInClass find(doc, clazz, xsSpec);
return find(); return find();
@@ -434,11 +434,11 @@ QList<InsertionLocation> InsertionPointLocator::methodDefinition(
target = candidate; target = candidate;
} }
Document::Ptr doc = m_refactoringChanges->file(target).cppDocument(); Document::Ptr doc = m_refactoringChanges.file(target)->cppDocument();
if (doc.isNull()) if (doc.isNull())
return result; return result;
Snapshot simplified = m_refactoringChanges->snapshot().simplified(doc); Snapshot simplified = m_refactoringChanges.snapshot().simplified(doc);
if (Symbol *s = simplified.findMatchingDefinition(declaration)) { if (Symbol *s = simplified.findMatchingDefinition(declaration)) {
if (Function *f = s->asFunction()) { if (Function *f = s->asFunction()) {
if (f->isConst() == declaration->type().isConst() if (f->isConst() == declaration->type().isConst()

View File

@@ -39,11 +39,10 @@
#include <CPlusPlusForwardDeclarations.h> #include <CPlusPlusForwardDeclarations.h>
#include <cplusplus/CppDocument.h> #include <cplusplus/CppDocument.h>
#include <cpptools/cpprefactoringchanges.h>
namespace CppTools { namespace CppTools {
class CppRefactoringChanges;
class CPPTOOLS_EXPORT InsertionLocation class CPPTOOLS_EXPORT InsertionLocation
{ {
public: public:
@@ -100,7 +99,7 @@ public:
}; };
public: public:
InsertionPointLocator(CppRefactoringChanges *refactoringChanges); InsertionPointLocator(const CppRefactoringChanges &refactoringChanges);
InsertionLocation methodDeclarationInClass(const QString &fileName, InsertionLocation methodDeclarationInClass(const QString &fileName,
const CPlusPlus::Class *clazz, const CPlusPlus::Class *clazz,
@@ -109,7 +108,7 @@ public:
QList<InsertionLocation> methodDefinition(CPlusPlus::Declaration *declaration) const; QList<InsertionLocation> methodDefinition(CPlusPlus::Declaration *declaration) const;
private: private:
CppRefactoringChanges *m_refactoringChanges; CppRefactoringChanges m_refactoringChanges;
}; };
} // namespace CppTools } // namespace CppTools

View File

@@ -297,7 +297,7 @@ static void addDeclaration(const Snapshot &snapshot,
declaration += QLatin1String(";\n"); declaration += QLatin1String(";\n");
CppTools::CppRefactoringChanges refactoring(snapshot); CppTools::CppRefactoringChanges refactoring(snapshot);
CppTools::InsertionPointLocator find(&refactoring); CppTools::InsertionPointLocator find(refactoring);
const CppTools::InsertionLocation loc = find.methodDeclarationInClass( const CppTools::InsertionLocation loc = find.methodDeclarationInClass(
fileName, cl, CppTools::InsertionPointLocator::PrivateSlot); fileName, cl, CppTools::InsertionPointLocator::PrivateSlot);

View File

@@ -114,7 +114,8 @@ public:
} }
} }
virtual void performChanges(QmlJSRefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring) virtual void performChanges(QmlJSRefactoringFilePtr currentFile,
const QmlJSRefactoringChanges &refactoring)
{ {
QString componentName = m_componentName; QString componentName = m_componentName;
QString path = QFileInfo(fileName()).path(); QString path = QFileInfo(fileName()).path();
@@ -142,7 +143,7 @@ public:
+ QLatin1String("}\n"); + QLatin1String("}\n");
// stop if we can't create the new file // stop if we can't create the new file
if (!refactoring->createFile(newFileName, txt)) if (!refactoring.createFile(newFileName, txt))
return; return;
QString replacement = componentName + QLatin1String(" {\n"); QString replacement = componentName + QLatin1String(" {\n");
@@ -152,8 +153,9 @@ public:
Utils::ChangeSet changes; Utils::ChangeSet changes;
changes.replace(start, end, replacement); changes.replace(start, end, replacement);
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(Range(start, end + 1)); currentFile->appendIndentRange(Range(start, end + 1));
currentFile->apply();
} }
}; };
@@ -163,13 +165,13 @@ public:
QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match( QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(
const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface) const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface)
{ {
const int pos = interface->currentFile().cursor().position(); const int pos = interface->currentFile()->cursor().position();
QList<Node *> path = interface->semanticInfo().rangePath(pos); QList<Node *> path = interface->semanticInfo().rangePath(pos);
for (int i = path.size() - 1; i >= 0; --i) { for (int i = path.size() - 1; i >= 0; --i) {
Node *node = path.at(i); Node *node = path.at(i);
if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) { if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) {
if (!interface->currentFile().isCursorOn(objDef->qualifiedTypeNameId)) if (!interface->currentFile()->isCursorOn(objDef->qualifiedTypeNameId))
return noResult(); return noResult();
// check that the node is not the root node // check that the node is not the root node
if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) { if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) {

View File

@@ -66,11 +66,10 @@ QmlJSQuickFixOperation::~QmlJSQuickFixOperation()
void QmlJSQuickFixOperation::perform() void QmlJSQuickFixOperation::perform()
{ {
QmlJSRefactoringChanges refactoring(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(), QmlJSRefactoringChanges refactoring(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(),
//_state.snapshot());
m_interface->semanticInfo().snapshot); m_interface->semanticInfo().snapshot);
QmlJSRefactoringFile current = refactoring.file(fileName()); QmlJSRefactoringFilePtr current = refactoring.file(fileName());
performChanges(&current, &refactoring); performChanges(current, refactoring);
} }
const QmlJSQuickFixAssistInterface *QmlJSQuickFixOperation::assistInterface() const const QmlJSQuickFixAssistInterface *QmlJSQuickFixOperation::assistInterface() const

View File

@@ -79,8 +79,8 @@ public:
protected: protected:
typedef Utils::ChangeSet::Range Range; typedef Utils::ChangeSet::Range Range;
virtual void performChanges(QmlJSTools::QmlJSRefactoringFile *currentFile, virtual void performChanges(QmlJSTools::QmlJSRefactoringFilePtr currentFile,
QmlJSTools::QmlJSRefactoringChanges *refactoring) = 0; const QmlJSTools::QmlJSRefactoringChanges &refactoring) = 0;
const Internal::QmlJSQuickFixAssistInterface *assistInterface() const; const Internal::QmlJSQuickFixAssistInterface *assistInterface() const;

View File

@@ -51,6 +51,7 @@ QmlJSQuickFixAssistInterface::QmlJSQuickFixAssistInterface(QmlJSTextEditorWidget
: DefaultAssistInterface(editor->document(), editor->position(), editor->file(), reason) : DefaultAssistInterface(editor->document(), editor->position(), editor->file(), reason)
, m_editor(editor) , m_editor(editor)
, m_semanticInfo(editor->semanticInfo()) , m_semanticInfo(editor->semanticInfo())
, m_currentFile(QmlJSRefactoringChanges::file(m_editor, m_semanticInfo.document))
{} {}
QmlJSQuickFixAssistInterface::~QmlJSQuickFixAssistInterface() QmlJSQuickFixAssistInterface::~QmlJSQuickFixAssistInterface()
@@ -61,9 +62,9 @@ const SemanticInfo &QmlJSQuickFixAssistInterface::semanticInfo() const
return m_semanticInfo; return m_semanticInfo;
} }
const QmlJSTools::QmlJSRefactoringFile QmlJSQuickFixAssistInterface::currentFile() const QmlJSRefactoringFilePtr QmlJSQuickFixAssistInterface::currentFile() const
{ {
return QmlJSRefactoringFile(m_editor, m_semanticInfo.document); return m_currentFile;
} }
QWidget *QmlJSQuickFixAssistInterface::widget() const QWidget *QmlJSQuickFixAssistInterface::widget() const

View File

@@ -51,12 +51,13 @@ public:
virtual ~QmlJSQuickFixAssistInterface(); virtual ~QmlJSQuickFixAssistInterface();
const SemanticInfo &semanticInfo() const; const SemanticInfo &semanticInfo() const;
const QmlJSTools::QmlJSRefactoringFile currentFile() const; QmlJSTools::QmlJSRefactoringFilePtr currentFile() const;
QWidget *widget() const; QWidget *widget() const;
private: private:
QmlJSTextEditorWidget *m_editor; QmlJSTextEditorWidget *m_editor;
SemanticInfo m_semanticInfo; SemanticInfo m_semanticInfo;
QmlJSTools::QmlJSRefactoringFilePtr m_currentFile;
}; };

View File

@@ -70,7 +70,7 @@ public:
{ {
UiObjectInitializer *objectInitializer = 0; UiObjectInitializer *objectInitializer = 0;
const int pos = interface->currentFile().cursor().position(); const int pos = interface->currentFile()->cursor().position();
if (QmlJS::AST::Node *member = interface->semanticInfo().rangeAt(pos)) { if (QmlJS::AST::Node *member = interface->semanticInfo().rangeAt(pos)) {
if (QmlJS::AST::UiObjectBinding *b = QmlJS::AST::cast<QmlJS::AST::UiObjectBinding *>(member)) { if (QmlJS::AST::UiObjectBinding *b = QmlJS::AST::cast<QmlJS::AST::UiObjectBinding *>(member)) {
@@ -104,7 +104,8 @@ private:
"Split initializer")); "Split initializer"));
} }
virtual void performChanges(QmlJSRefactoringFile *currentFile, QmlJSRefactoringChanges *) virtual void performChanges(QmlJSRefactoringFilePtr currentFile,
const QmlJSRefactoringChanges &)
{ {
Q_ASSERT(_objectInitializer != 0); Q_ASSERT(_objectInitializer != 0);
@@ -123,9 +124,10 @@ private:
changes.insert(currentFile->startOf(_objectInitializer->rbraceToken), changes.insert(currentFile->startOf(_objectInitializer->rbraceToken),
QLatin1String("\n")); QLatin1String("\n"));
currentFile->change(changes); currentFile->setChangeSet(changes);
currentFile->indent(Range(currentFile->startOf(_objectInitializer->lbraceToken), currentFile->appendIndentRange(Range(currentFile->startOf(_objectInitializer->lbraceToken),
currentFile->startOf(_objectInitializer->rbraceToken))); currentFile->startOf(_objectInitializer->rbraceToken)));
currentFile->apply();
} }
}; };
}; };

View File

@@ -775,11 +775,12 @@ void QmlOutlineModel::reparentNodes(QmlOutlineItem *targetItem, int row, QList<Q
} }
QmlJSRefactoringChanges refactoring(ModelManagerInterface::instance(), m_semanticInfo.snapshot); QmlJSRefactoringChanges refactoring(ModelManagerInterface::instance(), m_semanticInfo.snapshot);
TextEditor::RefactoringFile file = refactoring.file(m_semanticInfo.document->fileName()); TextEditor::RefactoringFilePtr file = refactoring.file(m_semanticInfo.document->fileName());
file.change(changeSet); file->setChangeSet(changeSet);
foreach (const Utils::ChangeSet::Range &range, changedRanges) { foreach (const Utils::ChangeSet::Range &range, changedRanges) {
file.indent(range); file->appendIndentRange(range);
} }
file->apply();
} }
void QmlOutlineModel::moveObjectMember(AST::UiObjectMember *toMove, void QmlOutlineModel::moveObjectMember(AST::UiObjectMember *toMove,

View File

@@ -43,65 +43,82 @@
using namespace QmlJS; using namespace QmlJS;
using namespace QmlJSTools; using namespace QmlJSTools;
class QmlJSTools::QmlJSRefactoringChangesData : public TextEditor::RefactoringChangesData
{
public:
QmlJSRefactoringChangesData(ModelManagerInterface *modelManager,
const Snapshot &snapshot)
: m_modelManager(modelManager)
, m_snapshot(snapshot)
{}
virtual void indentSelection(const QTextCursor &selection,
const QString &fileName,
const TextEditor::BaseTextEditorWidget *textEditor) const
{
// ### shares code with QmlJSTextEditor::indent
QTextDocument *doc = selection.document();
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(fileName, textEditor);
QtStyleCodeFormatter codeFormatter(tabSettings);
codeFormatter.updateStateUntil(block);
do {
tabSettings.indentLine(block, codeFormatter.indentFor(block));
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
}
virtual void fileChanged(const QString &fileName)
{
m_modelManager->updateSourceFiles(QStringList(fileName), true);
}
QmlJS::ModelManagerInterface *m_modelManager;
QmlJS::Snapshot m_snapshot;
};
QmlJSRefactoringChanges::QmlJSRefactoringChanges(ModelManagerInterface *modelManager, QmlJSRefactoringChanges::QmlJSRefactoringChanges(ModelManagerInterface *modelManager,
const Snapshot &snapshot) const Snapshot &snapshot)
: m_modelManager(modelManager) : RefactoringChanges(new QmlJSRefactoringChangesData(modelManager, snapshot))
, m_snapshot(snapshot)
{ {
Q_ASSERT(modelManager); }
QmlJSRefactoringFilePtr QmlJSRefactoringChanges::file(const QString &fileName) const
{
return QmlJSRefactoringFilePtr(new QmlJSRefactoringFile(fileName, m_data));
}
QmlJSRefactoringFilePtr QmlJSRefactoringChanges::file(
TextEditor::BaseTextEditorWidget *editor, const Document::Ptr &document)
{
return QmlJSRefactoringFilePtr(new QmlJSRefactoringFile(editor, document));
} }
const Snapshot &QmlJSRefactoringChanges::snapshot() const const Snapshot &QmlJSRefactoringChanges::snapshot() const
{ {
return m_snapshot; return data()->m_snapshot;
} }
QmlJSRefactoringFile QmlJSRefactoringChanges::file(const QString &fileName) QmlJSRefactoringChangesData *QmlJSRefactoringChanges::data() const
{ {
return QmlJSRefactoringFile(fileName, this); return static_cast<QmlJSRefactoringChangesData *>(m_data.data());
} }
void QmlJSRefactoringChanges::indentSelection(const QTextCursor &selection, QmlJSRefactoringFile::QmlJSRefactoringFile(const QString &fileName, const QSharedPointer<TextEditor::RefactoringChangesData> &data)
const QString &fileName, : RefactoringFile(fileName, data)
const TextEditor::BaseTextEditorWidget *textEditor) const
{
// ### shares code with QmlJSTextEditor::indent
QTextDocument *doc = selection.document();
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(fileName, textEditor);
QtStyleCodeFormatter codeFormatter(tabSettings);
codeFormatter.updateStateUntil(block);
do {
tabSettings.indentLine(block, codeFormatter.indentFor(block));
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
}
void QmlJSRefactoringChanges::fileChanged(const QString &fileName)
{
m_modelManager->updateSourceFiles(QStringList(fileName), true);
}
QmlJSRefactoringFile::QmlJSRefactoringFile()
{ }
QmlJSRefactoringFile::QmlJSRefactoringFile(const QString &fileName, QmlJSRefactoringChanges *refactoringChanges)
: RefactoringFile(fileName, refactoringChanges)
{ } { }
QmlJSRefactoringFile::QmlJSRefactoringFile(TextEditor::BaseTextEditorWidget *editor, QmlJS::Document::Ptr document) QmlJSRefactoringFile::QmlJSRefactoringFile(TextEditor::BaseTextEditorWidget *editor, QmlJS::Document::Ptr document)
: RefactoringFile() : RefactoringFile(editor)
, m_qmljsDocument(document) , m_qmljsDocument(document)
{ {
m_fileName = document->fileName(); m_fileName = document->fileName();
m_editor = editor;
} }
Document::Ptr QmlJSRefactoringFile::qmljsDocument() const Document::Ptr QmlJSRefactoringFile::qmljsDocument() const
@@ -109,7 +126,7 @@ Document::Ptr QmlJSRefactoringFile::qmljsDocument() const
if (!m_qmljsDocument) { if (!m_qmljsDocument) {
const QString source = document()->toPlainText(); const QString source = document()->toPlainText();
const QString name = fileName(); const QString name = fileName();
const Snapshot &snapshot = refactoringChanges()->snapshot(); const Snapshot &snapshot = data()->m_snapshot;
m_qmljsDocument = snapshot.documentFromSource(source, name); m_qmljsDocument = snapshot.documentFromSource(source, name);
m_qmljsDocument->parse(); m_qmljsDocument->parse();
@@ -145,7 +162,13 @@ bool QmlJSRefactoringFile::isCursorOn(AST::UiQualifiedId *ast) const
return pos <= ast->identifierToken.end(); return pos <= ast->identifierToken.end();
} }
QmlJSRefactoringChanges *QmlJSRefactoringFile::refactoringChanges() const QmlJSRefactoringChangesData *QmlJSRefactoringFile::data() const
{ {
return static_cast<QmlJSRefactoringChanges *>(m_refactoringChanges); return static_cast<QmlJSRefactoringChangesData *>(m_data.data());
}
void QmlJSRefactoringFile::fileChanged()
{
m_qmljsDocument.clear();
RefactoringFile::fileChanged();
} }

View File

@@ -46,14 +46,13 @@ class ModelManagerInterface;
namespace QmlJSTools { namespace QmlJSTools {
class QmlJSRefactoringChanges; class QmlJSRefactoringChanges;
class QmlJSRefactoringFile;
class QmlJSRefactoringChangesData;
typedef QSharedPointer<QmlJSRefactoringFile> QmlJSRefactoringFilePtr;
class QMLJSTOOLS_EXPORT QmlJSRefactoringFile: public TextEditor::RefactoringFile class QMLJSTOOLS_EXPORT QmlJSRefactoringFile: public TextEditor::RefactoringFile
{ {
public: public:
QmlJSRefactoringFile();
QmlJSRefactoringFile(const QString &fileName, QmlJSRefactoringChanges *refactoringChanges);
QmlJSRefactoringFile(TextEditor::BaseTextEditorWidget *editor, QmlJS::Document::Ptr document);
QmlJS::Document::Ptr qmljsDocument() const; QmlJS::Document::Ptr qmljsDocument() const;
/*! /*!
@@ -65,10 +64,16 @@ public:
bool isCursorOn(QmlJS::AST::UiObjectMember *ast) const; bool isCursorOn(QmlJS::AST::UiObjectMember *ast) const;
bool isCursorOn(QmlJS::AST::UiQualifiedId *ast) const; bool isCursorOn(QmlJS::AST::UiQualifiedId *ast) const;
private: protected:
QmlJSRefactoringChanges *refactoringChanges() const; QmlJSRefactoringFile(const QString &fileName, const QSharedPointer<TextEditor::RefactoringChangesData> &data);
QmlJSRefactoringFile(TextEditor::BaseTextEditorWidget *editor, QmlJS::Document::Ptr document);
QmlJSRefactoringChangesData *data() const;
virtual void fileChanged();
mutable QmlJS::Document::Ptr m_qmljsDocument; mutable QmlJS::Document::Ptr m_qmljsDocument;
friend class QmlJSRefactoringChanges;
}; };
@@ -78,19 +83,14 @@ public:
QmlJSRefactoringChanges(QmlJS::ModelManagerInterface *modelManager, QmlJSRefactoringChanges(QmlJS::ModelManagerInterface *modelManager,
const QmlJS::Snapshot &snapshot); const QmlJS::Snapshot &snapshot);
static QmlJSRefactoringFilePtr file(TextEditor::BaseTextEditorWidget *editor,
const QmlJS::Document::Ptr &document);
QmlJSRefactoringFilePtr file(const QString &fileName) const;
const QmlJS::Snapshot &snapshot() const; const QmlJS::Snapshot &snapshot() const;
QmlJSRefactoringFile file(const QString &fileName);
private: private:
virtual void indentSelection(const QTextCursor &selection, QmlJSRefactoringChangesData *data() const;
const QString &fileName,
const TextEditor::BaseTextEditorWidget *textEditor) const;
virtual void fileChanged(const QString &fileName);
private:
QmlJS::ModelManagerInterface *m_modelManager;
QmlJS::Snapshot m_snapshot;
}; };
} // namespace QmlJSTools } // namespace QmlJSTools

View File

@@ -169,7 +169,7 @@ Core::IEditor *BaseTextEditorWidget::openEditorAt(const QString &fileName, int l
Core::IEditor *editor = editorManager->openEditor(fileName, editorKind, Core::IEditor *editor = editorManager->openEditor(fileName, editorKind,
flags, newEditor); flags, newEditor);
TextEditor::ITextEditor *texteditor = qobject_cast<TextEditor::ITextEditor *>(editor); TextEditor::ITextEditor *texteditor = qobject_cast<TextEditor::ITextEditor *>(editor);
if (texteditor) { if (texteditor && line != -1) {
texteditor->gotoLine(line, column); texteditor->gotoLine(line, column);
return texteditor; return texteditor;
} }

View File

@@ -50,17 +50,17 @@
using namespace TextEditor; using namespace TextEditor;
RefactoringChanges::RefactoringChanges() RefactoringChanges::RefactoringChanges()
: m_data(new RefactoringChangesData)
{}
RefactoringChanges::RefactoringChanges(RefactoringChangesData *data)
: m_data(data)
{} {}
RefactoringChanges::~RefactoringChanges() RefactoringChanges::~RefactoringChanges()
{ {}
if (!m_fileToOpen.isEmpty()) {
BaseTextEditorWidget::openEditorAt(m_fileToOpen, m_lineToOpen, m_columnToOpen);
}
}
BaseTextEditorWidget *RefactoringChanges::editorForFile(const QString &fileName, BaseTextEditorWidget *RefactoringChanges::editorForFile(const QString &fileName)
bool openIfClosed)
{ {
Core::EditorManager *editorManager = Core::EditorManager::instance(); Core::EditorManager *editorManager = Core::EditorManager::instance();
@@ -70,20 +70,7 @@ BaseTextEditorWidget *RefactoringChanges::editorForFile(const QString &fileName,
if (textEditor != 0) if (textEditor != 0)
return textEditor; return textEditor;
} }
return 0;
if (!openIfClosed)
return 0;
QFile file(fileName);
if (!file.exists()) {
if (!file.open(QIODevice::Append))
return 0;
file.close();
}
Core::IEditor *editor = editorManager->openEditor(fileName, QString(),
Core::EditorManager::NoActivate | Core::EditorManager::IgnoreNavigationHistory);
return qobject_cast<BaseTextEditorWidget *>(editor->widget());
} }
QList<QTextCursor> RefactoringChanges::rangesToSelections(QTextDocument *document, const QList<Range> &ranges) QList<QTextCursor> RefactoringChanges::rangesToSelections(QTextDocument *document, const QList<Range> &ranges)
@@ -102,12 +89,15 @@ QList<QTextCursor> RefactoringChanges::rangesToSelections(QTextDocument *documen
return selections; return selections;
} }
bool RefactoringChanges::createFile(const QString &fileName, const QString &contents, bool reindent, bool openEditor) bool RefactoringChanges::createFile(const QString &fileName, const QString &contents, bool reindent, bool openEditor) const
{ {
if (QFile::exists(fileName)) if (QFile::exists(fileName))
return false; return false;
BaseTextEditorWidget *editor = editorForFile(fileName, openEditor); BaseTextEditorWidget *editor = editorForFile(fileName);
if (!editor && openEditor) {
editor = this->openEditor(fileName, false, -1, -1);
}
QTextDocument *document; QTextDocument *document;
if (editor) if (editor)
@@ -123,7 +113,7 @@ bool RefactoringChanges::createFile(const QString &fileName, const QString &cont
if (reindent) { if (reindent) {
cursor.select(QTextCursor::Document); cursor.select(QTextCursor::Document);
indentSelection(cursor, fileName, editor); m_data->indentSelection(cursor, fileName, editor);
} }
cursor.endEditBlock(); cursor.endEditBlock();
@@ -137,12 +127,12 @@ bool RefactoringChanges::createFile(const QString &fileName, const QString &cont
return false; return false;
} }
fileChanged(fileName); m_data->fileChanged(fileName);
return true; return true;
} }
bool RefactoringChanges::removeFile(const QString &fileName) bool RefactoringChanges::removeFile(const QString &fileName) const
{ {
if (!QFile::exists(fileName)) if (!QFile::exists(fileName))
return false; return false;
@@ -152,119 +142,70 @@ bool RefactoringChanges::removeFile(const QString &fileName)
return true; return true;
} }
RefactoringFile RefactoringChanges::file(const QString &fileName) BaseTextEditorWidget *RefactoringChanges::openEditor(const QString &fileName, bool activate, int line, int column)
{ {
if (QFile::exists(fileName)) Core::EditorManager::OpenEditorFlags flags = Core::EditorManager::IgnoreNavigationHistory;
return RefactoringFile(fileName, this); if (!activate)
else flags |= Core::EditorManager::NoActivate;
return RefactoringFile(); if (line != -1) {
} // openEditorAt uses a 1-based line and a 0-based column!
column -= 1;
BaseTextEditorWidget *RefactoringChanges::openEditor(const QString &fileName, int pos)
{
BaseTextEditorWidget *editor = editorForFile(fileName, true);
if (pos != -1) {
QTextCursor cursor = editor->textCursor();
cursor.setPosition(pos);
editor->setTextCursor(cursor);
} }
return editor; Core::IEditor *editor = BaseTextEditorWidget::openEditorAt(
fileName, line, column, QString(), flags);
return qobject_cast<BaseTextEditorWidget *>(editor->widget());
} }
void RefactoringChanges::activateEditor(const QString &fileName, int line, int column) RefactoringFilePtr RefactoringChanges::file(BaseTextEditorWidget *editor)
{ {
m_fileToOpen = fileName; return RefactoringFilePtr(new RefactoringFile(editor));
m_lineToOpen = line;
m_columnToOpen = column;
} }
RefactoringFilePtr RefactoringChanges::file(const QString &fileName) const
RefactoringFile::RefactoringFile() {
: m_refactoringChanges(0) return RefactoringFilePtr(new RefactoringFile(fileName, m_data));
, m_document(0) }
, m_editor(0)
, m_openEditor(false)
{ }
RefactoringFile::RefactoringFile(QTextDocument *document, const QString &fileName) RefactoringFile::RefactoringFile(QTextDocument *document, const QString &fileName)
: m_fileName(fileName) : m_fileName(fileName)
, m_refactoringChanges(0)
, m_document(document) , m_document(document)
, m_editor(0) , m_editor(0)
, m_openEditor(false) , m_openEditor(false)
, m_activateEditor(false)
, m_editorCursorPosition(-1)
{ } { }
RefactoringFile::RefactoringFile(BaseTextEditorWidget *editor) RefactoringFile::RefactoringFile(BaseTextEditorWidget *editor)
: m_fileName(editor->file()->fileName()) : m_fileName(editor->file()->fileName())
, m_refactoringChanges(0)
, m_document(0) , m_document(0)
, m_editor(editor) , m_editor(editor)
, m_openEditor(false) , m_openEditor(false)
, m_activateEditor(false)
, m_editorCursorPosition(-1)
{ } { }
RefactoringFile::RefactoringFile(const QString &fileName, RefactoringChanges *refactoringChanges) RefactoringFile::RefactoringFile(const QString &fileName, const QSharedPointer<RefactoringChangesData> &data)
: m_fileName(fileName) : m_fileName(fileName)
, m_refactoringChanges(refactoringChanges) , m_data(data)
, m_document(0) , m_document(0)
, m_editor(0) , m_editor(0)
, m_openEditor(false) , m_openEditor(false)
, m_activateEditor(false)
, m_editorCursorPosition(-1)
{ {
m_editor = RefactoringChanges::editorForFile(fileName, false); m_editor = RefactoringChanges::editorForFile(fileName);
}
RefactoringFile::RefactoringFile(const RefactoringFile &other)
: m_fileName(other.m_fileName)
, m_refactoringChanges(other.m_refactoringChanges)
, m_document(0)
, m_editor(other.m_editor)
{
Q_ASSERT_X(!other.m_document && other.m_changes.isEmpty() && other.m_indentRanges.isEmpty(),
"RefactoringFile", "A refactoring file with changes is not copyable");
} }
RefactoringFile::~RefactoringFile() RefactoringFile::~RefactoringFile()
{ {
if (m_refactoringChanges && m_openEditor && !m_fileName.isEmpty())
m_editor = m_refactoringChanges->openEditor(m_fileName, -1);
// apply changes, if any
if (m_refactoringChanges && !(m_indentRanges.isEmpty() && m_changes.isEmpty())) {
QTextDocument *doc = mutableDocument();
{
QTextCursor c = cursor();
c.beginEditBlock();
// build indent selections now, applying the changeset will change locations
const QList<QTextCursor> &indentSelections =
RefactoringChanges::rangesToSelections(
doc, m_indentRanges);
// apply changes and reindent
m_changes.apply(&c);
foreach (const QTextCursor &selection, indentSelections) {
m_refactoringChanges->indentSelection(selection, m_fileName, m_editor);
}
c.endEditBlock();
}
// if this document doesn't have an editor, write the result to a file
if (!m_editor && !m_fileName.isEmpty()) {
Utils::FileSaver saver(m_fileName);
saver.write(doc->toPlainText().toUtf8());
saver.finalize(Core::ICore::instance()->mainWindow());
}
if (!m_fileName.isEmpty())
m_refactoringChanges->fileChanged(m_fileName);
}
delete m_document; delete m_document;
} }
bool RefactoringFile::isValid() const bool RefactoringFile::isValid() const
{ {
return !m_fileName.isEmpty(); if (m_fileName.isEmpty())
return false;
return document();
} }
const QTextDocument *RefactoringFile::document() const const QTextDocument *RefactoringFile::document() const
@@ -278,7 +219,7 @@ QTextDocument *RefactoringFile::mutableDocument() const
return m_editor->document(); return m_editor->document();
else if (!m_document) { else if (!m_document) {
QString fileContents; QString fileContents;
if (!m_fileName.isEmpty()) { if (!m_fileName.isEmpty() && QFile::exists(m_fileName)) {
Utils::FileReader reader; Utils::FileReader reader;
if (reader.fetch(m_fileName, Core::ICore::instance()->mainWindow())) if (reader.fetch(m_fileName, Core::ICore::instance()->mainWindow()))
fileContents = QString::fromUtf8(reader.data()); fileContents = QString::fromUtf8(reader.data());
@@ -292,8 +233,10 @@ const QTextCursor RefactoringFile::cursor() const
{ {
if (m_editor) if (m_editor)
return m_editor->textCursor(); return m_editor->textCursor();
else if (!m_fileName.isEmpty()) else if (!m_fileName.isEmpty()) {
return QTextCursor(mutableDocument()); if (QTextDocument *doc = mutableDocument())
return QTextCursor(doc);
}
return QTextCursor(); return QTextCursor();
} }
@@ -312,6 +255,17 @@ int RefactoringFile::position(unsigned line, unsigned column) const
return -1; return -1;
} }
void RefactoringFile::lineAndColumn(int offset, unsigned *line, unsigned *column) const
{
Q_ASSERT(line);
Q_ASSERT(column);
Q_ASSERT(offset >= 0);
QTextCursor c(cursor());
c.setPosition(offset);
*line = c.blockNumber() + 1;
*column = c.positionInBlock() + 1;
}
QChar RefactoringFile::charAt(int pos) const QChar RefactoringFile::charAt(int pos) const
{ {
if (const QTextDocument *doc = document()) if (const QTextDocument *doc = document())
@@ -332,28 +286,87 @@ QString RefactoringFile::textOf(const Range &range) const
return textOf(range.start, range.end); return textOf(range.start, range.end);
} }
bool RefactoringFile::change(const Utils::ChangeSet &changeSet, bool openEditor) void RefactoringFile::setChangeSet(const Utils::ChangeSet &changeSet)
{ {
if (m_fileName.isEmpty()) if (m_fileName.isEmpty())
return false; return;
if (!m_changes.isEmpty())
return false;
m_changes = changeSet; m_changes = changeSet;
m_openEditor = openEditor;
return true;
} }
bool RefactoringFile::indent(const Range &range, bool openEditor) void RefactoringFile::appendIndentRange(const Range &range)
{ {
if (m_fileName.isEmpty()) if (m_fileName.isEmpty())
return false; return;
m_indentRanges.append(range); m_indentRanges.append(range);
}
if (openEditor)
m_openEditor = true; void RefactoringFile::setOpenEditor(bool activate, int pos)
{
return true; m_openEditor = true;
m_activateEditor = activate;
m_editorCursorPosition = pos;
}
void RefactoringFile::apply()
{
// open / activate / goto position
if (m_openEditor && !m_fileName.isEmpty()) {
unsigned line = -1, column = -1;
if (m_editorCursorPosition != -1)
lineAndColumn(m_editorCursorPosition, &line, &column);
m_editor = RefactoringChanges::openEditor(m_fileName, m_activateEditor, line, column);
m_openEditor = false;
m_activateEditor = false;
m_editorCursorPosition = -1;
}
// apply changes, if any
if (m_data && !(m_indentRanges.isEmpty() && m_changes.isEmpty())) {
QTextDocument *doc = mutableDocument();
if (doc) {
QTextCursor c(doc);
c.beginEditBlock();
// build indent selections now, applying the changeset will change locations
const QList<QTextCursor> &indentSelections =
RefactoringChanges::rangesToSelections(
doc, m_indentRanges);
m_indentRanges.clear();
// apply changes and reindent
m_changes.apply(&c);
m_changes.clear();
foreach (const QTextCursor &selection, indentSelections) {
m_data->indentSelection(selection, m_fileName, m_editor);
}
c.endEditBlock();
}
// if this document doesn't have an editor, write the result to a file
if (!m_editor && !m_fileName.isEmpty()) {
Utils::FileSaver saver(m_fileName);
saver.write(doc->toPlainText().toUtf8());
saver.finalize(Core::ICore::instance()->mainWindow());
}
fileChanged();
}
}
void RefactoringFile::fileChanged()
{
if (!m_fileName.isEmpty())
m_data->fileChanged(m_fileName);
}
void RefactoringChangesData::indentSelection(const QTextCursor &, const QString &, const BaseTextEditorWidget *) const
{
qWarning() << Q_FUNC_INFO << "not implemented";
}
void RefactoringChangesData::fileChanged(const QString &)
{
} }

View File

@@ -38,57 +38,69 @@
#include <QtCore/QList> #include <QtCore/QList>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QSharedPointer>
QT_FORWARD_DECLARE_CLASS(QTextDocument) QT_BEGIN_NAMESPACE
class QTextDocument;
QT_END_NAMESPACE
namespace TextEditor { namespace TextEditor {
class BaseTextEditorWidget; class BaseTextEditorWidget;
class RefactoringChanges; class RefactoringChanges;
class RefactoringFile;
class RefactoringChangesData;
typedef QSharedPointer<RefactoringFile> RefactoringFilePtr;
// ### listen to the m_editor::destroyed signal?
class TEXTEDITOR_EXPORT RefactoringFile class TEXTEDITOR_EXPORT RefactoringFile
{ {
Q_DISABLE_COPY(RefactoringFile)
public: public:
typedef Utils::ChangeSet::Range Range; typedef Utils::ChangeSet::Range Range;
public: public:
RefactoringFile();
// takes ownership of document
RefactoringFile(QTextDocument *document, const QString &fileName = QString());
RefactoringFile(BaseTextEditorWidget *editor);
RefactoringFile(const RefactoringFile &other);
virtual ~RefactoringFile(); virtual ~RefactoringFile();
bool isValid() const; bool isValid() const;
const QTextDocument *document() const; const QTextDocument *document() const;
// mustn't use the cursor to change the document
const QTextCursor cursor() const; const QTextCursor cursor() const;
QString fileName() const; QString fileName() const;
// converts 1-based line and column into 0-based offset // converts 1-based line and column into 0-based source offset
int position(unsigned line, unsigned column) const; int position(unsigned line, unsigned column) const;
// converts 0-based source offset into 1-based line and column
void lineAndColumn(int offset, unsigned *line, unsigned *column) const;
QChar charAt(int pos) const; QChar charAt(int pos) const;
QString textOf(int start, int end) const; QString textOf(int start, int end) const;
QString textOf(const Range &range) const; QString textOf(const Range &range) const;
bool change(const Utils::ChangeSet &changeSet, bool openEditor = true); void setChangeSet(const Utils::ChangeSet &changeSet);
bool indent(const Range &range, bool openEditor = true); void appendIndentRange(const Range &range);
void setOpenEditor(bool activate = false, int pos = -1);
void apply();
protected: protected:
// not assignable RefactoringFile(QTextDocument *document, const QString &fileName);
//const RefactoringFile &operator=(const RefactoringFile &other); RefactoringFile(BaseTextEditorWidget *editor);
RefactoringFile(const QString &fileName, const QSharedPointer<RefactoringChangesData> &data);
RefactoringFile(const QString &fileName, RefactoringChanges *refactoringChanges);
QTextDocument *mutableDocument() const; QTextDocument *mutableDocument() const;
// derived classes may want to clear language specific extra data
virtual void fileChanged();
protected: protected:
QString m_fileName; QString m_fileName;
RefactoringChanges *m_refactoringChanges; QSharedPointer<RefactoringChangesData> m_data;
mutable QTextDocument *m_document; mutable QTextDocument *m_document;
BaseTextEditorWidget *m_editor; BaseTextEditorWidget *m_editor;
Utils::ChangeSet m_changes; Utils::ChangeSet m_changes;
QList<Range> m_indentRanges; QList<Range> m_indentRanges;
bool m_openEditor; bool m_openEditor;
bool m_activateEditor;
int m_editorCursorPosition;
friend class RefactoringChanges; // access to constructor friend class RefactoringChanges; // access to constructor
}; };
@@ -106,36 +118,37 @@ public:
RefactoringChanges(); RefactoringChanges();
virtual ~RefactoringChanges(); virtual ~RefactoringChanges();
bool createFile(const QString &fileName, const QString &contents, bool reindent = true, bool openEditor = true); static RefactoringFilePtr file(BaseTextEditorWidget *editor);
bool removeFile(const QString &fileName); RefactoringFilePtr file(const QString &fileName) const;
bool createFile(const QString &fileName, const QString &contents, bool reindent = true, bool openEditor = true) const;
bool removeFile(const QString &fileName) const;
RefactoringFile file(const QString &fileName); static BaseTextEditorWidget *editorForFile(const QString &fileName);
BaseTextEditorWidget *openEditor(const QString &fileName, int pos = -1); protected:
explicit RefactoringChanges(RefactoringChangesData *data);
/*! static BaseTextEditorWidget *openEditor(const QString &fileName, bool activate, int line, int column);
\param fileName the file to activate the editor for
\param line the line to put the cursor on (1-based)
\param column the column to put the cursor on (1-based)
*/
void activateEditor(const QString &fileName, int line, int column);
static BaseTextEditorWidget *editorForFile(const QString &fileName,
bool openIfClosed = false);
private:
static QList<QTextCursor> rangesToSelections(QTextDocument *document, const QList<Range> &ranges); static QList<QTextCursor> rangesToSelections(QTextDocument *document, const QList<Range> &ranges);
virtual void indentSelection(const QTextCursor &selection,
const QString &fileName, protected:
const BaseTextEditorWidget *textEditor) const = 0; QSharedPointer<RefactoringChangesData> m_data;
virtual void fileChanged(const QString &fileName) = 0;
friend class RefactoringFile; friend class RefactoringFile;
};
private: class TEXTEDITOR_EXPORT RefactoringChangesData
QString m_fileToOpen; {
int m_lineToOpen; Q_DISABLE_COPY(RefactoringChangesData)
int m_columnToOpen;
public:
RefactoringChangesData() {}
virtual void indentSelection(const QTextCursor &selection,
const QString &fileName,
const BaseTextEditorWidget *textEditor) const;
virtual void fileChanged(const QString &fileName);
}; };
} // namespace TextEditor } // namespace TextEditor