From cd2dab2922329570ede5b15c80016a443e215734 Mon Sep 17 00:00:00 2001 From: Eike Ziller <eike.ziller@nokia.com> Date: Tue, 20 Dec 2011 18:45:29 +0100 Subject: [PATCH] Implement "search again" for find usages (C++) Change-Id: Ia3dc174c64da9194401883a1a989a712cb7aaed8 Reviewed-by: Leandro Melo <leandro.melo@nokia.com> --- src/plugins/cpptools/cppfindreferences.cpp | 222 ++++++++++++++++++--- src/plugins/cpptools/cppfindreferences.h | 17 +- 2 files changed, 214 insertions(+), 25 deletions(-) diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index d59191a5c1b..7317348dd34 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -122,14 +122,13 @@ public: if (! control->findIdentifier(symbolId->chars(), symbolId->size())) return usages; // skip this document, it's not using symbolId. } - Document::Ptr doc; QByteArray source; const QString unpreprocessedSource = getSource(fileName, workingCopy); - if (symbolDocument && fileName == symbolDocument->fileName()) + if (symbolDocument && fileName == symbolDocument->fileName()) { doc = symbolDocument; - else { + } else { source = snapshot.preprocessedCode(unpreprocessedSource, fileName); doc = snapshot.documentFromSource(source, fileName); doc->tokenize(); @@ -232,14 +231,34 @@ static void find_helper(QFutureInterface<Usage> &future, future.setProgressValue(files.size()); } -void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context) +void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, + const CPlusPlus::LookupContext &context) +{ + findUsages(symbol, context, QString(), false); +} + +void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, + const CPlusPlus::LookupContext &context, + const QString &replacement, + bool replace) { Overview overview; Find::SearchResult *search = Find::SearchResultWindow::instance()->startNewSearch(tr("C++ Usages:"), QString(), overview(context.fullyQualifiedName(symbol)), - Find::SearchResultWindow::SearchOnly); - findAll_helper(search, symbol, context); + replace ? Find::SearchResultWindow::SearchAndReplace + : Find::SearchResultWindow::SearchOnly, + QLatin1String("CppEditor")); + search->setTextToReplace(replacement); + connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)), + SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>))); + search->setSearchAgainSupported(true); + connect(search, SIGNAL(searchAgainRequested()), this, SLOT(searchAgain())); + CppFindReferencesParameters parameters; + parameters.context = context; + parameters.symbol = symbol; + search->setUserData(qVariantFromValue(parameters)); + findAll_helper(search); } void CppFindReferences::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context, @@ -248,26 +267,14 @@ void CppFindReferences::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus: if (const Identifier *id = symbol->identifier()) { const QString textToReplace = replacement.isEmpty() ? QString::fromUtf8(id->chars(), id->size()) : replacement; - - Overview overview; - Find::SearchResult *search = Find::SearchResultWindow::instance()->startNewSearch( - tr("C++ Usages:"), - QString(), - overview(context.fullyQualifiedName(symbol)), - Find::SearchResultWindow::SearchAndReplace, QLatin1String("CppEditor")); - search->setTextToReplace(textToReplace); - - connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)), - SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>))); - - findAll_helper(search, symbol, context); + findUsages(symbol, context, textToReplace, true); } } -void CppFindReferences::findAll_helper(Find::SearchResult *search, - Symbol *symbol, const LookupContext &context) +void CppFindReferences::findAll_helper(Find::SearchResult *search) { - if (! (symbol && symbol->identifier())) { + CppFindReferencesParameters parameters = search->userData().value<CppFindReferencesParameters>(); + if (!(parameters.symbol && parameters.symbol->identifier())) { search->finishSearch(); return; } @@ -278,7 +285,8 @@ void CppFindReferences::findAll_helper(Find::SearchResult *search, Find::SearchResultWindow::instance()->popup(true); const CppModelManagerInterface::WorkingCopy workingCopy = _modelManager->workingCopy(); QFuture<Usage> result; - result = QtConcurrent::run(&find_helper, workingCopy, context, this, symbol); + result = QtConcurrent::run(&find_helper, workingCopy, + parameters.context, this, parameters.symbol); createWatcher(result, search); Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager(); @@ -298,6 +306,174 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text, } } +void CppFindReferences::searchAgain() +{ + Find::SearchResult *search = qobject_cast<Find::SearchResult *>(sender()); + CppFindReferencesParameters parameters = search->userData().value<CppFindReferencesParameters>(); + Snapshot snapshot = CppModelManagerInterface::instance()->snapshot(); + search->reset(); + if (!findSymbol(¶meters, snapshot)) { + search->finishSearch(); + return; + } + search->setUserData(qVariantFromValue(parameters)); + findAll_helper(search); +} + +static QByteArray typeId(Symbol *symbol) +{ + if (symbol->asEnum()) { + return QByteArray("e"); + } else if (symbol->asFunction()) { + return QByteArray("f"); + } else if (symbol->asNamespace()) { + return QByteArray("n"); + } else if (symbol->asTemplate()) { + return QByteArray("t"); + } else if (symbol->asNamespaceAlias()) { + return QByteArray("na"); + } else if (symbol->asClass()) { + return QByteArray("c"); + } else if (symbol->asBlock()) { + return QByteArray("b"); + } else if (symbol->asUsingNamespaceDirective()) { + return QByteArray("u"); + } else if (symbol->asUsingDeclaration()) { + return QByteArray("ud"); + } else if (symbol->asDeclaration()) { + QByteArray temp("d,"); + Overview pretty; + temp.append(pretty.prettyType(symbol->type()).toLatin1()); + return temp; + } else if (symbol->asArgument()) { + return QByteArray("a"); + } else if (symbol->asTypenameArgument()) { + return QByteArray("ta"); + } else if (symbol->asBaseClass()) { + return QByteArray("bc"); + } else if (symbol->asForwardClassDeclaration()) { + return QByteArray("fcd"); + } else if (symbol->asQtPropertyDeclaration()) { + return QByteArray("qpd"); + } else if (symbol->asQtEnum()) { + return QByteArray("qe"); + } else if (symbol->asObjCBaseClass()) { + return QByteArray("ocbc"); + } else if (symbol->asObjCBaseProtocol()) { + return QByteArray("ocbp"); + } else if (symbol->asObjCClass()) { + return QByteArray("occ"); + } else if (symbol->asObjCForwardClassDeclaration()) { + return QByteArray("ocfd"); + } else if (symbol->asObjCProtocol()) { + return QByteArray("ocp"); + } else if (symbol->asObjCForwardProtocolDeclaration()) { + return QByteArray("ocfpd"); + } else if (symbol->asObjCMethod()) { + return QByteArray("ocm"); + } else if (symbol->asObjCPropertyDeclaration()) { + return QByteArray("ocpd"); + } + return QByteArray("unknown"); +} + +static QByteArray idForSymbol(Symbol *symbol) +{ + QByteArray uid(typeId(symbol)); + if (const Identifier *id = symbol->identifier()) { + uid.append("|"); + uid.append(QByteArray(id->chars(), id->size())); + } else if (Scope *scope = symbol->enclosingScope()) { + // add the index of this symbol within its enclosing scope + // (counting symbols without identifier of the same type) + int count = 0; + Scope::iterator it = scope->firstMember(); + while (it != scope->lastMember() && *it != symbol) { + Symbol *val = *it; + ++it; + if (val->identifier() || typeId(val) != uid) + continue; + ++count; + } + uid.append(QString::number(count).toLocal8Bit()); + } + return uid; +} + +namespace { +class SymbolFinder : public SymbolVisitor +{ +public: + SymbolFinder(const QStringList &uid) : m_uid(uid), m_index(0), m_result(0) { } + Symbol *result() const { return m_result; } + + bool preVisit(Symbol *symbol) + { + if (m_result) + return false; + int index = m_index; + if (symbol->asScope()) + ++m_index; + if (index >= m_uid.size()) + return false; + if (idForSymbol(symbol) != m_uid.at(index)) + return false; + if (index == m_uid.size() - 1) { + // symbol found + m_result = symbol; + return false; + } + return true; + } + + void postVisit(Symbol *symbol) + { + if (symbol->asScope()) + --m_index; + } + +private: + QStringList m_uid; + int m_index; + Symbol *m_result; +}; +} + +bool CppFindReferences::findSymbol(CppFindReferencesParameters *parameters, + const Snapshot &snapshot) +{ + QString symbolFile = QLatin1String(parameters->symbol->fileName()); + if (!snapshot.contains(symbolFile)) { + return false; + } + + Document::Ptr newSymbolDocument = snapshot.document(symbolFile); + // document is not parsed and has no bindings yet, do it + QString source = getSource(newSymbolDocument->fileName(), _modelManager->workingCopy()); + const QByteArray &preprocessedCode = + snapshot.preprocessedCode(source, newSymbolDocument->fileName()); + Document::Ptr doc = + snapshot.documentFromSource(preprocessedCode, newSymbolDocument->fileName()); + doc->check(); + + // construct id of old symbol + QStringList uid; + Symbol *current = parameters->symbol; + do { + uid.prepend(idForSymbol(current)); + current = current->enclosingScope(); + } while (current); + // find matching symbol in new document and return the new parameters + SymbolFinder finder(uid); + finder.accept(doc->globalNamespace()); + if (finder.result()) { + parameters->symbol = finder.result(); + parameters->context = LookupContext(doc, snapshot); + return true; + } + return false; +} + void CppFindReferences::displayResults(int first, int last) { QFutureWatcher<Usage> *watcher = static_cast<QFutureWatcher<Usage> *>(sender()); diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h index 5d08406e7c2..03755b0849a 100644 --- a/src/plugins/cpptools/cppfindreferences.h +++ b/src/plugins/cpptools/cppfindreferences.h @@ -58,6 +58,13 @@ class CppModelManagerInterface; namespace CppTools { namespace Internal { +class CppFindReferencesParameters +{ +public: + CPlusPlus::LookupContext context; + CPlusPlus::Symbol *symbol; +}; + class CppFindReferences: public QObject { Q_OBJECT @@ -83,13 +90,17 @@ private Q_SLOTS: void cancel(); void openEditor(const Find::SearchResultItem &item); void onReplaceButtonClicked(const QString &text, const QList<Find::SearchResultItem> &items); + void searchAgain(); private: - void findAll_helper(Find::SearchResult *search, - CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context); + void findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context, + const QString &replacement, bool replace); + void findAll_helper(Find::SearchResult *search); CPlusPlus::DependencyTable dependencyTable() const; void setDependencyTable(const CPlusPlus::DependencyTable &newTable); void createWatcher(const QFuture<CPlusPlus::Usage> &future, Find::SearchResult *search); + bool findSymbol(CppFindReferencesParameters *parameters, + const CPlusPlus::Snapshot &snapshot); private: QPointer<CPlusPlus::CppModelManagerInterface> _modelManager; @@ -102,4 +113,6 @@ private: } // namespace Internal } // namespace CppTools +Q_DECLARE_METATYPE(CppTools::Internal::CppFindReferencesParameters) + #endif // CPPFINDREFERENCES_H -- GitLab