summaryrefslogtreecommitdiff
path: root/src/plugins/cpptools
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/cpptools')
-rw-r--r--src/plugins/cpptools/cppcodecompletion.cpp54
-rw-r--r--src/plugins/cpptools/cppcodecompletion.h21
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h3
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.cpp248
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.h58
-rw-r--r--src/plugins/cpptools/cpptoolsplugin.cpp4
6 files changed, 387 insertions, 1 deletions
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index d69d683f81..ffa09ae1c8 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -30,6 +30,7 @@
#include "cppcodecompletion.h"
#include "cppmodelmanager.h"
#include "cppdoxygen.h"
+#include "cpptoolseditorsupport.h"
#include <Control.h>
#include <AST.h>
@@ -421,6 +422,59 @@ void FunctionArgumentWidget::updateHintText()
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.m_text = op->description();
+ item.m_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.m_data.toInt());
+ TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(_editor->widget());
+ quickFix->apply(ed->textCursor());
+}
+
+void CppQuickFixCollector::cleanup()
+{
+ _completions.clear();
+}
+
CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
: ICompletionCollector(manager),
m_manager(manager),
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index d32b81703f..7a00f364b1 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -52,6 +52,27 @@ namespace Internal {
class CppModelManager;
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
{
Q_OBJECT
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index d768d8d50b..5069f039a8 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -86,6 +86,9 @@ public:
bool isCppEditor(Core::IEditor *editor) const; // ### private
+ CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const
+ { return m_editorSupport.value(editor); }
+
void emitDocumentUpdated(CPlusPlus::Document::Ptr doc);
void stopEditorSelectionsUpdate()
diff --git a/src/plugins/cpptools/cpptoolseditorsupport.cpp b/src/plugins/cpptools/cpptoolseditorsupport.cpp
index a73e91b8da..1d69f3f7eb 100644
--- a/src/plugins/cpptools/cpptoolseditorsupport.cpp
+++ b/src/plugins/cpptools/cpptoolseditorsupport.cpp
@@ -33,9 +33,214 @@
#include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h>
-#include <QTimer>
+#include <AST.h>
+#include <ASTVisitor.h>
+#include <TranslationUnit.h>
+
+#include <QtCore/QTimer>
using namespace CppTools::Internal;
+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 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)
+ { }
+
+ 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;
+ }
+
+ /*
+ virtual bool visit(ForStatementAST *ast)
+ {
+ if (! checkPosition(ast))
+ return true;
+
+ if (ast->initializer && ast->initializer->asDeclarationStatement() != 0) {
+ if (checkPosition(ast->initializer)) {
+ // move initializer
+ _nodes.append(ast);
+ }
+ }
+
+ 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.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.length - 1);
+ return tc;
+}
CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
: QObject(modelManager),
@@ -46,6 +251,13 @@ CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
_updateDocumentTimer->setSingleShot(true);
_updateDocumentTimer->setInterval(_updateDocumentInterval);
connect(_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
+
+ _quickFixMark = new QuickFixMark(this);
+
+ _quickFixTimer = new QTimer(this);
+ _quickFixTimer->setSingleShot(true);
+ _quickFixTimer->setInterval(DEFAULT_QUICKFIX_INTERVAL);
+ connect(_quickFixTimer, SIGNAL(timeout()), this, SLOT(checkDocumentNow()));
}
CppEditorSupport::~CppEditorSupport()
@@ -62,7 +274,11 @@ void CppEditorSupport::setTextEditor(TextEditor::ITextEditor *textEditor)
return;
connect(_textEditor, SIGNAL(contentsChanged()), this, SIGNAL(contentsChanged()));
+ connect(qobject_cast<TextEditor::BaseTextEditor *>(_textEditor->widget()), SIGNAL(cursorPositionChanged()),
+ this, SLOT(checkDocument()));
+
connect(this, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
+
updateDocument();
}
@@ -107,5 +323,35 @@ 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 QByteArray plainText = contents();
+ const QString fileName = _textEditor->file()->fileName();
+ const QByteArray preprocessedCode = snapshot.preprocessedCode(plainText, fileName);
+
+ if (Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, fileName)) {
+ 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;
+ }
+ }
+}
diff --git a/src/plugins/cpptools/cpptoolseditorsupport.h b/src/plugins/cpptools/cpptoolseditorsupport.h
index 4df23c7b25..f962ca0063 100644
--- a/src/plugins/cpptools/cpptoolseditorsupport.h
+++ b/src/plugins/cpptools/cpptoolseditorsupport.h
@@ -33,13 +33,21 @@
#include <QObject>
#include <QPointer>
#include <QFuture>
+#include <QSharedPointer>
+#include <QTextCursor.h>
+#include <cplusplus/CppDocument.h>
QT_BEGIN_NAMESPACE
class QTimer;
QT_END_NAMESPACE
+namespace CPlusPlus {
+ class AST;
+}
+
namespace TextEditor {
class ITextEditor;
+ class ITextMark;
} // end of namespace TextEditor
namespace CppTools {
@@ -47,6 +55,46 @@ namespace Internal {
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::AST *_node;
+ CPlusPlus::Document::Ptr _doc;
+ CPlusPlus::Snapshot _snapshot;
+ QTextCursor _textCursor;
+};
+
class CppEditorSupport: public QObject
{
Q_OBJECT
@@ -55,6 +103,9 @@ public:
CppEditorSupport(CppModelManager *modelManager);
virtual ~CppEditorSupport();
+ QList<QuickFixOperationPtr> quickFixes() const
+ { return _quickFixes; }
+
TextEditor::ITextEditor *textEditor() const;
void setTextEditor(TextEditor::ITextEditor *textEditor);
@@ -70,6 +121,9 @@ private Q_SLOTS:
void updateDocument();
void updateDocumentNow();
+ void checkDocument();
+ void checkDocumentNow();
+
private:
enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 150 };
@@ -79,6 +133,10 @@ private:
int _updateDocumentInterval;
QFuture<void> _documentParser;
QByteArray _cachedContents;
+
+ QTimer *_quickFixTimer;
+ TextEditor::ITextMark *_quickFixMark;
+ QList<QuickFixOperationPtr> _quickFixes;
};
} // namespace Internal
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 470aeea146..62d77eb27d 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -151,8 +151,12 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
// Objects
m_modelManager = new CppModelManager(this);
addAutoReleasedObject(m_modelManager);
+
m_completion = new CppCodeCompletion(m_modelManager);
addAutoReleasedObject(m_completion);
+
+ addAutoReleasedObject(new CppQuickFixCollector(m_modelManager));
+
CppQuickOpenFilter *quickOpenFilter = new CppQuickOpenFilter(m_modelManager,
core->editorManager());
addAutoReleasedObject(quickOpenFilter);