1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "cppcurrentdocumentfilter.h"
27 
28 #include "cppmodelmanager.h"
29 #include "cpptoolsconstants.h"
30 
31 #include <coreplugin/editormanager/editormanager.h>
32 #include <coreplugin/editormanager/ieditor.h>
33 #include <coreplugin/idocument.h>
34 
35 #include <QRegularExpression>
36 
37 using namespace CppTools::Internal;
38 using namespace CPlusPlus;
39 
CppCurrentDocumentFilter(CppTools::CppModelManager * manager)40 CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppTools::CppModelManager *manager)
41     : m_modelManager(manager)
42 {
43     setId(Constants::CURRENT_DOCUMENT_FILTER_ID);
44     setDisplayName(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME);
45     setDefaultShortcutString(".");
46     setPriority(High);
47     setDefaultIncludedByDefault(false);
48 
49     search.setSymbolsToSearchFor(SymbolSearcher::Declarations |
50                                  SymbolSearcher::Enums |
51                                  SymbolSearcher::Functions |
52                                  SymbolSearcher::Classes);
53 
54     connect(manager, &CppModelManager::documentUpdated,
55             this, &CppCurrentDocumentFilter::onDocumentUpdated);
56     connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
57             this, &CppCurrentDocumentFilter::onCurrentEditorChanged);
58     connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
59             this, &CppCurrentDocumentFilter::onEditorAboutToClose);
60 }
61 
matchesFor(QFutureInterface<Core::LocatorFilterEntry> & future,const QString & entry)62 QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
63         QFutureInterface<Core::LocatorFilterEntry> &future, const QString & entry)
64 {
65     QList<Core::LocatorFilterEntry> goodEntries;
66     QList<Core::LocatorFilterEntry> betterEntries;
67 
68     const QRegularExpression regexp = createRegExp(entry);
69     if (!regexp.isValid())
70         return goodEntries;
71 
72     const QList<IndexItem::Ptr> items = itemsOfCurrentDocument();
73     for (const IndexItem::Ptr &info : items) {
74         if (future.isCanceled())
75             break;
76 
77         QString matchString = info->symbolName();
78         if (info->type() == IndexItem::Declaration)
79             matchString = info->representDeclaration();
80         else if (info->type() == IndexItem::Function)
81             matchString += info->symbolType();
82 
83         QRegularExpressionMatch match = regexp.match(matchString);
84         if (match.hasMatch()) {
85             const bool betterMatch = match.capturedStart() == 0;
86             QVariant id = QVariant::fromValue(info);
87             QString name = matchString;
88             QString extraInfo = info->symbolScope();
89             if (info->type() == IndexItem::Function) {
90                 if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) {
91                     name += info->symbolType();
92                     match = regexp.match(name);
93                 }
94             }
95 
96             Core::LocatorFilterEntry filterEntry(this, name, id, info->icon());
97             filterEntry.extraInfo = extraInfo;
98             if (match.hasMatch()) {
99                 filterEntry.highlightInfo = highlightInfo(match);
100             } else {
101                 match = regexp.match(extraInfo);
102                 filterEntry.highlightInfo =
103                         highlightInfo(match, Core::LocatorFilterEntry::HighlightInfo::ExtraInfo);
104             }
105 
106             if (betterMatch)
107                 betterEntries.append(filterEntry);
108             else
109                 goodEntries.append(filterEntry);
110         }
111     }
112 
113     // entries are unsorted by design!
114 
115     betterEntries += goodEntries;
116     return betterEntries;
117 }
118 
accept(Core::LocatorFilterEntry selection,QString * newText,int * selectionStart,int * selectionLength) const119 void CppCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection,
120                                       QString *newText, int *selectionStart,
121                                       int *selectionLength) const
122 {
123     Q_UNUSED(newText)
124     Q_UNUSED(selectionStart)
125     Q_UNUSED(selectionLength)
126     IndexItem::Ptr info = qvariant_cast<CppTools::IndexItem::Ptr>(selection.internalData);
127     Core::EditorManager::openEditorAt(info->fileName(), info->line(), info->column());
128 }
129 
onDocumentUpdated(Document::Ptr doc)130 void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc)
131 {
132     QMutexLocker locker(&m_mutex);
133     if (m_currentFileName == doc->fileName())
134         m_itemsOfCurrentDoc.clear();
135 }
136 
onCurrentEditorChanged(Core::IEditor * currentEditor)137 void CppCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *currentEditor)
138 {
139     QMutexLocker locker(&m_mutex);
140     if (currentEditor)
141         m_currentFileName = currentEditor->document()->filePath().toString();
142     else
143         m_currentFileName.clear();
144     m_itemsOfCurrentDoc.clear();
145 }
146 
onEditorAboutToClose(Core::IEditor * editorAboutToClose)147 void CppCurrentDocumentFilter::onEditorAboutToClose(Core::IEditor *editorAboutToClose)
148 {
149     if (!editorAboutToClose)
150         return;
151 
152     QMutexLocker locker(&m_mutex);
153     if (m_currentFileName == editorAboutToClose->document()->filePath().toString()) {
154         m_currentFileName.clear();
155         m_itemsOfCurrentDoc.clear();
156     }
157 }
158 
itemsOfCurrentDocument()159 QList<CppTools::IndexItem::Ptr> CppCurrentDocumentFilter::itemsOfCurrentDocument()
160 {
161     QMutexLocker locker(&m_mutex);
162 
163     if (m_currentFileName.isEmpty())
164         return QList<CppTools::IndexItem::Ptr>();
165 
166     if (m_itemsOfCurrentDoc.isEmpty()) {
167         const Snapshot snapshot = m_modelManager->snapshot();
168         if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) {
169             IndexItem::Ptr rootNode = search(thisDocument);
170             rootNode->visitAllChildren([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
171                 m_itemsOfCurrentDoc.append(info);
172                 return IndexItem::Recurse;
173             });
174         }
175     }
176 
177     return m_itemsOfCurrentDoc;
178 }
179