Skip to content
Snippets Groups Projects
cppfindreferences.cpp 25.9 KiB
Newer Older
hjk's avatar
hjk committed
/****************************************************************************
Roberto Raggi's avatar
Roberto Raggi committed
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
** Contact: http://www.qt-project.org/legal
Roberto Raggi's avatar
Roberto Raggi committed
**
hjk's avatar
hjk committed
** This file is part of Qt Creator.
Roberto Raggi's avatar
Roberto Raggi committed
**
hjk's avatar
hjk committed
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
Roberto Raggi's avatar
Roberto Raggi committed
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
****************************************************************************/
Roberto Raggi's avatar
Roberto Raggi committed

#include "cppfindreferences.h"
Roberto Raggi's avatar
Roberto Raggi committed
#include "cpptoolsconstants.h"
#include "cppmodelmanagerinterface.h"
Roberto Raggi's avatar
Roberto Raggi committed

#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <texteditor/basefilefind.h>

#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <utils/textfileformat.h>
Roberto Raggi's avatar
Roberto Raggi committed

#include <cplusplus/Overview.h>
#include <QtConcurrentMap>
#include <QDir>
Roberto Raggi's avatar
Roberto Raggi committed

using namespace Core;
Roberto Raggi's avatar
Roberto Raggi committed
using namespace CppTools::Internal;
using namespace CppTools;
Roberto Raggi's avatar
Roberto Raggi committed
using namespace CPlusPlus;

static QByteArray getSource(const QString &fileName,
                            const CppModelManagerInterface::WorkingCopy &workingCopy)
