From e42ca194c53b8286447c7750feb8c7497c88e698 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen <erik.verbruggen@nokia.com> Date: Mon, 7 Jun 2010 13:06:21 +0200 Subject: [PATCH] Introduced token caching to prevent repetetive tokenizing. Also removed TokenUnderCursor as it's functionality is in the token cache. Reviewed-by: ckamm --- src/libs/cplusplus/BackwardsScanner.cpp | 63 ++++++++------- src/libs/cplusplus/BackwardsScanner.h | 14 ++-- src/libs/cplusplus/ExpressionUnderCursor.cpp | 9 ++- src/libs/cplusplus/ExpressionUnderCursor.h | 4 +- src/libs/cplusplus/MatchingText.cpp | 8 +- src/libs/cplusplus/MatchingText.h | 5 +- src/libs/cplusplus/SimpleLexer.cpp | 9 +-- src/libs/cplusplus/SimpleLexer.h | 10 +-- src/libs/cplusplus/TokenCache.cpp | 81 +++++++++++++++++++ src/libs/cplusplus/TokenCache.h | 39 +++++++++ src/libs/cplusplus/TokenUnderCursor.cpp | 67 --------------- src/libs/cplusplus/TokenUnderCursor.h | 61 -------------- src/libs/cplusplus/cplusplus-lib.pri | 8 +- src/plugins/cppeditor/cppeditor.cpp | 28 ++++--- src/plugins/cppeditor/cppeditor.h | 3 + src/plugins/cppeditor/cpphighlighter.cpp | 10 +-- src/plugins/cppeditor/cpphoverhandler.cpp | 2 +- src/plugins/cppeditor/cpphoverhandler.h | 4 + src/plugins/cpptools/cppcodecompletion.cpp | 52 ++++++------ src/plugins/cpptools/cppmodelmanager.cpp | 3 + src/plugins/cpptools/cppmodelmanager.h | 2 + .../cpptools/cppmodelmanagerinterface.h | 11 +++ .../cpptools/cpptoolseditorsupport.cpp | 11 ++- src/plugins/cpptools/cpptoolseditorsupport.h | 4 + src/plugins/debugger/watchutils.cpp | 7 +- 25 files changed, 273 insertions(+), 242 deletions(-) create mode 100644 src/libs/cplusplus/TokenCache.cpp create mode 100644 src/libs/cplusplus/TokenCache.h delete mode 100644 src/libs/cplusplus/TokenUnderCursor.cpp delete mode 100644 src/libs/cplusplus/TokenUnderCursor.h diff --git a/src/libs/cplusplus/BackwardsScanner.cpp b/src/libs/cplusplus/BackwardsScanner.cpp index 3a0fbb936f9..00f1f4046f3 100644 --- a/src/libs/cplusplus/BackwardsScanner.cpp +++ b/src/libs/cplusplus/BackwardsScanner.cpp @@ -27,33 +27,52 @@ ** **************************************************************************/ #include "BackwardsScanner.h" +#include "TokenCache.h" #include <Token.h> #include <QtGui/QTextCursor> +#include <QTextDocument> using namespace CPlusPlus; -BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suffix, int maxBlockCount) - : _offset(0) +BackwardsScanner::BackwardsScanner(TokenCache *tokenCache, const QTextCursor &cursor, int maxBlockCount, const QString &suffix) + : _tokenCache(tokenCache) + , _offset(0) , _blocksTokenized(0) , _block(cursor.block()) , _maxBlockCount(maxBlockCount) { - _tokenize.setQtMocRunEnabled(true); - _tokenize.setSkipComments(true); - _tokenize.setObjCEnabled(true); - _text = _block.text().left(cursor.position() - cursor.block().position()); + int pos = cursor.position() - cursor.block().position(); + _text = _block.text().left(pos); + _text += suffix; - if (! suffix.isEmpty()) - _text += suffix; + _tokens.append(tokenCache->tokensForBlock(_block)); - _tokens.append(_tokenize(_text, previousBlockState(_block))); + for (int i = _tokens.size() - 1; i >= 0; --i) { + const int tokenEnd = _tokens.at(i).end(); + + if ((tokenEnd < pos) || + (tokenEnd == pos && suffix.isEmpty())) { + break; + } else { + _tokens.removeAt(i); + } + } + + QString remainingText; + if (!_tokens.isEmpty()) + remainingText = _text.mid(_tokens.last().end()); + if (!remainingText.isEmpty()) { + SimpleLexer tokenize; + tokenize.setQtMocRunEnabled(true); + tokenize.setSkipComments(true); + tokenize.setObjCEnabled(true); + + _tokens.append(tokenize(remainingText, TokenCache::previousBlockState(_block))); + } _startToken = _tokens.size(); } -int BackwardsScanner::state() const -{ return _tokenize.state(); } - SimpleToken BackwardsScanner::LA(int index) const { return const_cast<BackwardsScanner *>(this)->fetchToken(_startToken - index); } @@ -71,6 +90,7 @@ const SimpleToken &BackwardsScanner::fetchToken(int tokenIndex) } else { ++_blocksTokenized; + QList<SimpleToken> newTokens = _tokenCache->tokensForBlock(_block); QString blockText = _block.text(); _text.prepend(QLatin1Char('\n')); _text.prepend(blockText); @@ -79,12 +99,11 @@ const SimpleToken &BackwardsScanner::fetchToken(int tokenIndex) for (int i = 0; i < _tokens.size(); ++i) { SimpleToken t = _tokens.at(i); t.setPosition(t.position() + blockText.length() + 1); - t.setText(_text.midRef(t.position(), t.length())); adaptedTokens.append(t); } - _tokens = _tokenize(blockText, previousBlockState(_block)); - _offset += _tokens.size(); + _tokens = newTokens; + _offset += newTokens.size(); _tokens += adaptedTokens; } } @@ -119,20 +138,6 @@ QStringRef BackwardsScanner::textRef(int index) const return _text.midRef(firstToken.begin(), firstToken.length()); } -int BackwardsScanner::previousBlockState(const QTextBlock &block) -{ - const QTextBlock prevBlock = block.previous(); - - if (prevBlock.isValid()) { - int state = prevBlock.userState(); - - if (state != -1) - return state; - } - - return 0; -} - int BackwardsScanner::size() const { return _tokens.size(); diff --git a/src/libs/cplusplus/BackwardsScanner.h b/src/libs/cplusplus/BackwardsScanner.h index cca06db75c1..25b7bd3289e 100644 --- a/src/libs/cplusplus/BackwardsScanner.h +++ b/src/libs/cplusplus/BackwardsScanner.h @@ -36,16 +36,18 @@ namespace CPlusPlus { +class TokenCache; + class CPLUSPLUS_EXPORT BackwardsScanner { enum { MAX_BLOCK_COUNT = 10 }; public: - BackwardsScanner(const QTextCursor &cursor, - const QString &suffix = QString(), - int maxBlockCount = MAX_BLOCK_COUNT); + BackwardsScanner(TokenCache *cache, + const QTextCursor &cursor, + int maxBlockCount = MAX_BLOCK_COUNT, + const QString &suffix = QString()); - int state() const; int startToken() const; int startPosition() const; @@ -67,20 +69,18 @@ public: int startOfMatchingBrace(int index) const; int startOfBlock(int index) const; - static int previousBlockState(const QTextBlock &block); - int size() const; private: const SimpleToken &fetchToken(int tokenIndex); private: + TokenCache *_tokenCache; QList<SimpleToken> _tokens; int _offset; int _blocksTokenized; QTextBlock _block; QString _text; - SimpleLexer _tokenize; int _maxBlockCount; int _startToken; }; diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index c840ad398dd..c1b439ed099 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -30,6 +30,7 @@ #include "ExpressionUnderCursor.h" #include "SimpleLexer.h" #include "BackwardsScanner.h" +#include "TokenCache.h" #include <Token.h> #include <QTextCursor> @@ -37,8 +38,8 @@ using namespace CPlusPlus; -ExpressionUnderCursor::ExpressionUnderCursor() - : _jumpedComma(false) +ExpressionUnderCursor::ExpressionUnderCursor(TokenCache *tokenCache) + : _tokenCache(tokenCache), _jumpedComma(false) { } ExpressionUnderCursor::~ExpressionUnderCursor() @@ -218,7 +219,7 @@ bool ExpressionUnderCursor::isAccessToken(const SimpleToken &tk) QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) { - BackwardsScanner scanner(cursor); + BackwardsScanner scanner(_tokenCache, cursor); _jumpedComma = false; @@ -232,7 +233,7 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const { - BackwardsScanner scanner(cursor); + BackwardsScanner scanner(_tokenCache, cursor); int index = scanner.startToken(); diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h index 3972aca6e4f..ea017ca5339 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.h +++ b/src/libs/cplusplus/ExpressionUnderCursor.h @@ -43,11 +43,12 @@ namespace CPlusPlus { class BackwardsScanner; class SimpleToken; +class TokenCache; class CPLUSPLUS_EXPORT ExpressionUnderCursor { public: - ExpressionUnderCursor(); + ExpressionUnderCursor(TokenCache *tokenCache); ~ExpressionUnderCursor(); QString operator()(const QTextCursor &cursor); @@ -59,6 +60,7 @@ private: bool isAccessToken(const SimpleToken &tk); private: + TokenCache *_tokenCache; bool _jumpedComma; }; diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index b0c5461f24b..ed1b8c12b2c 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "MatchingText.h" #include "BackwardsScanner.h" +#include "TokenCache.h" #include <Token.h> @@ -75,7 +76,8 @@ static bool isCompleteCharLiteral(const BackwardsScanner &tk, int index) return false; } -MatchingText::MatchingText() +MatchingText::MatchingText(TokenCache *tokenCache) + : _tokenCache(tokenCache) { } bool MatchingText::shouldInsertMatchingText(const QTextCursor &tc) @@ -151,7 +153,7 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri if (text.isEmpty() || !shouldInsertMatchingText(la)) return QString(); - BackwardsScanner tk(tc, textToProcess.left(*skippedChars), MAX_NUM_LINES); + BackwardsScanner tk(_tokenCache, tc, MAX_NUM_LINES, textToProcess.left(*skippedChars)); const int startToken = tk.startToken(); int index = startToken; @@ -211,7 +213,7 @@ bool MatchingText::shouldInsertNewline(const QTextCursor &tc) const QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const { - BackwardsScanner tk(tc, QString(), MAX_NUM_LINES); + BackwardsScanner tk(_tokenCache, tc, MAX_NUM_LINES); int index = tk.startToken(); if (tk[index - 1].isNot(T_LBRACE)) diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h index 5a49fa927c0..8e42dc0f817 100644 --- a/src/libs/cplusplus/MatchingText.h +++ b/src/libs/cplusplus/MatchingText.h @@ -35,11 +35,12 @@ namespace CPlusPlus { class BackwardsScanner; +class TokenCache; class CPLUSPLUS_EXPORT MatchingText { public: - MatchingText(); + MatchingText(TokenCache *tokenCache); static bool shouldInsertMatchingText(const QTextCursor &tc); static bool shouldInsertMatchingText(const QChar &lookAhead); @@ -50,6 +51,8 @@ public: private: bool shouldInsertNewline(const QTextCursor &tc) const; + + TokenCache *_tokenCache; }; } // end of namespace CPlusPlus diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp index 94be6331476..070f7dd737b 100644 --- a/src/libs/cplusplus/SimpleLexer.cpp +++ b/src/libs/cplusplus/SimpleLexer.cpp @@ -37,12 +37,11 @@ using namespace CPlusPlus; -SimpleToken::SimpleToken(const Token &token, const QStringRef &text) +SimpleToken::SimpleToken(const Token &token) : _kind(token.f.kind) , _flags(0) , _position(token.begin()) , _length(token.f.length) - , _text(text) { f._whitespace = token.f.whitespace; f._newline = token.f.newline; @@ -148,17 +147,17 @@ QList<SimpleToken> SimpleLexer::operator()(const QString &text, int state) break; QStringRef spell = text.midRef(lex.tokenOffset(), lex.tokenLength()); - SimpleToken simpleTk(tk, spell); + SimpleToken simpleTk(tk); lex.setScanAngleStringLiteralTokens(false); if (tk.f.newline && tk.is(T_POUND)) inPreproc = true; else if (inPreproc && tokens.size() == 1 && simpleTk.is(T_IDENTIFIER) && - simpleTk.text() == QLatin1String("include")) + spell == QLatin1String("include")) lex.setScanAngleStringLiteralTokens(true); else if (_objCEnabled && inPreproc && tokens.size() == 1 && simpleTk.is(T_IDENTIFIER) && - simpleTk.text() == QLatin1String("import")) + spell == QLatin1String("import")) lex.setScanAngleStringLiteralTokens(true); if (_objCEnabled && tk.is(T_IDENTIFIER)) diff --git a/src/libs/cplusplus/SimpleLexer.h b/src/libs/cplusplus/SimpleLexer.h index 7b55e8f43ae..8b5ea26c99c 100644 --- a/src/libs/cplusplus/SimpleLexer.h +++ b/src/libs/cplusplus/SimpleLexer.h @@ -42,7 +42,7 @@ class Token; class CPLUSPLUS_EXPORT SimpleToken { public: - SimpleToken(const Token &token, const QStringRef &text); + SimpleToken(const Token &token); SimpleToken() : _kind(0) @@ -66,9 +66,6 @@ public: inline int end() const { return _position + _length; } - inline QStringRef text() const - { return _text; } - inline bool followsNewline() const { return f._newline; } @@ -91,10 +88,6 @@ public: inline void setPosition(int position) { _position = position; } - // internal - inline void setText(const QStringRef &text) - { _text = text; } - public: short _kind; union { @@ -109,7 +102,6 @@ public: int _position; int _length; - QStringRef _text; friend class SimpleLexer; }; diff --git a/src/libs/cplusplus/TokenCache.cpp b/src/libs/cplusplus/TokenCache.cpp new file mode 100644 index 00000000000..0be110100df --- /dev/null +++ b/src/libs/cplusplus/TokenCache.cpp @@ -0,0 +1,81 @@ +#include "SimpleLexer.h" +#include "TokenCache.h" + +using namespace CPlusPlus; + +TokenCache::TokenCache() + : m_doc(0) + , m_revision(-1) +{} + +void TokenCache::setDocument(QTextDocument *doc) +{ + m_doc = doc; + m_revision = -1; +} + +QList<SimpleToken> TokenCache::tokensForBlock(const QTextBlock &block) const +{ + Q_ASSERT(m_doc); + Q_ASSERT(m_doc == block.document()); + + const int documentRevision = m_doc->revision(); + + if (documentRevision != m_revision) { + m_tokensByBlock.clear(); + m_revision = documentRevision; + } + + const int blockNr = block.blockNumber(); + + if (m_tokensByBlock.contains(blockNr)) { + return m_tokensByBlock.value(blockNr); + } else { + + SimpleLexer tokenize; + tokenize.setObjCEnabled(true); + tokenize.setQtMocRunEnabled(true); + tokenize.setSkipComments(false); + + const int prevState = previousBlockState(block); + QList<SimpleToken> tokens = tokenize(block.text(), prevState); + m_tokensByBlock.insert(blockNr, tokens); + + return tokens; + } +} + +SimpleToken TokenCache::tokenUnderCursor(const QTextCursor &cursor) const +{ + const QTextBlock block = cursor.block(); + const QList<SimpleToken> tokens = tokensForBlock(block); + const int column = cursor.position() - block.position(); + + for (int index = tokens.size() - 1; index >= 0; --index) { + const SimpleToken &tk = tokens.at(index); + if (tk.position() < column) + return tk; + } + + return SimpleToken(); +} + +QString TokenCache::text(const QTextBlock &block, int tokenIndex) const +{ + SimpleToken tk = tokensForBlock(block).at(tokenIndex); + return block.text().mid(tk.position(), tk.length()); +} + +int TokenCache::previousBlockState(const QTextBlock &block) +{ + const QTextBlock prevBlock = block.previous(); + + if (prevBlock.isValid()) { + int state = prevBlock.userState(); + + if (state != -1) + return state; + } + + return 0; +} diff --git a/src/libs/cplusplus/TokenCache.h b/src/libs/cplusplus/TokenCache.h new file mode 100644 index 00000000000..0e75e08d73e --- /dev/null +++ b/src/libs/cplusplus/TokenCache.h @@ -0,0 +1,39 @@ +#ifndef TOKENCACHE_H +#define TOKENCACHE_H + +#include <CPlusPlusForwardDeclarations.h> +#include <cplusplus/SimpleLexer.h> + +#include <QtCore/QHash> +#include <QtCore/QList> + +#include <QtGui/QTextBlock> +#include <QtGui/QTextCursor> +#include <QtGui/QTextDocument> + +namespace CPlusPlus { + +class CPLUSPLUS_EXPORT TokenCache +{ +public: + TokenCache(); + + void setDocument(QTextDocument *doc); + + QList<CPlusPlus::SimpleToken> tokensForBlock(const QTextBlock &block) const; + CPlusPlus::SimpleToken tokenUnderCursor(const QTextCursor &cursor) const; + + QString text(const QTextBlock &block, int tokenIndex) const; + + static int previousBlockState(const QTextBlock &block); + +private: + QTextDocument *m_doc; + + mutable int m_revision; + mutable QHash<int, QList<CPlusPlus::SimpleToken> > m_tokensByBlock; +}; + +} // namespace CPlusPlus + +#endif // TOKENCACHE_H diff --git a/src/libs/cplusplus/TokenUnderCursor.cpp b/src/libs/cplusplus/TokenUnderCursor.cpp deleted file mode 100644 index 5cbcdfc7a22..00000000000 --- a/src/libs/cplusplus/TokenUnderCursor.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 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 "TokenUnderCursor.h" -#include "BackwardsScanner.h" -#include <Token.h> - -#include <QTextCursor> -#include <QTextBlock> -#include <climits> - -using namespace CPlusPlus; - -TokenUnderCursor::TokenUnderCursor() -{ } - -TokenUnderCursor::~TokenUnderCursor() -{ } - -SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor, QTextBlock *b) -{ - SimpleLexer tokenize; - tokenize.setObjCEnabled(true); - tokenize.setSkipComments(false); - - QTextBlock block = cursor.block(); - int column = cursor.position() - cursor.block().position(); - - _text = block.text(); - _tokens = tokenize(_text, BackwardsScanner::previousBlockState(block)); - for (int index = _tokens.size() - 1; index != -1; --index) { - const SimpleToken &tk = _tokens.at(index); - if (tk.position() < column) { - if (b) - *b = block; - return tk; - } - } - - return SimpleToken(); -} diff --git a/src/libs/cplusplus/TokenUnderCursor.h b/src/libs/cplusplus/TokenUnderCursor.h deleted file mode 100644 index 92d421963c9..00000000000 --- a/src/libs/cplusplus/TokenUnderCursor.h +++ /dev/null @@ -1,61 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 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 CPLUSPLUS_TOKENUNDERCURSOR_H -#define CPLUSPLUS_TOKENUNDERCURSOR_H - -#include "SimpleLexer.h" -#include <QList> - -QT_BEGIN_NAMESPACE -class QString; -class QTextCursor; -class QTextBlock; -QT_END_NAMESPACE - -namespace CPlusPlus { - -class CPLUSPLUS_EXPORT TokenUnderCursor -{ -public: - TokenUnderCursor(); - ~TokenUnderCursor(); - - SimpleToken operator()(const QTextCursor &cursor, QTextBlock *block = 0); - - const QList<SimpleToken> &tokens() const - { return _tokens; } - -private: - QList<SimpleToken> _tokens; - QString _text; -}; - -} // end of namespace CPlusPlus - -#endif // CPLUSPLUS_TOKENUNDERCURSOR_H diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri index 3e883a4efdc..6244bf9e1b2 100644 --- a/src/libs/cplusplus/cplusplus-lib.pri +++ b/src/libs/cplusplus/cplusplus-lib.pri @@ -12,18 +12,18 @@ contains(QT, gui) { HEADERS += \ $$PWD/Icons.h \ $$PWD/ExpressionUnderCursor.h \ - $$PWD/TokenUnderCursor.h \ $$PWD/BackwardsScanner.h \ $$PWD/MatchingText.h \ - $$PWD/OverviewModel.h + $$PWD/OverviewModel.h \ + $$PWD/TokenCache.h SOURCES += \ $$PWD/Icons.cpp \ $$PWD/ExpressionUnderCursor.cpp \ - $$PWD/TokenUnderCursor.cpp \ $$PWD/BackwardsScanner.cpp \ $$PWD/MatchingText.cpp \ - $$PWD/OverviewModel.cpp + $$PWD/OverviewModel.cpp \ + $$PWD/TokenCache.cpp } HEADERS += \ diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 1a944fa4932..59d6e7383c5 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -51,11 +51,11 @@ #include <cplusplus/Overview.h> #include <cplusplus/OverviewModel.h> #include <cplusplus/SimpleLexer.h> -#include <cplusplus/TokenUnderCursor.h> #include <cplusplus/MatchingText.h> #include <cplusplus/BackwardsScanner.h> #include <cplusplus/FastPreprocessor.h> #include <cplusplus/CheckUndefinedSymbols.h> +#include <cplusplus/TokenCache.h> #include <cpptools/cppmodelmanagerinterface.h> @@ -534,7 +534,7 @@ struct FindCanonicalSymbol SemanticInfo info; FindCanonicalSymbol(CPPEditor *editor, const SemanticInfo &info) - : editor(editor), info(info) + : editor(editor), expressionUnderCursor(editor->tokenCache()), info(info) { typeOfExpression.init(info.doc, info.snapshot); } @@ -728,6 +728,11 @@ void CPPEditor::cut() finishRename(); } +TokenCache *CPPEditor::tokenCache() const +{ + return m_modelManager->tokenCache(editableInterface()); +} + void CPPEditor::startRename() { m_inRenameChanged = false; @@ -1207,7 +1212,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, SimpleLexer tokenize; tokenize.setQtMocRunEnabled(true); const QString blockText = cursor.block().text(); - const QList<SimpleToken> tokens = tokenize(blockText, BackwardsScanner::previousBlockState(cursor.block())); + const QList<SimpleToken> tokens = tokenize(blockText, TokenCache::previousBlockState(cursor.block())); bool recognizedQtMethod = false; @@ -1254,10 +1259,8 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, } if (! recognizedQtMethod) { - static TokenUnderCursor tokenUnderCursor; - - QTextBlock block; - const SimpleToken tk = tokenUnderCursor(tc, &block); + const QTextBlock block = tc.block(); + const SimpleToken tk = tokenCache()->tokenUnderCursor(tc); beginOfToken = block.position() + tk.begin(); endOfToken = block.position() + tk.end(); @@ -1287,7 +1290,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, return link; // Evaluate the type of the expression under the cursor - ExpressionUnderCursor expressionUnderCursor; + ExpressionUnderCursor expressionUnderCursor(tokenCache()); const QString expression = expressionUnderCursor(tc); TypeOfExpression typeOfExpression; @@ -1386,13 +1389,13 @@ bool CPPEditor::isElectricCharacter(const QChar &ch) const QString CPPEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text, const QChar &la, int *skippedChars) const { - MatchingText m; + MatchingText m(tokenCache()); return m.insertMatchingBrace(tc, text, la, skippedChars); } QString CPPEditor::insertParagraphSeparator(const QTextCursor &tc) const { - MatchingText m; + MatchingText m(tokenCache()); return m.insertParagraphSeparator(tc); } @@ -1415,8 +1418,7 @@ bool CPPEditor::contextAllowsAutoParentheses(const QTextCursor &cursor, bool CPPEditor::isInComment(const QTextCursor &cursor) const { - CPlusPlus::TokenUnderCursor tokenUnderCursor; - const SimpleToken tk = tokenUnderCursor(cursor); + const SimpleToken tk = tokenCache()->tokenUnderCursor(cursor); if (tk.isComment()) { const int pos = cursor.selectionEnd() - cursor.block().position(); @@ -1470,7 +1472,7 @@ void CPPEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedCha const TabSettings &ts = tabSettings(); - BackwardsScanner tk(tc, QString(), 400); + BackwardsScanner tk(tokenCache(), tc, 400); const int tokenCount = tk.startToken(); if (tokenCount != 0) { diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index dabb54799b8..35fd20127cf 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -48,6 +48,7 @@ QT_END_NAMESPACE namespace CPlusPlus { class OverviewModel; class Symbol; +class TokenCache; } namespace CppTools { @@ -198,6 +199,8 @@ public: virtual void paste(); // reimplemented from BaseTextEditor virtual void cut(); // reimplemented from BaseTextEditor + CPlusPlus::TokenCache *tokenCache() const; + public Q_SLOTS: virtual void setFontSettings(const TextEditor::FontSettings &); void setSortedMethodOverview(bool sort); diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 25354f44877..8a976fcb634 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -104,7 +104,7 @@ void CppHighlighter::highlightBlock(const QString &text) } if (tk.is(T_LPAREN) || tk.is(T_LBRACE) || tk.is(T_LBRACKET)) { - const QChar c(tk.text().at(0)); + const QChar c = text.at(tk.position()); parentheses.append(Parenthesis(Parenthesis::Opened, c, tk.position())); if (tk.is(T_LBRACE)) { ++braceDepth; @@ -117,7 +117,7 @@ void CppHighlighter::highlightBlock(const QString &text) } } } else if (tk.is(T_RPAREN) || tk.is(T_RBRACE) || tk.is(T_RBRACKET)) { - const QChar c(tk.text().at(0)); + const QChar c = text.at(tk.position()); parentheses.append(Parenthesis(Parenthesis::Closed, c, tk.position())); if (tk.is(T_RBRACE)) { --braceDepth; @@ -141,7 +141,7 @@ void CppHighlighter::highlightBlock(const QString &text) highlightAsPreprocessor = true; } else if (highlightCurrentWordAsPreprocessor && - (tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(tk.text())) + (tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(text.midRef(tk.position(), tk.length()))) setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]); else if (tk.is(T_NUMERIC_LITERAL)) @@ -180,7 +180,7 @@ void CppHighlighter::highlightBlock(const QString &text) initialState = 0; } - } else if (tk.isKeyword() || isQtKeyword(tk.text()) || tk.isObjCAtKeyword() || tk.isObjCTypeQualifier()) + } else if (tk.isKeyword() || isQtKeyword(text.midRef(tk.position(), tk.length())) || tk.isObjCAtKeyword() || tk.isObjCTypeQualifier()) setFormat(tk.position(), tk.length(), m_formats[CppKeywordFormat]); else if (tk.isOperator()) @@ -190,7 +190,7 @@ void CppHighlighter::highlightBlock(const QString &text) setFormat(tk.position(), tk.length(), m_formats[CppLabelFormat]); else if (tk.is(T_IDENTIFIER)) - highlightWord(tk.text(), tk.position(), tk.length()); + highlightWord(text.midRef(tk.position(), tk.length()), tk.position(), tk.length()); } diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index bfc03815001..651a982772a 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -232,7 +232,7 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in } // Fetch the expression's code - ExpressionUnderCursor expressionUnderCursor; + ExpressionUnderCursor expressionUnderCursor(m_modelManager->tokenCache(editor)); const QString expression = expressionUnderCursor(tc); const QList<LookupItem> types = typeOfExpression(expression, scope); diff --git a/src/plugins/cppeditor/cpphoverhandler.h b/src/plugins/cppeditor/cpphoverhandler.h index 311b8292236..95e942359b9 100644 --- a/src/plugins/cppeditor/cpphoverhandler.h +++ b/src/plugins/cppeditor/cpphoverhandler.h @@ -36,6 +36,10 @@ QT_BEGIN_NAMESPACE class QPoint; QT_END_NAMESPACE +namespace CPlusPlus { +class TokenCache; +} + namespace Core { class IEditor; } diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 935e0315959..2ede5fca70d 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -50,7 +50,6 @@ #include <cplusplus/Overview.h> #include <cplusplus/ExpressionUnderCursor.h> #include <cplusplus/BackwardsScanner.h> -#include <cplusplus/TokenUnderCursor.h> #include <cplusplus/LookupContext.h> #include <coreplugin/icore.h> @@ -65,7 +64,6 @@ #include <utils/faketooltip.h> #include <utils/qtcassert.h> -#include <QtCore/QDebug> #include <QtCore/QMap> #include <QtCore/QFile> #include <QtGui/QAction> @@ -454,7 +452,8 @@ QIcon CppCodeCompletion::iconForSymbol(Symbol *symbol) const /* Searches backwards for an access operator. */ -static int startOfOperator(TextEditor::ITextEditable *editor, +static int startOfOperator(TokenCache *tokenCache, + TextEditor::ITextEditable *editor, int pos, unsigned *kind, bool wantFunctionCall) { @@ -547,15 +546,14 @@ static int startOfOperator(TextEditor::ITextEditable *editor, } if (completionKind == T_COMMA) { - ExpressionUnderCursor expressionUnderCursor; + ExpressionUnderCursor expressionUnderCursor(tokenCache); if (expressionUnderCursor.startOfFunctionCall(tc) == -1) { completionKind = T_EOF_SYMBOL; start = pos; } } - static CPlusPlus::TokenUnderCursor tokenUnderCursor; - const SimpleToken tk = tokenUnderCursor(tc); + const SimpleToken tk = tokenCache->tokenUnderCursor(tc); if (completionKind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) { completionKind = T_EOF_SYMBOL; @@ -575,7 +573,7 @@ static int startOfOperator(TextEditor::ITextEditable *editor, start = pos; } else if (completionKind == T_LPAREN) { - const QList<SimpleToken> &tokens = tokenUnderCursor.tokens(); + const QList<SimpleToken> &tokens = tokenCache->tokensForBlock(tc.block()); int i = 0; for (; i < tokens.size(); ++i) { const SimpleToken &token = tokens.at(i); @@ -597,11 +595,11 @@ static int startOfOperator(TextEditor::ITextEditable *editor, // Check for include preprocessor directive else if (completionKind == T_STRING_LITERAL || completionKind == T_ANGLE_STRING_LITERAL || completionKind == T_SLASH) { bool include = false; - const QList<SimpleToken> &tokens = tokenUnderCursor.tokens(); + const QList<SimpleToken> &tokens = tokenCache->tokensForBlock(tc.block()); if (tokens.size() >= 3) { if (tokens.at(0).is(T_POUND) && tokens.at(1).is(T_IDENTIFIER) && (tokens.at(2).is(T_STRING_LITERAL) || tokens.at(2).is(T_ANGLE_STRING_LITERAL))) { - QStringRef directive = tokens.at(1).text(); + QString directive = tokenCache->text(tc.block(), 1); if (directive == QLatin1String("include") || directive == QLatin1String("include_next") || directive == QLatin1String("import")) { @@ -634,9 +632,10 @@ int CppCodeCompletion::startPosition() const bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor) { const int pos = editor->position(); + TokenCache *tokenCache = m_manager->tokenCache(editor); unsigned token = T_EOF_SYMBOL; - if (startOfOperator(editor, pos, &token, /*want function call=*/ true) != pos) { + if (startOfOperator(tokenCache, editor, pos, &token, /*want function call=*/ true) != pos) { if (token == T_POUND) { if (TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget())) { QTextCursor tc(edit->document()); @@ -684,7 +683,8 @@ int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditable *editor) while (editor->characterAt(endOfOperator - 1).isSpace()) --endOfOperator; - int endOfExpression = startOfOperator(editor, endOfOperator, + TokenCache *tokenCache = m_manager->tokenCache(editor); + int endOfExpression = startOfOperator(tokenCache, editor, endOfOperator, &m_completionOperator, /*want function call =*/ true); @@ -725,7 +725,7 @@ int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditable *editor) return m_startPosition; } - ExpressionUnderCursor expressionUnderCursor; + ExpressionUnderCursor expressionUnderCursor(m_manager->tokenCache(editor)); QTextCursor tc(edit->document()); if (m_completionOperator == T_COMMA) { @@ -800,14 +800,8 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit, } } - if (debug) - qDebug() << "scope:" << scope->owner()->fileName() << scope->owner()->line() << scope->owner()->column(); - QList<LookupItem> results = typeOfExpression(expression, scope, TypeOfExpression::Preprocess); - if (debug) - qDebug() << "got:" << results.size() << "results"; - if (results.isEmpty()) { if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { if (! (expression.isEmpty() || expression == QLatin1String("this"))) { @@ -828,7 +822,8 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit, QTextCursor tc(edit->document()); tc.setPosition(index); - ExpressionUnderCursor expressionUnderCursor; + TokenCache *tokenCache = m_manager->tokenCache(edit->editableInterface()); + ExpressionUnderCursor expressionUnderCursor(tokenCache); const QString baseExpression = expressionUnderCursor(tc); // Resolve the type of this expression @@ -1084,7 +1079,8 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &r QTextCursor tc(edit->document()); tc.setPosition(endOfExpression); - BackwardsScanner bs(tc); + TokenCache *tokenCache = m_manager->tokenCache(m_editor); + BackwardsScanner bs(tokenCache, tc); const int startToken = bs.startToken(); const int lineStartToken = bs.startOfLine(startToken); // make sure the required tokens are actually available @@ -1143,8 +1139,8 @@ bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults) { const LookupContext &context = typeOfExpression.context(); - if (debug) - qDebug() << Q_FUNC_INFO << __LINE__; +// if (debug) +// qDebug() << Q_FUNC_INFO << __LINE__; if (baseResults.isEmpty()) return false; @@ -1156,8 +1152,8 @@ bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults) if (ClassOrNamespace *binding = resolveExpression.baseExpression(baseResults, m_completionOperator, &replacedDotOperator)) { - if (debug) - qDebug() << "cool we got a binding for the base expression"; +// if (debug) +// qDebug() << "cool we got a binding for the base expression"; if (replacedDotOperator && binding) { // Replace . with -> @@ -1173,10 +1169,10 @@ bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults) return ! m_completions.isEmpty(); } - if (debug) { - Overview oo; - qDebug() << "hmm, got:" << oo(baseResults.first().type()); - } +// if (debug) { +// Overview oo; +// qDebug() << "hmm, got:" << oo(baseResults.first().type()); +// } return false; } diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index f6222bfc500..6c20bfe215a 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -962,6 +962,9 @@ bool CppModelManager::isCppEditor(Core::IEditor *editor) const return editor->context().contains(uid); } +TokenCache *CppModelManager::tokenCache(TextEditor::ITextEditor *editor) const +{ return editorSupport(editor)->tokenCache(); } + void CppModelManager::emitDocumentUpdated(Document::Ptr doc) { emit documentUpdated(doc); } diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 5659604141a..f75e4026334 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -108,6 +108,8 @@ public: CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const { return m_editorSupport.value(editor); } + virtual CPlusPlus::TokenCache *tokenCache(TextEditor::ITextEditor *editor) const; + void emitDocumentUpdated(CPlusPlus::Document::Ptr doc); void stopEditorSelectionsUpdate() diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index 94add378635..32250e8dade 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -44,16 +44,25 @@ namespace Core { namespace CPlusPlus { class LookupContext; + class TokenCache; } namespace ProjectExplorer { class Project; } +namespace TextEditor { + class ITextEditor; +} + namespace CppTools { class AbstractEditorSupport; +namespace Internal { +class CppEditorSupport; +} + class CPPTOOLS_EXPORT CppModelManagerInterface : public QObject { Q_OBJECT @@ -136,6 +145,8 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0; + virtual CPlusPlus::TokenCache *tokenCache(TextEditor::ITextEditor *editor) const = 0; + Q_SIGNALS: void documentUpdated(CPlusPlus::Document::Ptr doc); diff --git a/src/plugins/cpptools/cpptoolseditorsupport.cpp b/src/plugins/cpptools/cpptoolseditorsupport.cpp index 77cccf10180..33eed4e0202 100644 --- a/src/plugins/cpptools/cpptoolseditorsupport.cpp +++ b/src/plugins/cpptools/cpptoolseditorsupport.cpp @@ -67,8 +67,12 @@ void CppEditorSupport::setTextEditor(TextEditor::ITextEditor *textEditor) { _textEditor = textEditor; - if (! _textEditor) + if (_textEditor) { + if (TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(_textEditor->widget())) + _tokenCache.setDocument(ed->document()); + } else { return; + } connect(_textEditor, SIGNAL(contentsChanged()), this, SIGNAL(contentsChanged())); connect(this, SIGNAL(contentsChanged()), this, SLOT(updateDocument())); @@ -96,6 +100,11 @@ unsigned CppEditorSupport::editorRevision() const return 0; } +TokenCache *CppEditorSupport::tokenCache() +{ + return &_tokenCache; +} + int CppEditorSupport::updateDocumentInterval() const { return _updateDocumentInterval; } diff --git a/src/plugins/cpptools/cpptoolseditorsupport.h b/src/plugins/cpptools/cpptoolseditorsupport.h index 882a9ac9aa9..61fed38d3c4 100644 --- a/src/plugins/cpptools/cpptoolseditorsupport.h +++ b/src/plugins/cpptools/cpptoolseditorsupport.h @@ -36,6 +36,7 @@ #include <QSharedPointer> #include <QTextCursor> #include <cplusplus/CppDocument.h> +#include <cplusplus/TokenCache.h> QT_BEGIN_NAMESPACE class QTimer; @@ -72,6 +73,8 @@ public: QString contents(); unsigned editorRevision() const; + CPlusPlus::TokenCache *tokenCache(); + Q_SIGNALS: void contentsChanged(); @@ -89,6 +92,7 @@ private: QFuture<void> _documentParser; QString _cachedContents; unsigned _revision; + CPlusPlus::TokenCache _tokenCache; }; } // namespace Internal diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 2db73df8669..7dd096a85b2 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -736,7 +736,8 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, return QString(); QString expr = plaintext->textCursor().selectedText(); - if (expr.isEmpty()) { + CppTools::CppModelManagerInterface *modelManager = ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>(); + if (expr.isEmpty() && modelManager) { QTextCursor tc(plaintext->document()); tc.setPosition(pos); @@ -745,7 +746,7 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, tc.movePosition(QTextCursor::EndOfWord); // Fetch the expression's code. - CPlusPlus::ExpressionUnderCursor expressionUnderCursor; + CPlusPlus::ExpressionUnderCursor expressionUnderCursor(modelManager->tokenCache(editor)); expr = expressionUnderCursor(tc); *column = tc.columnNumber(); *line = tc.blockNumber(); @@ -757,7 +758,7 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, if (function && !expr.isEmpty()) if (const Core::IFile *file = editor->file()) - if (CppTools::CppModelManagerInterface *modelManager = ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>()) + if (modelManager) *function = CppTools::AbstractEditorSupport::functionAt(modelManager, file->fileName(), *line, *column); return expr; -- GitLab