forked from qt-creator/qt-creator
Mark the symbols lazily in a background thread.
This commit is contained in:
@@ -270,15 +270,13 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct FindCanonicalSymbol
|
struct CanonicalSymbol
|
||||||
{
|
{
|
||||||
CPPEditor *editor;
|
CPPEditor *editor;
|
||||||
QString code;
|
|
||||||
TypeOfExpression typeOfExpression;
|
TypeOfExpression typeOfExpression;
|
||||||
ExpressionUnderCursor expressionUnderCursor;
|
|
||||||
SemanticInfo info;
|
SemanticInfo info;
|
||||||
|
|
||||||
FindCanonicalSymbol(CPPEditor *editor, const SemanticInfo &info)
|
CanonicalSymbol(CPPEditor *editor, const SemanticInfo &info)
|
||||||
: editor(editor), info(info)
|
: editor(editor), info(info)
|
||||||
{
|
{
|
||||||
typeOfExpression.init(info.doc, info.snapshot);
|
typeOfExpression.init(info.doc, info.snapshot);
|
||||||
@@ -289,12 +287,19 @@ struct FindCanonicalSymbol
|
|||||||
return typeOfExpression.context();
|
return typeOfExpression.context();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isIdentifierChar(const QChar &ch) const
|
static inline bool isIdentifierChar(const QChar &ch)
|
||||||
{
|
{
|
||||||
return ch.isLetterOrNumber() || ch == QLatin1Char('_');
|
return ch.isLetterOrNumber() || ch == QLatin1Char('_');
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *operator()(const QTextCursor &cursor)
|
Scope *getScopeAndExpression(const QTextCursor &cursor, QString *code)
|
||||||
|
{
|
||||||
|
return getScopeAndExpression(editor, info, cursor, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Scope *getScopeAndExpression(CPPEditor *editor, const SemanticInfo &info,
|
||||||
|
const QTextCursor &cursor,
|
||||||
|
QString *code)
|
||||||
{
|
{
|
||||||
if (! info.doc)
|
if (! info.doc)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -316,10 +321,30 @@ struct FindCanonicalSymbol
|
|||||||
++pos;
|
++pos;
|
||||||
tc.setPosition(pos);
|
tc.setPosition(pos);
|
||||||
|
|
||||||
code = expressionUnderCursor(tc);
|
ExpressionUnderCursor expressionUnderCursor;
|
||||||
Scope *scope = info.doc->scopeAt(line, col);
|
*code = expressionUnderCursor(tc);
|
||||||
|
return info.doc->scopeAt(line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *operator()(const QTextCursor &cursor)
|
||||||
|
{
|
||||||
|
QString code;
|
||||||
|
|
||||||
|
if (Scope *scope = getScopeAndExpression(cursor, &code))
|
||||||
|
return operator()(scope, code);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *operator()(Scope *scope, const QString &code)
|
||||||
|
{
|
||||||
|
return canonicalSymbol(scope, code, typeOfExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Symbol *canonicalSymbol(Scope *scope, const QString &code, TypeOfExpression &typeOfExpression)
|
||||||
|
{
|
||||||
const QList<LookupItem> results = typeOfExpression(code, scope, TypeOfExpression::Preprocess);
|
const QList<LookupItem> results = typeOfExpression(code, scope, TypeOfExpression::Preprocess);
|
||||||
|
|
||||||
for (int i = 0; i < results.size(); ++i) { // ### TODO virtual methods and classes.
|
for (int i = 0; i < results.size(); ++i) { // ### TODO virtual methods and classes.
|
||||||
const LookupItem &r = results.at(i);
|
const LookupItem &r = results.at(i);
|
||||||
|
|
||||||
@@ -329,6 +354,7 @@ struct FindCanonicalSymbol
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
@@ -372,6 +398,10 @@ CPPEditor::CPPEditor(QWidget *parent)
|
|||||||
m_nextHighlightBlockNumber = 0;
|
m_nextHighlightBlockNumber = 0;
|
||||||
connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightTypeUsages(int,int)));
|
connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightTypeUsages(int,int)));
|
||||||
connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishTypeUsages()));
|
connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishTypeUsages()));
|
||||||
|
|
||||||
|
m_referencesRevision = 0;
|
||||||
|
m_referencesCursorPosition = 0;
|
||||||
|
connect(&m_referencesWatcher, SIGNAL(finished()), SLOT(markSymbolsNow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CPPEditor::~CPPEditor()
|
CPPEditor::~CPPEditor()
|
||||||
@@ -587,7 +617,7 @@ void CPPEditor::findUsages()
|
|||||||
{
|
{
|
||||||
const SemanticInfo info = m_lastSemanticInfo;
|
const SemanticInfo info = m_lastSemanticInfo;
|
||||||
|
|
||||||
FindCanonicalSymbol cs(this, info);
|
CanonicalSymbol cs(this, info);
|
||||||
Symbol *canonicalSymbol = cs(textCursor());
|
Symbol *canonicalSymbol = cs(textCursor());
|
||||||
if (canonicalSymbol) {
|
if (canonicalSymbol) {
|
||||||
m_modelManager->findUsages(canonicalSymbol, cs.context());
|
m_modelManager->findUsages(canonicalSymbol, cs.context());
|
||||||
@@ -634,7 +664,7 @@ void CPPEditor::renameUsagesNow()
|
|||||||
{
|
{
|
||||||
const SemanticInfo info = m_lastSemanticInfo;
|
const SemanticInfo info = m_lastSemanticInfo;
|
||||||
|
|
||||||
FindCanonicalSymbol cs(this, info);
|
CanonicalSymbol cs(this, info);
|
||||||
if (Symbol *canonicalSymbol = cs(textCursor())) {
|
if (Symbol *canonicalSymbol = cs(textCursor())) {
|
||||||
if (canonicalSymbol->identifier() != 0) {
|
if (canonicalSymbol->identifier() != 0) {
|
||||||
if (showWarningMessage()) {
|
if (showWarningMessage()) {
|
||||||
@@ -649,42 +679,73 @@ void CPPEditor::renameUsagesNow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPPEditor::markSymbols(Symbol *canonicalSymbol, const SemanticInfo &info)
|
void CPPEditor::markSymbolsNow()
|
||||||
{
|
{
|
||||||
//updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
if (m_references.isCanceled())
|
||||||
|
return;
|
||||||
|
else if (m_referencesCursorPosition != position())
|
||||||
|
return;
|
||||||
|
else if (m_referencesRevision != editorRevision())
|
||||||
|
return;
|
||||||
|
|
||||||
abortRename();
|
const SemanticInfo info = m_lastSemanticInfo;
|
||||||
|
TranslationUnit *unit = info.doc->translationUnit();
|
||||||
|
const QList<int> result = m_references.result();
|
||||||
|
|
||||||
QList<QTextEdit::ExtraSelection> selections;
|
QList<QTextEdit::ExtraSelection> selections;
|
||||||
|
|
||||||
if (info.doc && canonicalSymbol) {
|
foreach (int index, result) {
|
||||||
TranslationUnit *unit = info.doc->translationUnit();
|
unsigned line, column;
|
||||||
|
unit->getTokenPosition(index, &line, &column);
|
||||||
|
|
||||||
LookupContext context(info.doc, info.snapshot);
|
if (column)
|
||||||
const QList<int> references = m_modelManager->references(canonicalSymbol, context);
|
--column; // adjust the column position.
|
||||||
foreach (int index, references) {
|
|
||||||
unsigned line, column;
|
|
||||||
unit->getTokenPosition(index, &line, &column);
|
|
||||||
|
|
||||||
if (column)
|
const int len = unit->tokenAt(index).f.length;
|
||||||
--column; // adjust the column position.
|
|
||||||
|
|
||||||
const int len = unit->tokenAt(index).f.length;
|
QTextCursor cursor(document()->findBlockByNumber(line - 1));
|
||||||
|
cursor.setPosition(cursor.position() + column);
|
||||||
|
cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
|
||||||
|
|
||||||
QTextCursor cursor(document()->findBlockByNumber(line - 1));
|
QTextEdit::ExtraSelection sel;
|
||||||
cursor.setPosition(cursor.position() + column);
|
sel.format = m_occurrencesFormat;
|
||||||
cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
|
sel.cursor = cursor;
|
||||||
|
selections.append(sel);
|
||||||
|
|
||||||
QTextEdit::ExtraSelection sel;
|
|
||||||
sel.format = m_occurrencesFormat;
|
|
||||||
sel.cursor = cursor;
|
|
||||||
selections.append(sel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setExtraSelections(CodeSemanticsSelection, selections);
|
setExtraSelections(CodeSemanticsSelection, selections);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QList<int> lazyFindReferences(Scope *scope, QString code, const LookupContext &context)
|
||||||
|
{
|
||||||
|
TypeOfExpression typeOfExpression;
|
||||||
|
typeOfExpression.init(context.thisDocument(), context.snapshot(), context.bindings());
|
||||||
|
if (Symbol *canonicalSymbol = CanonicalSymbol::canonicalSymbol(scope, code, typeOfExpression))
|
||||||
|
return CppTools::CppModelManagerInterface::instance()->references(canonicalSymbol, context);
|
||||||
|
return QList<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPEditor::markSymbols(const QTextCursor &tc, const SemanticInfo &info)
|
||||||
|
{
|
||||||
|
abortRename();
|
||||||
|
|
||||||
|
if (! info.doc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CanonicalSymbol cs(this, info);
|
||||||
|
QString expression;
|
||||||
|
if (Scope *scope = cs.getScopeAndExpression(this, info, tc, &expression)) {
|
||||||
|
LookupContext context(info.doc, info.snapshot);
|
||||||
|
|
||||||
|
m_references.cancel();
|
||||||
|
m_referencesRevision = info.revision;
|
||||||
|
m_referencesCursorPosition = position();
|
||||||
|
m_references = QtConcurrent::run(&lazyFindReferences, scope, expression, context);
|
||||||
|
m_referencesWatcher.setFuture(m_references);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CPPEditor::renameSymbolUnderCursor()
|
void CPPEditor::renameSymbolUnderCursor()
|
||||||
{
|
{
|
||||||
updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
||||||
@@ -1792,8 +1853,7 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
|
|||||||
if (! m_renameSelections.isEmpty())
|
if (! m_renameSelections.isEmpty())
|
||||||
setExtraSelections(CodeSemanticsSelection, m_renameSelections); // ###
|
setExtraSelections(CodeSemanticsSelection, m_renameSelections); // ###
|
||||||
else {
|
else {
|
||||||
FindCanonicalSymbol cs(this, semanticInfo);
|
markSymbols(textCursor(), semanticInfo);
|
||||||
markSymbols(cs(textCursor()), semanticInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_lastSemanticInfo.forced = false; // clear the forced flag
|
m_lastSemanticInfo.forced = false; // clear the forced flag
|
||||||
|
@@ -236,13 +236,15 @@ private Q_SLOTS:
|
|||||||
void highlightTypeUsages(int from, int to);
|
void highlightTypeUsages(int from, int to);
|
||||||
void finishTypeUsages();
|
void finishTypeUsages();
|
||||||
|
|
||||||
|
void markSymbolsNow();
|
||||||
|
|
||||||
void performQuickFix(int index);
|
void performQuickFix(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool showWarningMessage() const;
|
bool showWarningMessage() const;
|
||||||
void setShowWarningMessage(bool showWarningMessage);
|
void setShowWarningMessage(bool showWarningMessage);
|
||||||
|
|
||||||
void markSymbols(CPlusPlus::Symbol *canonicalSymbol, const SemanticInfo &info);
|
void markSymbols(const QTextCursor &tc, const SemanticInfo &info);
|
||||||
bool sortedOutline() const;
|
bool sortedOutline() const;
|
||||||
CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
|
CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
|
||||||
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
|
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
|
||||||
@@ -305,6 +307,11 @@ private:
|
|||||||
QFutureWatcher<SemanticInfo::Use> m_highlightWatcher;
|
QFutureWatcher<SemanticInfo::Use> m_highlightWatcher;
|
||||||
unsigned m_highlightRevision; // the editor revision that requested the highlight
|
unsigned m_highlightRevision; // the editor revision that requested the highlight
|
||||||
int m_nextHighlightBlockNumber;
|
int m_nextHighlightBlockNumber;
|
||||||
|
|
||||||
|
QFuture<QList<int> > m_references;
|
||||||
|
QFutureWatcher<QList<int> > m_referencesWatcher;
|
||||||
|
unsigned m_referencesRevision;
|
||||||
|
int m_referencesCursorPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user