forked from qt-creator/qt-creator
CppEditor: InsertDefFromDecl: choose insert position
Now one can decide where the new definition should go: Inside the class, outside the class or to the implementation file. Further the text cursor is positioned inside the new created definition body. Task-number: QTCREATORBUG-6973 Change-Id: I593955dd1e44e35240fa1e9b9a5c1a67eb119456 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@digia.com> Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
This commit is contained in:
committed by
Nikolai Kosjar
parent
5dbcb974b0
commit
15f90404aa
@@ -115,6 +115,12 @@ void CppEditor::Internal::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
|
||||
// different quick fixes.
|
||||
namespace {
|
||||
|
||||
enum DefPos {
|
||||
DefPosInsideClass,
|
||||
DefPosOutsideClass,
|
||||
DefPosImplementationFile
|
||||
};
|
||||
|
||||
inline bool isQtStringLiteral(const QByteArray &id)
|
||||
{
|
||||
return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral";
|
||||
@@ -2446,16 +2452,29 @@ class InsertDefOperation: public CppQuickFixOperation
|
||||
{
|
||||
public:
|
||||
InsertDefOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
|
||||
Declaration *decl, const InsertionLocation &loc)
|
||||
Declaration *decl, const InsertionLocation &loc, const DefPos defpos,
|
||||
bool freeFunction = false)
|
||||
: CppQuickFixOperation(interface, 0)
|
||||
, m_decl(decl)
|
||||
, m_loc(loc)
|
||||
, m_defpos(defpos)
|
||||
{
|
||||
const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength());
|
||||
const QDir dir = QFileInfo(declFile).dir();
|
||||
setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
|
||||
"Add Definition in %1")
|
||||
.arg(dir.relativeFilePath(m_loc.fileName())));
|
||||
if (m_defpos == DefPosImplementationFile) {
|
||||
const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength());
|
||||
const QDir dir = QFileInfo(declFile).dir();
|
||||
setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
|
||||
"Add Definition in %1")
|
||||
.arg(dir.relativeFilePath(m_loc.fileName())));
|
||||
} else if (freeFunction) {
|
||||
setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
|
||||
"Add Definition Here"));
|
||||
} else if (m_defpos == DefPosInsideClass) {
|
||||
setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
|
||||
"Add Definition Inside Class"));
|
||||
} else if (m_defpos == DefPosOutsideClass) {
|
||||
setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
|
||||
"Add Definition Outside Class"));
|
||||
}
|
||||
}
|
||||
|
||||
void perform()
|
||||
@@ -2469,44 +2488,76 @@ public:
|
||||
oo.showReturnTypes = true;
|
||||
oo.showArgumentNames = true;
|
||||
|
||||
// make target lookup context
|
||||
Document::Ptr targetDoc = targetFile->cppDocument();
|
||||
Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column());
|
||||
LookupContext targetContext(targetDoc, assistInterface()->snapshot());
|
||||
ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
|
||||
if (!targetCoN)
|
||||
targetCoN = targetContext.globalNamespace();
|
||||
if (m_defpos == DefPosInsideClass) {
|
||||
const int targetPos = targetFile->position(m_loc.line(), m_loc.column());
|
||||
ChangeSet target;
|
||||
target.replace(targetPos - 1, targetPos, QLatin1String(" {\n\n}")); // replace ';'
|
||||
targetFile->setChangeSet(target);
|
||||
targetFile->appendIndentRange(ChangeSet::Range(targetPos, targetPos + 4));
|
||||
targetFile->setOpenEditor(true, targetPos);
|
||||
targetFile->apply();
|
||||
|
||||
// setup rewriting to get minimally qualified names
|
||||
SubstitutionEnvironment env;
|
||||
env.setContext(assistInterface()->context());
|
||||
env.switchScope(m_decl->enclosingScope());
|
||||
UseMinimalNames q(targetCoN);
|
||||
env.enter(&q);
|
||||
Control *control = assistInterface()->context().control().data();
|
||||
// Move cursor inside definition
|
||||
QTextCursor c = targetFile->cursor();
|
||||
c.setPosition(targetPos);
|
||||
c.movePosition(QTextCursor::Down);
|
||||
c.movePosition(QTextCursor::EndOfLine);
|
||||
assistInterface()->editor()->setTextCursor(c);
|
||||
} else {
|
||||
// make target lookup context
|
||||
Document::Ptr targetDoc = targetFile->cppDocument();
|
||||
Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column());
|
||||
LookupContext targetContext(targetDoc, assistInterface()->snapshot());
|
||||
ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
|
||||
if (!targetCoN)
|
||||
targetCoN = targetContext.globalNamespace();
|
||||
|
||||
// rewrite the function type
|
||||
FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
|
||||
// setup rewriting to get minimally qualified names
|
||||
SubstitutionEnvironment env;
|
||||
env.setContext(assistInterface()->context());
|
||||
env.switchScope(m_decl->enclosingScope());
|
||||
UseMinimalNames q(targetCoN);
|
||||
env.enter(&q);
|
||||
Control *control = assistInterface()->context().control().data();
|
||||
|
||||
// rewrite the function name
|
||||
QString name = oo.prettyName(LookupContext::minimalName(m_decl, targetCoN, control));
|
||||
// rewrite the function type
|
||||
const FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
|
||||
|
||||
QString defText = oo.prettyType(tn, name) + QLatin1String("\n{\n}");
|
||||
// rewrite the function name
|
||||
const QString name = oo.prettyName(LookupContext::minimalName(m_decl, targetCoN,
|
||||
control));
|
||||
|
||||
int targetPos = targetFile->position(m_loc.line(), m_loc.column());
|
||||
int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1);
|
||||
const QString defText = oo.prettyType(tn, name) + QLatin1String("\n{\n\n}");
|
||||
|
||||
ChangeSet target;
|
||||
target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix());
|
||||
targetFile->setChangeSet(target);
|
||||
targetFile->appendIndentRange(ChangeSet::Range(targetPos2, targetPos));
|
||||
targetFile->setOpenEditor(true, targetPos);
|
||||
targetFile->apply();
|
||||
const int targetPos = targetFile->position(m_loc.line(), m_loc.column());
|
||||
const int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1);
|
||||
|
||||
ChangeSet target;
|
||||
target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix());
|
||||
targetFile->setChangeSet(target);
|
||||
targetFile->appendIndentRange(ChangeSet::Range(targetPos2, targetPos));
|
||||
targetFile->setOpenEditor(true, targetPos);
|
||||
targetFile->apply();
|
||||
|
||||
// Move cursor inside definition
|
||||
QTextCursor c = targetFile->cursor();
|
||||
c.setPosition(targetPos);
|
||||
c.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor,
|
||||
m_loc.prefix().count(QLatin1String("\n")) + 2);
|
||||
c.movePosition(QTextCursor::EndOfLine);
|
||||
if (m_defpos == DefPosImplementationFile) {
|
||||
if (BaseTextEditorWidget *editor = refactoring.editorForFile(m_loc.fileName()))
|
||||
editor->setTextCursor(c);
|
||||
} else {
|
||||
assistInterface()->editor()->setTextCursor(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Declaration *m_decl;
|
||||
InsertionLocation m_loc;
|
||||
const InsertionLocation m_loc;
|
||||
const DefPos m_defpos;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
@@ -2525,12 +2576,62 @@ void InsertDefFromDecl::match(const CppQuickFixInterface &interface, QuickFixOpe
|
||||
if (Function *func = decl->type()->asFunctionType()) {
|
||||
if (func->isSignal())
|
||||
return;
|
||||
CppRefactoringChanges refactoring(interface->snapshot());
|
||||
InsertionPointLocator locator(refactoring);
|
||||
foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
|
||||
if (loc.isValid())
|
||||
result.append(CppQuickFixOperation::Ptr(new InsertDefOperation(interface, decl, loc)));
|
||||
|
||||
InsertDefOperation *op = 0;
|
||||
bool isHeaderFile = false;
|
||||
const QString cppFileName = correspondingHeaderOrSource(
|
||||
interface->fileName(), &isHeaderFile);
|
||||
|
||||
// Insert Position: Implementation File
|
||||
if (isHeaderFile && !cppFileName.isEmpty()) {
|
||||
CppRefactoringChanges refactoring(interface->snapshot());
|
||||
InsertionPointLocator locator(refactoring);
|
||||
foreach (const InsertionLocation &loc,
|
||||
locator.methodDefinition(decl)) {
|
||||
if (loc.isValid()) {
|
||||
op = new InsertDefOperation(interface, decl, loc,
|
||||
DefPosImplementationFile);
|
||||
result.append(CppQuickFixOperation::Ptr(op));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dealing with a free function
|
||||
const CppRefactoringFilePtr file = interface->currentFile();
|
||||
unsigned line, column;
|
||||
if (func->enclosingClass() == 0) {
|
||||
file->lineAndColumn(file->endOf(simpleDecl), &line, &column);
|
||||
InsertionLocation loc(interface->fileName(), QLatin1String(""),
|
||||
QLatin1String(""), line, column);
|
||||
op = new InsertDefOperation(interface, decl, loc,
|
||||
DefPosInsideClass, true);
|
||||
result.append(CppQuickFixOperation::Ptr(op));
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert Position: Outside Class
|
||||
--idx;
|
||||
for (; idx >= 0; --idx) {
|
||||
AST *node = path.at(idx);
|
||||
if (ClassSpecifierAST *ast = node->asClassSpecifier()) {
|
||||
file->lineAndColumn(file->endOf(ast), &line, &column);
|
||||
InsertionLocation loc(interface->fileName(),
|
||||
QLatin1String("\n\n"), QLatin1String(""),
|
||||
line, column + 1); // include ';'
|
||||
op = new InsertDefOperation(interface, decl, loc,
|
||||
DefPosOutsideClass);
|
||||
result.append(CppQuickFixOperation::Ptr(op));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert Position: Inside Class
|
||||
file->lineAndColumn(file->endOf(simpleDecl), &line, &column);
|
||||
InsertionLocation loc(interface->fileName(), QLatin1String(""),
|
||||
QLatin1String(""), line, column);
|
||||
op = new InsertDefOperation(interface, decl, loc, DefPosInsideClass);
|
||||
result.append(CppQuickFixOperation::Ptr(op));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user