forked from qt-creator/qt-creator
Introduced the quick fix engine
This commit is contained in:
@@ -31,7 +31,6 @@
|
|||||||
#include "cppeditorconstants.h"
|
#include "cppeditorconstants.h"
|
||||||
#include "cppplugin.h"
|
#include "cppplugin.h"
|
||||||
#include "cpphighlighter.h"
|
#include "cpphighlighter.h"
|
||||||
|
|
||||||
#include <cpptools/cpptoolsplugin.h>
|
#include <cpptools/cpptoolsplugin.h>
|
||||||
|
|
||||||
#include <AST.h>
|
#include <AST.h>
|
||||||
|
|||||||
@@ -14,13 +14,15 @@ HEADERS += cppplugin.h \
|
|||||||
cppeditorconstants.h \
|
cppeditorconstants.h \
|
||||||
cppeditorenums.h \
|
cppeditorenums.h \
|
||||||
cppeditor_global.h \
|
cppeditor_global.h \
|
||||||
cppclasswizard.h
|
cppclasswizard.h \
|
||||||
|
cppquickfix.h
|
||||||
SOURCES += cppplugin.cpp \
|
SOURCES += cppplugin.cpp \
|
||||||
cppeditor.cpp \
|
cppeditor.cpp \
|
||||||
cpphighlighter.cpp \
|
cpphighlighter.cpp \
|
||||||
cpphoverhandler.cpp \
|
cpphoverhandler.cpp \
|
||||||
cppfilewizard.cpp \
|
cppfilewizard.cpp \
|
||||||
cppclasswizard.cpp
|
cppclasswizard.cpp \
|
||||||
|
cppquickfix.cpp
|
||||||
RESOURCES += cppeditor.qrc
|
RESOURCES += cppeditor.qrc
|
||||||
|
|
||||||
OTHER_FILES += CppEditor.pluginspec CppEditor.mimetypes.xml
|
OTHER_FILES += CppEditor.pluginspec CppEditor.mimetypes.xml
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "cppeditorenums.h"
|
#include "cppeditorenums.h"
|
||||||
#include "cppfilewizard.h"
|
#include "cppfilewizard.h"
|
||||||
#include "cpphoverhandler.h"
|
#include "cpphoverhandler.h"
|
||||||
|
#include "cppquickfix.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
@@ -183,6 +184,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
|
|||||||
|
|
||||||
addAutoReleasedObject(new CppEditorFactory(this));
|
addAutoReleasedObject(new CppEditorFactory(this));
|
||||||
addAutoReleasedObject(new CppHoverHandler);
|
addAutoReleasedObject(new CppHoverHandler);
|
||||||
|
addAutoReleasedObject(new CPPQuickFixCollector);
|
||||||
|
|
||||||
CppFileWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
|
CppFileWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
|
||||||
|
|
||||||
|
|||||||
141
src/plugins/cppeditor/cppquickfix.cpp
Normal file
141
src/plugins/cppeditor/cppquickfix.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
|
**
|
||||||
|
** Commercial Usage
|
||||||
|
**
|
||||||
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||||
|
** accordance with the Qt Commercial License Agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Nokia.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
**
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** If you are unsure which license is appropriate for your use, please
|
||||||
|
** contact the sales department at http://qt.nokia.com/contact.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#include "cppquickfix.h"
|
||||||
|
#include "cppeditor.h"
|
||||||
|
#include <TranslationUnit.h>
|
||||||
|
#include <Token.h>
|
||||||
|
|
||||||
|
#include <cpptools/cppmodelmanagerinterface.h>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
using namespace CppEditor::Internal;
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
|
QuickFixOperation::QuickFixOperation(CPlusPlus::Document::Ptr doc, const CPlusPlus::Snapshot &snapshot)
|
||||||
|
: _doc(doc), _snapshot(snapshot)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
QuickFixOperation::~QuickFixOperation()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
QTextCursor QuickFixOperation::textCursor() const
|
||||||
|
{ return _textCursor; }
|
||||||
|
|
||||||
|
void QuickFixOperation::setTextCursor(const QTextCursor &tc)
|
||||||
|
{ _textCursor = tc; }
|
||||||
|
|
||||||
|
const CPlusPlus::Token &QuickFixOperation::tokenAt(unsigned index) const
|
||||||
|
{ return _doc->translationUnit()->tokenAt(index); }
|
||||||
|
|
||||||
|
void QuickFixOperation::getTokenStartPosition(unsigned index, unsigned *line, unsigned *column) const
|
||||||
|
{ _doc->translationUnit()->getPosition(tokenAt(index).begin(), line, column); }
|
||||||
|
|
||||||
|
void QuickFixOperation::getTokenEndPosition(unsigned index, unsigned *line, unsigned *column) const
|
||||||
|
{ _doc->translationUnit()->getPosition(tokenAt(index).end(), line, column); }
|
||||||
|
|
||||||
|
QTextCursor QuickFixOperation::cursor(unsigned index) const
|
||||||
|
{
|
||||||
|
const Token &tk = tokenAt(index);
|
||||||
|
|
||||||
|
unsigned line, col;
|
||||||
|
getTokenStartPosition(index, &line, &col);
|
||||||
|
QTextCursor tc = _textCursor;
|
||||||
|
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col - 1);
|
||||||
|
tc.setPosition(tc.position() + tk.f.length, QTextCursor::KeepAnchor);
|
||||||
|
return tc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextCursor QuickFixOperation::moveAtStartOfToken(unsigned index) const
|
||||||
|
{
|
||||||
|
unsigned line, col;
|
||||||
|
getTokenStartPosition(index, &line, &col);
|
||||||
|
QTextCursor tc = _textCursor;
|
||||||
|
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col - 1);
|
||||||
|
return tc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextCursor QuickFixOperation::moveAtEndOfToken(unsigned index) const
|
||||||
|
{
|
||||||
|
const Token &tk = tokenAt(index);
|
||||||
|
|
||||||
|
unsigned line, col;
|
||||||
|
getTokenStartPosition(index, &line, &col);
|
||||||
|
QTextCursor tc = _textCursor;
|
||||||
|
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col + tk.f.length - 1);
|
||||||
|
return tc;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPPQuickFixCollector::CPPQuickFixCollector()
|
||||||
|
: _modelManager(CppTools::CppModelManagerInterface::instance()), _editor(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
CPPQuickFixCollector::~CPPQuickFixCollector()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool CPPQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editor)
|
||||||
|
{ return qobject_cast<CPPEditorEditable *>(editor) != 0; }
|
||||||
|
|
||||||
|
bool CPPQuickFixCollector::triggersCompletion(TextEditor::ITextEditable *)
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable)
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
Q_ASSERT(editable != 0);
|
||||||
|
_editor = qobject_cast<CPPEditor *>(editable->widget());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPQuickFixCollector::completions(QList<TextEditor::CompletionItem> *quicFixItems)
|
||||||
|
{
|
||||||
|
quicFixItems->append(_quickFixItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPQuickFixCollector::complete(const TextEditor::CompletionItem &item)
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
const int index = item.data.toInt();
|
||||||
|
|
||||||
|
QList<QuickFixOperationPtr> quickFixes; // ### get get the quick fixes.
|
||||||
|
|
||||||
|
if (index < quickFixes.size()) {
|
||||||
|
QuickFixOperationPtr quickFix = quickFixes.at(index);
|
||||||
|
quickFix->apply(_editor->textCursor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPQuickFixCollector::cleanup()
|
||||||
|
{
|
||||||
|
_quickFixItems.clear();
|
||||||
|
}
|
||||||
111
src/plugins/cppeditor/cppquickfix.h
Normal file
111
src/plugins/cppeditor/cppquickfix.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
|
**
|
||||||
|
** Commercial Usage
|
||||||
|
**
|
||||||
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||||
|
** accordance with the Qt Commercial License Agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Nokia.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
**
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** If you are unsure which license is appropriate for your use, please
|
||||||
|
** contact the sales department at http://qt.nokia.com/contact.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CPPQUICKFIX_H
|
||||||
|
#define CPPQUICKFIX_H
|
||||||
|
|
||||||
|
#include <texteditor/icompletioncollector.h>
|
||||||
|
|
||||||
|
#include <cplusplus/CppDocument.h>
|
||||||
|
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
|
#include <QtGui/QTextCursor>
|
||||||
|
|
||||||
|
namespace CppTools {
|
||||||
|
class CppModelManagerInterface;
|
||||||
|
} // end of namespace CppTools
|
||||||
|
|
||||||
|
namespace CppEditor {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class CPPEditor;
|
||||||
|
class QuickFixOperation;
|
||||||
|
typedef QSharedPointer<QuickFixOperation> QuickFixOperationPtr;
|
||||||
|
|
||||||
|
class QuickFixOperation
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY(QuickFixOperation)
|
||||||
|
|
||||||
|
public:
|
||||||
|
QuickFixOperation(CPlusPlus::Document::Ptr doc,
|
||||||
|
const CPlusPlus::Snapshot &snapshot);
|
||||||
|
|
||||||
|
virtual ~QuickFixOperation();
|
||||||
|
|
||||||
|
virtual QString description() const = 0;
|
||||||
|
virtual void apply(QTextCursor cursor) = 0;
|
||||||
|
|
||||||
|
CPlusPlus::Document::Ptr document() const { return _doc; }
|
||||||
|
CPlusPlus::Snapshot snapshot() const { return _snapshot; }
|
||||||
|
|
||||||
|
QTextCursor textCursor() const;
|
||||||
|
void setTextCursor(const QTextCursor &tc);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const CPlusPlus::Token &tokenAt(unsigned index) const;
|
||||||
|
void getTokenStartPosition(unsigned index, unsigned *line,
|
||||||
|
unsigned *column) const;
|
||||||
|
void getTokenEndPosition(unsigned index, unsigned *line,
|
||||||
|
unsigned *column) const;
|
||||||
|
|
||||||
|
QTextCursor cursor(unsigned index) const;
|
||||||
|
QTextCursor moveAtStartOfToken(unsigned index) const;
|
||||||
|
QTextCursor moveAtEndOfToken(unsigned index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CPlusPlus::Document::Ptr _doc;
|
||||||
|
CPlusPlus::Snapshot _snapshot;
|
||||||
|
QTextCursor _textCursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPPQuickFixCollector: public TextEditor::IQuickFixCollector
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CPPQuickFixCollector();
|
||||||
|
virtual ~CPPQuickFixCollector();
|
||||||
|
|
||||||
|
virtual bool supportsEditor(TextEditor::ITextEditable *editor);
|
||||||
|
virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
|
||||||
|
virtual int startCompletion(TextEditor::ITextEditable *editor);
|
||||||
|
virtual void completions(QList<TextEditor::CompletionItem> *completions);
|
||||||
|
virtual void complete(const TextEditor::CompletionItem &item);
|
||||||
|
virtual void cleanup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CppTools::CppModelManagerInterface *_modelManager;
|
||||||
|
CPPEditor *_editor;
|
||||||
|
QList<TextEditor::CompletionItem> _quickFixItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Internal
|
||||||
|
} // end of namespace CppEditor
|
||||||
|
|
||||||
|
#endif // CPPQUICKFIX_H
|
||||||
@@ -463,59 +463,6 @@ void FunctionArgumentWidget::updateHintText()
|
|||||||
m_popupFrame->move(pos);
|
m_popupFrame->move(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
CppQuickFixCollector::CppQuickFixCollector(CppModelManager *modelManager)
|
|
||||||
: _modelManager(modelManager), _editor(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
CppQuickFixCollector::~CppQuickFixCollector()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool CppQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editor)
|
|
||||||
{ return _modelManager->isCppEditor(editor); }
|
|
||||||
|
|
||||||
bool CppQuickFixCollector::triggersCompletion(TextEditor::ITextEditable *)
|
|
||||||
{ return false; }
|
|
||||||
|
|
||||||
int CppQuickFixCollector::startCompletion(TextEditor::ITextEditable *editor)
|
|
||||||
{
|
|
||||||
_editor = editor;
|
|
||||||
|
|
||||||
if (CppEditorSupport *extra = _modelManager->editorSupport(editor)) {
|
|
||||||
const QList<QuickFixOperationPtr> quickFixes = extra->quickFixes();
|
|
||||||
if (! quickFixes.isEmpty()) {
|
|
||||||
int i = 0;
|
|
||||||
foreach (QuickFixOperationPtr op, quickFixes) {
|
|
||||||
TextEditor::CompletionItem item(this);
|
|
||||||
item.text = op->description();
|
|
||||||
item.data = QVariant::fromValue(i);
|
|
||||||
_completions.append(item);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
return editor->position();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CppQuickFixCollector::completions(QList<TextEditor::CompletionItem> *completions)
|
|
||||||
{
|
|
||||||
completions->append(_completions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CppQuickFixCollector::complete(const TextEditor::CompletionItem &item)
|
|
||||||
{
|
|
||||||
CppEditorSupport *extra = _modelManager->editorSupport(_editor);
|
|
||||||
const QList<QuickFixOperationPtr> quickFixes = extra->quickFixes();
|
|
||||||
QuickFixOperationPtr quickFix = quickFixes.at(item.data.toInt());
|
|
||||||
TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(_editor->widget());
|
|
||||||
quickFix->apply(ed->textCursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CppQuickFixCollector::cleanup()
|
|
||||||
{
|
|
||||||
_completions.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
|
CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
|
||||||
: ICompletionCollector(manager),
|
: ICompletionCollector(manager),
|
||||||
m_manager(manager),
|
m_manager(manager),
|
||||||
|
|||||||
@@ -55,27 +55,6 @@ namespace Internal {
|
|||||||
class CppModelManager;
|
class CppModelManager;
|
||||||
class FunctionArgumentWidget;
|
class FunctionArgumentWidget;
|
||||||
|
|
||||||
class CppQuickFixCollector: public TextEditor::IQuickFixCollector
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
CppQuickFixCollector(CppModelManager *modelManager);
|
|
||||||
virtual ~CppQuickFixCollector();
|
|
||||||
|
|
||||||
virtual bool supportsEditor(TextEditor::ITextEditable *editor);
|
|
||||||
virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
|
|
||||||
virtual int startCompletion(TextEditor::ITextEditable *editor);
|
|
||||||
virtual void completions(QList<TextEditor::CompletionItem> *completions);
|
|
||||||
virtual void complete(const TextEditor::CompletionItem &item);
|
|
||||||
virtual void cleanup();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CppModelManager *_modelManager;
|
|
||||||
TextEditor::ITextEditable *_editor;
|
|
||||||
QList<TextEditor::CompletionItem> _completions;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CppCodeCompletion : public TextEditor::ICompletionCollector
|
class CppCodeCompletion : public TextEditor::ICompletionCollector
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|||||||
@@ -44,273 +44,6 @@
|
|||||||
using namespace CppTools::Internal;
|
using namespace CppTools::Internal;
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DEFAULT_QUICKFIX_INTERVAL = 500
|
|
||||||
};
|
|
||||||
|
|
||||||
class QuickFixMark: public TextEditor::ITextMark
|
|
||||||
{
|
|
||||||
QIcon _icon;
|
|
||||||
|
|
||||||
public:
|
|
||||||
QuickFixMark(QObject *parent)
|
|
||||||
: TextEditor::ITextMark(parent),
|
|
||||||
_icon(QLatin1String(":/core/images/redo.png")) // ### FIXME
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual ~QuickFixMark()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual QIcon icon() const
|
|
||||||
{ return _icon; }
|
|
||||||
|
|
||||||
virtual void updateLineNumber(int)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual void updateBlock(const QTextBlock &)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual void removedFromEditor()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual void documentClosing()
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
class ReplaceCast: public QuickFixOperation
|
|
||||||
{
|
|
||||||
CastExpressionAST *_castExpression;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ReplaceCast(CastExpressionAST *node, Document::Ptr doc, const Snapshot &snapshot)
|
|
||||||
: QuickFixOperation(doc, snapshot),
|
|
||||||
_castExpression(node)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual QString description() const
|
|
||||||
{ return QLatin1String("Rewrite old C-style cast"); }
|
|
||||||
|
|
||||||
virtual void apply(QTextCursor tc)
|
|
||||||
{
|
|
||||||
setTextCursor(tc);
|
|
||||||
|
|
||||||
tc.beginEditBlock();
|
|
||||||
|
|
||||||
QTextCursor beginOfCast = cursor(_castExpression->lparen_token);
|
|
||||||
QTextCursor endOfCast = cursor(_castExpression->rparen_token);
|
|
||||||
QTextCursor beginOfExpr = moveAtStartOfToken(_castExpression->expression->firstToken());
|
|
||||||
QTextCursor endOfExpr = moveAtEndOfToken(_castExpression->expression->lastToken() - 1);
|
|
||||||
|
|
||||||
beginOfCast.insertText(QLatin1String("reinterpret_cast<"));
|
|
||||||
endOfCast.insertText(QLatin1String(">"));
|
|
||||||
|
|
||||||
beginOfExpr.insertText(QLatin1String("("));
|
|
||||||
endOfExpr.insertText(QLatin1String(")"));
|
|
||||||
|
|
||||||
tc.endEditBlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RewriteConditional: public QuickFixOperation
|
|
||||||
{
|
|
||||||
QString _source;
|
|
||||||
BinaryExpressionAST *_binaryExpression;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RewriteConditional(const QString &source, BinaryExpressionAST *node,
|
|
||||||
Document::Ptr doc, const Snapshot &snapshot)
|
|
||||||
: QuickFixOperation(doc, snapshot),
|
|
||||||
_source(source),
|
|
||||||
_binaryExpression(node)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual QString description() const
|
|
||||||
{ return QString::fromUtf8("Rewrite conditional (%1)").arg(_source.simplified()); }
|
|
||||||
|
|
||||||
virtual void apply(QTextCursor tc)
|
|
||||||
{
|
|
||||||
setTextCursor(tc);
|
|
||||||
|
|
||||||
tc.beginEditBlock();
|
|
||||||
|
|
||||||
UnaryExpressionAST *left_unary_expr = _binaryExpression->left_expression->asUnaryExpression();
|
|
||||||
UnaryExpressionAST *right_unary_expr = _binaryExpression->right_expression->asUnaryExpression();
|
|
||||||
|
|
||||||
QTextCursor left_not_op = cursor(left_unary_expr->unary_op_token);
|
|
||||||
QTextCursor right_not_op = cursor(right_unary_expr->unary_op_token);
|
|
||||||
QTextCursor log_and_op = cursor(_binaryExpression->binary_op_token);
|
|
||||||
|
|
||||||
QTextCursor begin_of_expr = moveAtStartOfToken(_binaryExpression->firstToken());
|
|
||||||
QTextCursor end_of_expr = moveAtEndOfToken(_binaryExpression->lastToken() - 1);
|
|
||||||
|
|
||||||
left_not_op.removeSelectedText();
|
|
||||||
right_not_op.removeSelectedText();
|
|
||||||
log_and_op.insertText(QLatin1String("||"));
|
|
||||||
begin_of_expr.insertText(QLatin1String("!("));
|
|
||||||
end_of_expr.insertText(QLatin1String(")"));
|
|
||||||
|
|
||||||
tc.endEditBlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
class CheckDocument: protected ASTVisitor
|
|
||||||
{
|
|
||||||
QTextCursor _textCursor;
|
|
||||||
Document::Ptr _doc;
|
|
||||||
Snapshot _snapshot;
|
|
||||||
unsigned _line;
|
|
||||||
unsigned _column;
|
|
||||||
QList<QuickFixOperationPtr> _quickFixes;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CheckDocument(Document::Ptr doc, Snapshot snapshot)
|
|
||||||
: ASTVisitor(doc->control()), _doc(doc), _snapshot(snapshot),
|
|
||||||
_line(0), _column(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
QList<QuickFixOperationPtr> operator()(QTextCursor tc)
|
|
||||||
{
|
|
||||||
_quickFixes.clear();
|
|
||||||
_textCursor = tc;
|
|
||||||
_line = tc.blockNumber() + 1;
|
|
||||||
_column = tc.columnNumber() + 1;
|
|
||||||
accept(_doc->translationUnit()->ast());
|
|
||||||
return _quickFixes;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
using ASTVisitor::visit;
|
|
||||||
|
|
||||||
bool checkPosition(AST *ast) const
|
|
||||||
{
|
|
||||||
unsigned startLine, startColumn;
|
|
||||||
unsigned endLine, endColumn;
|
|
||||||
|
|
||||||
getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
|
|
||||||
getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
|
|
||||||
|
|
||||||
if (_line < startLine || (_line == startLine && _column < startColumn))
|
|
||||||
return false;
|
|
||||||
else if (_line > endLine || (_line == endLine && _column >= endColumn))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextCursor moveAtStartOfToken(unsigned index) const
|
|
||||||
{
|
|
||||||
unsigned line, col;
|
|
||||||
getTokenStartPosition(index, &line, &col);
|
|
||||||
QTextCursor tc = _textCursor;
|
|
||||||
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col - 1);
|
|
||||||
return tc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextCursor moveAtEndOfToken(unsigned index) const
|
|
||||||
{
|
|
||||||
const Token &tk = tokenAt(index);
|
|
||||||
|
|
||||||
unsigned line, col;
|
|
||||||
getTokenStartPosition(index, &line, &col);
|
|
||||||
QTextCursor tc = _textCursor;
|
|
||||||
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col + tk.f.length - 1);
|
|
||||||
return tc;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool visit(BinaryExpressionAST *ast)
|
|
||||||
{
|
|
||||||
if (ast->left_expression && ast->right_expression && tokenKind(ast->binary_op_token) == T_AMPER_AMPER &&
|
|
||||||
checkPosition(ast)) {
|
|
||||||
UnaryExpressionAST *left_unary_expr = ast->left_expression->asUnaryExpression();
|
|
||||||
UnaryExpressionAST *right_unary_expr = ast->right_expression->asUnaryExpression();
|
|
||||||
if (left_unary_expr && left_unary_expr->expression && tokenKind(left_unary_expr->unary_op_token) == T_NOT &&
|
|
||||||
right_unary_expr && right_unary_expr->expression && tokenKind(right_unary_expr->unary_op_token) == T_NOT) {
|
|
||||||
// replace !a && !b with !(a || b)
|
|
||||||
QTextCursor beg = moveAtStartOfToken(ast->firstToken());
|
|
||||||
QTextCursor end = moveAtEndOfToken(ast->lastToken() - 1);
|
|
||||||
beg.setPosition(end.position(), QTextCursor::KeepAnchor);
|
|
||||||
QString source = beg.selectedText();
|
|
||||||
|
|
||||||
QuickFixOperationPtr op(new RewriteConditional(source, ast, _doc, _snapshot));
|
|
||||||
_quickFixes.append(op);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool visit(CastExpressionAST *ast)
|
|
||||||
{
|
|
||||||
if (! checkPosition(ast))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (ast->type_id && ast->lparen_token && ast->rparen_token && ast->expression) {
|
|
||||||
QuickFixOperationPtr op(new ReplaceCast(ast, _doc, _snapshot));
|
|
||||||
_quickFixes.append(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
QuickFixOperation::QuickFixOperation(CPlusPlus::Document::Ptr doc, const CPlusPlus::Snapshot &snapshot)
|
|
||||||
: _doc(doc), _snapshot(snapshot)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
QuickFixOperation::~QuickFixOperation()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
QTextCursor QuickFixOperation::textCursor() const
|
|
||||||
{ return _textCursor; }
|
|
||||||
|
|
||||||
void QuickFixOperation::setTextCursor(const QTextCursor &tc)
|
|
||||||
{ _textCursor = tc; }
|
|
||||||
|
|
||||||
const CPlusPlus::Token &QuickFixOperation::tokenAt(unsigned index) const
|
|
||||||
{ return _doc->translationUnit()->tokenAt(index); }
|
|
||||||
|
|
||||||
void QuickFixOperation::getTokenStartPosition(unsigned index, unsigned *line, unsigned *column) const
|
|
||||||
{ _doc->translationUnit()->getPosition(tokenAt(index).begin(), line, column); }
|
|
||||||
|
|
||||||
void QuickFixOperation::getTokenEndPosition(unsigned index, unsigned *line, unsigned *column) const
|
|
||||||
{ _doc->translationUnit()->getPosition(tokenAt(index).end(), line, column); }
|
|
||||||
|
|
||||||
QTextCursor QuickFixOperation::cursor(unsigned index) const
|
|
||||||
{
|
|
||||||
const Token &tk = tokenAt(index);
|
|
||||||
|
|
||||||
unsigned line, col;
|
|
||||||
getTokenStartPosition(index, &line, &col);
|
|
||||||
QTextCursor tc = _textCursor;
|
|
||||||
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col - 1);
|
|
||||||
tc.setPosition(tc.position() + tk.f.length, QTextCursor::KeepAnchor);
|
|
||||||
return tc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextCursor QuickFixOperation::moveAtStartOfToken(unsigned index) const
|
|
||||||
{
|
|
||||||
unsigned line, col;
|
|
||||||
getTokenStartPosition(index, &line, &col);
|
|
||||||
QTextCursor tc = _textCursor;
|
|
||||||
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col - 1);
|
|
||||||
return tc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextCursor QuickFixOperation::moveAtEndOfToken(unsigned index) const
|
|
||||||
{
|
|
||||||
const Token &tk = tokenAt(index);
|
|
||||||
|
|
||||||
unsigned line, col;
|
|
||||||
getTokenStartPosition(index, &line, &col);
|
|
||||||
QTextCursor tc = _textCursor;
|
|
||||||
tc.setPosition(tc.document()->findBlockByNumber(line - 1).position() + col + tk.f.length - 1);
|
|
||||||
return tc;
|
|
||||||
}
|
|
||||||
|
|
||||||
CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
|
CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
|
||||||
: QObject(modelManager),
|
: QObject(modelManager),
|
||||||
_modelManager(modelManager),
|
_modelManager(modelManager),
|
||||||
@@ -320,14 +53,6 @@ CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
|
|||||||
_updateDocumentTimer->setSingleShot(true);
|
_updateDocumentTimer->setSingleShot(true);
|
||||||
_updateDocumentTimer->setInterval(_updateDocumentInterval);
|
_updateDocumentTimer->setInterval(_updateDocumentInterval);
|
||||||
connect(_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
|
connect(_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
|
||||||
_quickFixMark = new QuickFixMark(this);
|
|
||||||
|
|
||||||
_quickFixTimer = new QTimer(this);
|
|
||||||
_quickFixTimer->setSingleShot(true);
|
|
||||||
_quickFixTimer->setInterval(DEFAULT_QUICKFIX_INTERVAL);
|
|
||||||
#ifdef QTCREATOR_WITH_QUICKFIX
|
|
||||||
connect(_quickFixTimer, SIGNAL(timeout()), this, SLOT(checkDocumentNow()));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CppEditorSupport::~CppEditorSupport()
|
CppEditorSupport::~CppEditorSupport()
|
||||||
@@ -344,12 +69,6 @@ void CppEditorSupport::setTextEditor(TextEditor::ITextEditor *textEditor)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
connect(_textEditor, SIGNAL(contentsChanged()), this, SIGNAL(contentsChanged()));
|
connect(_textEditor, SIGNAL(contentsChanged()), this, SIGNAL(contentsChanged()));
|
||||||
|
|
||||||
#ifdef QTCREATOR_WITH_QUICKFIX
|
|
||||||
connect(qobject_cast<TextEditor::BaseTextEditor *>(_textEditor->widget()), SIGNAL(cursorPositionChanged()),
|
|
||||||
this, SLOT(checkDocument()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
connect(this, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
|
connect(this, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
|
||||||
|
|
||||||
updateDocument();
|
updateDocument();
|
||||||
@@ -396,37 +115,3 @@ void CppEditorSupport::updateDocumentNow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppEditorSupport::checkDocument()
|
|
||||||
{
|
|
||||||
_quickFixTimer->start(DEFAULT_QUICKFIX_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CppEditorSupport::checkDocumentNow()
|
|
||||||
{
|
|
||||||
_textEditor->markableInterface()->removeMark(_quickFixMark);
|
|
||||||
_quickFixes.clear();
|
|
||||||
|
|
||||||
TextEditor::BaseTextEditor *ed =
|
|
||||||
qobject_cast<TextEditor::BaseTextEditor *>(_textEditor->widget());
|
|
||||||
|
|
||||||
Snapshot snapshot = _modelManager->snapshot();
|
|
||||||
const QString plainText = contents();
|
|
||||||
const QString fileName = _textEditor->file()->fileName();
|
|
||||||
const QByteArray preprocessedCode = snapshot.preprocessedCode(plainText, fileName);
|
|
||||||
|
|
||||||
if (Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, fileName)) {
|
|
||||||
doc->parse();
|
|
||||||
|
|
||||||
CheckDocument checkDocument(doc, snapshot);
|
|
||||||
QList<QuickFixOperationPtr> quickFixes = checkDocument(ed->textCursor());
|
|
||||||
if (! quickFixes.isEmpty()) {
|
|
||||||
int line, col;
|
|
||||||
ed->convertPosition(ed->position(), &line, &col);
|
|
||||||
|
|
||||||
_textEditor->markableInterface()->addMark(_quickFixMark, line);
|
|
||||||
_quickFixes = quickFixes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,45 +55,6 @@ namespace Internal {
|
|||||||
|
|
||||||
class CppModelManager;
|
class CppModelManager;
|
||||||
|
|
||||||
class QuickFixOperation;
|
|
||||||
typedef QSharedPointer<QuickFixOperation> QuickFixOperationPtr;
|
|
||||||
|
|
||||||
class QuickFixOperation
|
|
||||||
{
|
|
||||||
Q_DISABLE_COPY(QuickFixOperation)
|
|
||||||
|
|
||||||
public:
|
|
||||||
QuickFixOperation(CPlusPlus::Document::Ptr doc,
|
|
||||||
const CPlusPlus::Snapshot &snapshot);
|
|
||||||
|
|
||||||
virtual ~QuickFixOperation();
|
|
||||||
|
|
||||||
virtual QString description() const = 0;
|
|
||||||
virtual void apply(QTextCursor cursor) = 0;
|
|
||||||
|
|
||||||
CPlusPlus::Document::Ptr document() const { return _doc; }
|
|
||||||
CPlusPlus::Snapshot snapshot() const { return _snapshot; }
|
|
||||||
|
|
||||||
QTextCursor textCursor() const;
|
|
||||||
void setTextCursor(const QTextCursor &tc);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const CPlusPlus::Token &tokenAt(unsigned index) const;
|
|
||||||
void getTokenStartPosition(unsigned index, unsigned *line,
|
|
||||||
unsigned *column) const;
|
|
||||||
void getTokenEndPosition(unsigned index, unsigned *line,
|
|
||||||
unsigned *column) const;
|
|
||||||
|
|
||||||
QTextCursor cursor(unsigned index) const;
|
|
||||||
QTextCursor moveAtStartOfToken(unsigned index) const;
|
|
||||||
QTextCursor moveAtEndOfToken(unsigned index) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CPlusPlus::Document::Ptr _doc;
|
|
||||||
CPlusPlus::Snapshot _snapshot;
|
|
||||||
QTextCursor _textCursor;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CppEditorSupport: public QObject
|
class CppEditorSupport: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -102,9 +63,6 @@ public:
|
|||||||
CppEditorSupport(CppModelManager *modelManager);
|
CppEditorSupport(CppModelManager *modelManager);
|
||||||
virtual ~CppEditorSupport();
|
virtual ~CppEditorSupport();
|
||||||
|
|
||||||
QList<QuickFixOperationPtr> quickFixes() const
|
|
||||||
{ return _quickFixes; }
|
|
||||||
|
|
||||||
TextEditor::ITextEditor *textEditor() const;
|
TextEditor::ITextEditor *textEditor() const;
|
||||||
void setTextEditor(TextEditor::ITextEditor *textEditor);
|
void setTextEditor(TextEditor::ITextEditor *textEditor);
|
||||||
|
|
||||||
@@ -120,9 +78,6 @@ private Q_SLOTS:
|
|||||||
void updateDocument();
|
void updateDocument();
|
||||||
void updateDocumentNow();
|
void updateDocumentNow();
|
||||||
|
|
||||||
void checkDocument();
|
|
||||||
void checkDocumentNow();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 150 };
|
enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 150 };
|
||||||
|
|
||||||
@@ -132,10 +87,6 @@ private:
|
|||||||
int _updateDocumentInterval;
|
int _updateDocumentInterval;
|
||||||
QFuture<void> _documentParser;
|
QFuture<void> _documentParser;
|
||||||
QString _cachedContents;
|
QString _cachedContents;
|
||||||
|
|
||||||
QTimer *_quickFixTimer;
|
|
||||||
TextEditor::ITextMark *_quickFixMark;
|
|
||||||
QList<QuickFixOperationPtr> _quickFixes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -108,8 +108,6 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
|
|||||||
m_completion = new CppCodeCompletion(m_modelManager);
|
m_completion = new CppCodeCompletion(m_modelManager);
|
||||||
addAutoReleasedObject(m_completion);
|
addAutoReleasedObject(m_completion);
|
||||||
|
|
||||||
addAutoReleasedObject(new CppQuickFixCollector(m_modelManager));
|
|
||||||
|
|
||||||
CppLocatorFilter *locatorFilter = new CppLocatorFilter(m_modelManager,
|
CppLocatorFilter *locatorFilter = new CppLocatorFilter(m_modelManager,
|
||||||
core->editorManager());
|
core->editorManager());
|
||||||
addAutoReleasedObject(locatorFilter);
|
addAutoReleasedObject(locatorFilter);
|
||||||
|
|||||||
Reference in New Issue
Block a user