Christian Kamm's avatar
Christian Kamm committed
{
    if (workingCopy.contains(fileName)) {
        return workingCopy.source(fileName);
    } else {
        QString fileContents;
        Utils::TextFileFormat format;
        QString error;
        QTextCodec *defaultCodec = EditorManager::defaultTextCodec();
        Utils::TextFileFormat::ReadResult result = Utils::TextFileFormat::readFile(
                    fileName, defaultCodec, &fileContents, &format, &error);
        if (result != Utils::TextFileFormat::ReadSuccess)
            qWarning() << "Could not read " << fileName << ". Error: " << error;
Christian Kamm's avatar
Christian Kamm committed

        return fileContents.toUtf8();
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;
}

static QList<QByteArray> fullIdForSymbol(Symbol *symbol)
{
    QList<QByteArray> uid;
    Symbol *current = symbol;
    do {
        uid.prepend(idForSymbol(current));
        current = current->enclosingScope();
    } while (current);
    return uid;
}

namespace {
class ProcessFile: public std::unary_function<QString, QList<Usage> >
    const CppModelManagerInterface::WorkingCopy workingCopy;
Erik Verbruggen's avatar
Erik Verbruggen committed
    Document::Ptr symbolDocument;
    QFutureInterface<Usage> *future;
    ProcessFile(const CppModelManagerInterface::WorkingCopy &workingCopy,
Erik Verbruggen's avatar
Erik Verbruggen committed
                Document::Ptr symbolDocument,
                Symbol *symbol,
                QFutureInterface<Usage> *future)
        : workingCopy(workingCopy),
          snapshot(snapshot),
          symbolDocument(symbolDocument),
          symbol(symbol),
          future(future)
    { }

    QList<Usage> operator()(const QString &fileName)
    {
        QList<Usage> usages;
        if (future->isPaused())
            future->waitForResume();
        if (future->isCanceled())
            return usages;
        const Identifier *symbolId = symbol->identifier();

        if (Document::Ptr previousDoc = snapshot.document(fileName)) {
            Control *control = previousDoc->control();
            if (!control->findIdentifier(symbolId->chars(), symbolId->size()))
                return usages; // skip this document, it's not using symbolId.
        }
        Document::Ptr doc;
        const QByteArray unpreprocessedSource = getSource(fileName, workingCopy);
        if (symbolDocument && fileName == symbolDocument->fileName()) {
            doc = symbolDocument;
            doc = snapshot.preprocessedDocument(unpreprocessedSource, fileName);

        Control *control = doc->control();
        if (control->findIdentifier(symbolId->chars(), symbolId->size()) != 0) {
            if (doc != symbolDocument)
                doc->check();
            FindUsages process(unpreprocessedSource, doc, snapshot);
        if (future->isPaused())
            future->waitForResume();
class UpdateUI: public std::binary_function<QList<Usage> &, QList<Usage>, void>
{
    QFutureInterface<Usage> *future;

public:
    UpdateUI(QFutureInterface<Usage> *future): future(future) {}
    void operator()(QList<Usage> &, const QList<Usage> &usages)
    {
        foreach (const Usage &u, usages)
            future->reportResult(u);

        future->setProgressValue(future->progressValue() + 1);
    }
};

} // end of anonymous namespace

CppFindReferences::CppFindReferences(CppModelManagerInterface *modelManager)
    : QObject(modelManager),
      m_modelManager(modelManager)
    connect(modelManager, SIGNAL(globalSnapshotChanged()), this, SLOT(flushDependencyTable()));
}

CppFindReferences::~CppFindReferences()
{
}

QList<int> CppFindReferences::references(Symbol *symbol, const LookupContext &context) const
{
    QList<int> references;

    FindUsages findUsages(context);
    findUsages(symbol);
    references = findUsages.references();

    return references;
}

static void find_helper(QFutureInterface<Usage> &future,
                        const CppModelManagerInterface::WorkingCopy workingCopy,
                        const LookupContext context,
                        CppFindReferences *findRefs,
                        Symbol *symbol)
Roberto Raggi's avatar
Roberto Raggi committed
{
Roberto Raggi's avatar
Roberto Raggi committed
    const Identifier *symbolId = symbol->identifier();
    QTC_ASSERT(symbolId != 0, return);
    const Snapshot snapshot = context.snapshot();

Roberto Raggi's avatar
Roberto Raggi committed
    const QString sourceFile = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
    QStringList files(sourceFile);
    if (symbol->isClass()
        || symbol->isForwardClassDeclaration()
        || (symbol->enclosingScope()
            && !symbol->isStatic()
            && symbol->enclosingScope()->isNamespace())) {
        foreach (const Document::Ptr &doc, context.snapshot()) {
            if (doc->fileName() == sourceFile)
                continue;

            Control *control = doc->control();

            if (control->findIdentifier(symbolId->chars(), symbolId->size()))
                files.append(doc->fileName());
        }
    } else {
        DependencyTable dependencyTable = findRefs->updateDependencyTable(snapshot);
        files += dependencyTable.filesDependingOn(sourceFile);
    files.removeDuplicates();
Roberto Raggi's avatar
Roberto Raggi committed

    future.setProgressRange(0, files.size());

    ProcessFile process(workingCopy, snapshot, context.thisDocument(), symbol, &future);
    UpdateUI reduce(&future);
    // This thread waits for blockingMappedReduced to finish, so reduce the pool's used thread count
    // so the blockingMappedReduced can use one more thread, and increase it again afterwards.
    QThreadPool::globalInstance()->releaseThread();
    QtConcurrent::blockingMappedReduced<QList<Usage> > (files, process, reduce);
    QThreadPool::globalInstance()->reserveThread();
Roberto Raggi's avatar
Roberto Raggi committed
    future.setProgressValue(files.size());
}

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)
    Find::SearchResult *search = Find::SearchResultWindow::instance()->startNewSearch(tr("C++ Usages:"),
                                                overview.prettyName(context.fullyQualifiedName(symbol)),
                                                replace ? Find::SearchResultWindow::SearchAndReplace
                                                        : Find::SearchResultWindow::SearchOnly,
                                                QLatin1String("CppEditor"));
    search->setTextToReplace(replacement);
    connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)),
            SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)));
    connect(search, SIGNAL(paused(bool)), this, SLOT(setPaused(bool)));
    search->setSearchAgainSupported(true);
    connect(search, SIGNAL(searchAgainRequested()), this, SLOT(searchAgain()));
    CppFindReferencesParameters parameters;
    parameters.symbolId = fullIdForSymbol(symbol);
    parameters.symbolFileName = QByteArray(symbol->fileName());
    search->setUserData(qVariantFromValue(parameters));
    findAll_helper(search, symbol, context);
void CppFindReferences::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context,
                                     const QString &replacement)
Roberto Raggi's avatar
Roberto Raggi committed
{
Roberto Raggi's avatar
Roberto Raggi committed
    if (const Identifier *id = symbol->identifier()) {
        const QString textToReplace = replacement.isEmpty()
                ? QString::fromUtf8(id->chars(), id->size()) : replacement;
        findUsages(symbol, context, textToReplace, true);
void CppFindReferences::findAll_helper(Find::SearchResult *search, CPlusPlus::Symbol *symbol,
                                       const CPlusPlus::LookupContext &context)
    if (!(symbol && symbol->identifier())) {
        search->finishSearch(false);
    }
    connect(search, SIGNAL(cancelled()), this, SLOT(cancel()));
    connect(search, SIGNAL(activated(Find::SearchResultItem)),
            this, SLOT(openEditor(Find::SearchResultItem)));
    Find::SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
    const CppModelManagerInterface::WorkingCopy workingCopy = m_modelManager->workingCopy();
Roberto Raggi's avatar
Roberto Raggi committed
    QFuture<Usage> result;
    result = QtConcurrent::run(&find_helper, workingCopy, context, this, symbol);
    createWatcher(result, search);

    FutureProgress *progress = ProgressManager::addTask(result, tr("Searching"),
                                                              CppTools::Constants::TASK_SEARCH);
Roberto Raggi's avatar
Roberto Raggi committed

    connect(progress, SIGNAL(clicked()), search, SLOT(popup()));
Roberto Raggi's avatar
Roberto Raggi committed
}

Roberto Raggi's avatar
Roberto Raggi committed
void CppFindReferences::onReplaceButtonClicked(const QString &text,
                                               const QList<Find::SearchResultItem> &items,
                                               bool preserveCase)
Roberto Raggi's avatar
Roberto Raggi committed
{
    const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items, preserveCase);
    if (!fileNames.isEmpty()) {
        m_modelManager->updateSourceFiles(fileNames);
        Find::SearchResultWindow::instance()->hide();
void CppFindReferences::searchAgain()
{
    Find::SearchResult *search = qobject_cast<Find::SearchResult *>(sender());
    CppFindReferencesParameters parameters = search->userData().value<CppFindReferencesParameters>();
    Snapshot snapshot = CppModelManagerInterface::instance()->snapshot();
    search->restart();
    LookupContext context;
    Symbol *symbol = findSymbol(parameters, snapshot, &context);
    if (!symbol) {
        search->finishSearch(false);
    findAll_helper(search, symbol, context);
}

namespace {
class SymbolFinder : public SymbolVisitor
{
public:
    SymbolFinder(const QList<QByteArray> &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:
    QList<QByteArray> m_uid;
    int m_index;
    Symbol *m_result;
};
}

CPlusPlus::Symbol *CppFindReferences::findSymbol(const CppFindReferencesParameters &parameters,
                                      const Snapshot &snapshot, LookupContext *context)
    QTC_ASSERT(context, return 0);
    QString symbolFile = QLatin1String(parameters.symbolFileName);
    if (!snapshot.contains(symbolFile))

    Document::Ptr newSymbolDocument = snapshot.document(symbolFile);
    // document is not parsed and has no bindings yet, do it
    QByteArray source = getSource(newSymbolDocument->fileName(), m_modelManager->workingCopy());
    Document::Ptr doc =
            snapshot.preprocessedDocument(source, newSymbolDocument->fileName());
    doc->check();

    // find matching symbol in new document and return the new parameters
    SymbolFinder finder(parameters.symbolId);
    finder.accept(doc->globalNamespace());
    if (finder.result()) {
        *context = LookupContext(doc, snapshot);
        return finder.result();
Roberto Raggi's avatar
Roberto Raggi committed
void CppFindReferences::displayResults(int first, int last)
Roberto Raggi's avatar
Roberto Raggi committed
{
    QFutureWatcher<Usage> *watcher = static_cast<QFutureWatcher<Usage> *>(sender());
    Find::SearchResult *search = m_watchers.value(watcher);
    if (!search) {
        // search was deleted while it was running
        watcher->cancel();
Roberto Raggi's avatar
Roberto Raggi committed
    for (int index = first; index != last; ++index) {
        Usage result = watcher->future().resultAt(index);
        search->addResult(result.path,
                          result.line,
                          result.lineText,
                          result.col,
                          result.len);
Roberto Raggi's avatar
Roberto Raggi committed
    }
Roberto Raggi's avatar
Roberto Raggi committed
}

void CppFindReferences::searchFinished()
{
    QFutureWatcher<Usage> *watcher = static_cast<QFutureWatcher<Usage> *>(sender());
    Find::SearchResult *search = m_watchers.value(watcher);
    if (search)
        search->finishSearch(watcher->isCanceled());
    m_watchers.remove(watcher);
    watcher->deleteLater();
Roberto Raggi's avatar
Roberto Raggi committed
}

void CppFindReferences::cancel()
{
    Find::SearchResult *search = qobject_cast<Find::SearchResult *>(sender());
    QTC_ASSERT(search, return);
    QFutureWatcher<Usage> *watcher = m_watchers.key(search);
    QTC_ASSERT(watcher, return);
    watcher->cancel();
void CppFindReferences::setPaused(bool paused)
{
    Find::SearchResult *search = qobject_cast<Find::SearchResult *>(sender());
    QTC_ASSERT(search, return);
    QFutureWatcher<Usage> *watcher = m_watchers.key(search);
    QTC_ASSERT(watcher, return);
    if (!paused || watcher->isRunning()) // guard against pausing when the search is finished
        watcher->setPaused(paused);
}

void CppFindReferences::openEditor(const Find::SearchResultItem &item)
Roberto Raggi's avatar
Roberto Raggi committed
{
    if (item.path.size() > 0) {
        EditorManager::openEditorAt(QDir::fromNativeSeparators(item.path.first()),
                                              item.lineNumber, item.textMarkPos);
    } else {
        EditorManager::openEditor(QDir::fromNativeSeparators(item.text));
Roberto Raggi's avatar
Roberto Raggi committed
}

Christian Kamm's avatar
Christian Kamm committed

namespace {

class FindMacroUsesInFile: public std::unary_function<QString, QList<Usage> >
{
    const CppModelManagerInterface::WorkingCopy workingCopy;
Christian Kamm's avatar
Christian Kamm committed
    const Snapshot snapshot;
    const Macro &macro;
    QFutureInterface<Usage> *future;
Christian Kamm's avatar
Christian Kamm committed

public:
    FindMacroUsesInFile(const CppModelManagerInterface::WorkingCopy &workingCopy,
Christian Kamm's avatar
Christian Kamm committed
                        const Snapshot snapshot,
                        const Macro &macro,
                        QFutureInterface<Usage> *future)
        : workingCopy(workingCopy), snapshot(snapshot), macro(macro), future(future)
Christian Kamm's avatar
Christian Kamm committed
    { }

    QList<Usage> operator()(const QString &fileName)
    {
        QList<Usage> usages;
        Document::Ptr doc = snapshot.document(fileName);
restart_search:
        if (future->isPaused())
            future->waitForResume();
        if (future->isCanceled())
            return usages;
Christian Kamm's avatar
Christian Kamm committed

Christian Kamm's avatar
Christian Kamm committed
        foreach (const Document::MacroUse &use, doc->macroUses()) {
            const Macro &useMacro = use.macro();

            if (useMacro.fileName() == macro.fileName()) { // Check if this is a match, but possibly against an outdated document.
                if (source.isEmpty())
                    source = getSource(fileName, workingCopy);

                if (macro.fileRevision() > useMacro.fileRevision()) {
                    // yes, it is outdated, so re-preprocess and start from scratch for this file.
                    doc = snapshot.preprocessedDocument(source, fileName);
                    usages.clear();
                    goto restart_search;
                if (macro.name() == useMacro.name()) {
                    unsigned lineStart;
                    const QByteArray &lineSource = matchingLine(use.begin(), source, &lineStart);
                    usages.append(Usage(fileName, QString::fromUtf8(lineSource), use.beginLine(),
                                        use.begin() - lineStart, useMacro.name().length()));
                }
        if (future->isPaused())
            future->waitForResume();
Christian Kamm's avatar
Christian Kamm committed
        return usages;
    }

    static QByteArray matchingLine(unsigned position, const QByteArray &source,
                                   unsigned *lineStart = 0)
Christian Kamm's avatar
Christian Kamm committed
    {
        int lineBegin = source.lastIndexOf('\n', position) + 1;
        int lineEnd = source.indexOf('\n', position);
        if (lineEnd == -1)
            lineEnd = source.length();
Christian Kamm's avatar
Christian Kamm committed

        if (lineStart)
Christian Kamm's avatar
Christian Kamm committed

        const QByteArray matchingLine = source.mid(lineBegin, lineEnd - lineBegin);
Christian Kamm's avatar
Christian Kamm committed
        return matchingLine;
    }
};

} // end of anonymous namespace

static void findMacroUses_helper(QFutureInterface<Usage> &future,
                                 const CppModelManagerInterface::WorkingCopy workingCopy,
                                 const Snapshot snapshot,
                                 CppFindReferences *findRefs,
                                 const Macro macro)
Christian Kamm's avatar
Christian Kamm committed
{
    // ensure the dependency table is updated
    DependencyTable dependencies = findRefs->updateDependencyTable(snapshot);

Christian Kamm's avatar
Christian Kamm committed
    const QString& sourceFile = macro.fileName();
    QStringList files(sourceFile);
    files += dependencies.filesDependingOn(sourceFile);
Christian Kamm's avatar
Christian Kamm committed
    files.removeDuplicates();

    future.setProgressRange(0, files.size());
    FindMacroUsesInFile process(workingCopy, snapshot, macro, &future);
Christian Kamm's avatar
Christian Kamm committed
    UpdateUI reduce(&future);
    // This thread waits for blockingMappedReduced to finish, so reduce the pool's used thread count
    // so the blockingMappedReduced can use one more thread, and increase it again afterwards.
    QThreadPool::globalInstance()->releaseThread();
Christian Kamm's avatar
Christian Kamm committed
    QtConcurrent::blockingMappedReduced<QList<Usage> > (files, process, reduce);
    QThreadPool::globalInstance()->reserveThread();
Christian Kamm's avatar
Christian Kamm committed
    future.setProgressValue(files.size());
}

void CppFindReferences::findMacroUses(const Macro &macro)
{
    findMacroUses(macro, QString(), false);
}

void CppFindReferences::findMacroUses(const Macro &macro, const QString &replacement, bool replace)
Christian Kamm's avatar
Christian Kamm committed
{
    Find::SearchResult *search = Find::SearchResultWindow::instance()->startNewSearch(
                tr("C++ Macro Usages:"),
                QString(),
                QString::fromUtf8(macro.name()),
                replace ? Find::SearchResultWindow::SearchAndReplace
                        : Find::SearchResultWindow::SearchOnly,
                QLatin1String("CppEditor"));

    search->setTextToReplace(replacement);
    connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)),
            SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>,bool)));
Christian Kamm's avatar
Christian Kamm committed

    Find::SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
Christian Kamm's avatar
Christian Kamm committed

    connect(search, SIGNAL(activated(Find::SearchResultItem)),
Christian Kamm's avatar
Christian Kamm committed
            this, SLOT(openEditor(Find::SearchResultItem)));
    connect(search, SIGNAL(cancelled()), this, SLOT(cancel()));
    connect(search, SIGNAL(paused(bool)), this, SLOT(setPaused(bool)));
Christian Kamm's avatar
Christian Kamm committed

    const Snapshot snapshot = m_modelManager->snapshot();
    const CppModelManagerInterface::WorkingCopy workingCopy = m_modelManager->workingCopy();
Christian Kamm's avatar
Christian Kamm committed

    // add the macro definition itself
    {
        const QByteArray &source = getSource(macro.fileName(), workingCopy);
        const QByteArray line = FindMacroUsesInFile::matchingLine(macro.offset(), source,
                                                                  &lineStart);
        search->addResult(macro.fileName(), macro.line(), QString::fromUtf8(line),
                          macro.offset() - lineStart, macro.name().length());
Christian Kamm's avatar
Christian Kamm committed
    }

    QFuture<Usage> result;
    result = QtConcurrent::run(&findMacroUses_helper, workingCopy, snapshot, this, macro);
    createWatcher(result, search);
Christian Kamm's avatar
Christian Kamm committed

    FutureProgress *progress = ProgressManager::addTask(result, tr("Searching"),
                                                              CppTools::Constants::TASK_SEARCH);
    connect(progress, SIGNAL(clicked()), search, SLOT(popup()));
void CppFindReferences::renameMacroUses(const Macro &macro, const QString &replacement)
{
    const QString textToReplace = replacement.isEmpty() ? QString::fromUtf8(macro.name()) : replacement;
    findMacroUses(macro, textToReplace, true);
}

DependencyTable CppFindReferences::updateDependencyTable(CPlusPlus::Snapshot snapshot)
{
    DependencyTable oldDeps = dependencyTable();
    if (oldDeps.isValidFor(snapshot))
        return oldDeps;

    DependencyTable newDeps;
    newDeps.build(snapshot);
    setDependencyTable(newDeps);
    return newDeps;
}

void CppFindReferences::flushDependencyTable()
{
    QMutexLocker locker(&m_depsLock);
    Q_UNUSED(locker);
    m_deps = DependencyTable();
}

DependencyTable CppFindReferences::dependencyTable() const
{
    QMutexLocker locker(&m_depsLock);
    Q_UNUSED(locker);
    return m_deps;
}

void CppFindReferences::setDependencyTable(const CPlusPlus::DependencyTable &newTable)
{
    QMutexLocker locker(&m_depsLock);
    Q_UNUSED(locker);
    m_deps = newTable;
}

void CppFindReferences::createWatcher(const QFuture<Usage> &future, Find::SearchResult *search)
{
    QFutureWatcher<Usage> *watcher = new QFutureWatcher<Usage>();
    watcher->setPendingResultsLimit(1);
    connect(watcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(displayResults(int,int)));
    connect(watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
    m_watchers.insert(watcher, search);
Eike Ziller's avatar
Eike Ziller committed
    watcher->setFuture(future);