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 #pragma once
27 
28 #include "qmljs_global.h"
29 #include "qmljsbundle.h"
30 #include "qmljsdocument.h"
31 #include "qmljsqrcparser.h"
32 #include "qmljsdialect.h"
33 
34 // #include <cplusplus/CppDocument.h>
35 #include <utils/environment.h>
36 
37 #include <QFuture>
38 #include <QHash>
39 #include <QObject>
40 #include <QPointer>
41 #include <QStringList>
42 
QT_FORWARD_DECLARE_CLASS(QTimer)43 QT_FORWARD_DECLARE_CLASS(QTimer)
44 
45 namespace ProjectExplorer { class Project; }
46 
47 namespace QmlJS {
48 
49 class Snapshot;
50 class PluginDumper;
51 
52 class QMLJS_EXPORT ModelManagerInterface: public QObject
53 {
54     Q_OBJECT
55 
56 public:
57     enum QrcResourceSelector {
58         ActiveQrcResources,
59         AllQrcResources
60     };
61 
62     class ProjectInfo
63     {
64     public:
ProjectInfo()65         ProjectInfo()
66             : tryQmlDump(false), qmlDumpHasRelocatableFlag(true)
67         { }
68 
ProjectInfo(QPointer<ProjectExplorer::Project> project)69         ProjectInfo(QPointer<ProjectExplorer::Project> project)
70             : project(project)
71             , tryQmlDump(false), qmlDumpHasRelocatableFlag(true)
72         { }
73 
74         explicit operator bool() const
75         { return ! project.isNull(); }
76 
isValid()77         bool isValid() const
78         { return ! project.isNull(); }
79 
isNull()80         bool isNull() const
81         { return project.isNull(); }
82 
83     public: // attributes
84         QPointer<ProjectExplorer::Project> project;
85         QStringList sourceFiles;
86         PathsAndLanguages importPaths;
87         QStringList activeResourceFiles;
88         QStringList allResourceFiles;
89         QHash<QString, QString> resourceFileContents;
90 
91         // whether trying to run qmldump makes sense
92         bool tryQmlDump;
93         bool qmlDumpHasRelocatableFlag;
94         QString qmlDumpPath;
95         ::Utils::Environment qmlDumpEnvironment;
96 
97         QString qtImportsPath;
98         QString qtQmlPath;
99         QString qtVersionString;
100         QmlJS::QmlLanguageBundles activeBundle;
101         QmlJS::QmlLanguageBundles extendedBundle;
102     };
103 
104     class WorkingCopy
105     {
106     public:
107         typedef QHash<QString, QPair<QString, int> > Table;
108 
109         void insert(const QString &fileName, const QString &source, int revision = 0)
110         { _elements.insert(fileName, {source, revision}); }
111 
contains(const QString & fileName)112         bool contains(const QString &fileName) const
113         { return _elements.contains(fileName); }
114 
source(const QString & fileName)115         QString source(const QString &fileName) const
116         { return _elements.value(fileName).first; }
117 
get(const QString & fileName)118         QPair<QString, int> get(const QString &fileName) const
119         { return _elements.value(fileName); }
120 
all()121         Table all() const
122         { return _elements; }
123 
124     private:
125         Table _elements;
126     };
127 
128     class CppData
129     {
130     public:
131         QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedTypes;
132         QHash<QString, QString> contextProperties;
133     };
134 
135     typedef QHash<QString, CppData> CppDataHash;
136     typedef QHashIterator<QString, CppData> CppDataHashIterator;
137 
138 public:
139     ModelManagerInterface(QObject *parent = 0);
140     ~ModelManagerInterface() override;
141 
142     static Dialect guessLanguageOfFile(const QString &fileName);
143     static QStringList globPatternsForLanguages(const QList<Dialect> languages);
144     static ModelManagerInterface *instance();
145     static void writeWarning(const QString &msg);
146     static WorkingCopy workingCopy();
147 
148     QmlJS::Snapshot snapshot() const;
149     QmlJS::Snapshot newestSnapshot() const;
150 
151     void activateScan();
152     void updateSourceFiles(const QStringList &files,
153                            bool emitDocumentOnDiskChanged);
154     void fileChangedOnDisk(const QString &path);
155     void removeFiles(const QStringList &files);
156     QStringList qrcPathsForFile(const QString &file, const QLocale *locale = 0,
157                                 ProjectExplorer::Project *project = 0,
158                                 QrcResourceSelector resources = AllQrcResources);
159     QStringList filesAtQrcPath(const QString &path, const QLocale *locale = 0,
160                                ProjectExplorer::Project *project = 0,
161                                QrcResourceSelector resources = AllQrcResources);
162     QMap<QString,QStringList> filesInQrcPath(const QString &path,
163                                              const QLocale *locale = 0,
164                                              ProjectExplorer::Project *project = 0,
165                                              bool addDirs = false,
166                                              QrcResourceSelector resources = AllQrcResources);
167 
168     QList<ProjectInfo> projectInfos() const;
169     ProjectInfo projectInfo(ProjectExplorer::Project *project,
170                             const ModelManagerInterface::ProjectInfo &defaultValue = ProjectInfo()) const;
171     void updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p);
172 
173     void updateDocument(QmlJS::Document::Ptr doc);
174     void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info);
175     void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc);
176     void updateQrcFile(const QString &path);
177     ProjectInfo projectInfoForPath(const QString &path) const;
178     QList<ProjectInfo> allProjectInfosForPath(const QString &path) const;
179     bool isIdle() const ;
180 
181     QStringList importPathsNames() const;
182     QmlJS::QmlLanguageBundles activeBundles() const;
183     QmlJS::QmlLanguageBundles extendedBundles() const;
184 
185     void loadPluginTypes(const QString &libraryPath, const QString &importPath,
186                          const QString &importUri, const QString &importVersion);
187 
188     CppDataHash cppData() const;
189     LibraryInfo builtins(const Document::Ptr &doc) const;
190     ViewerContext completeVContext(const ViewerContext &vCtx,
191                                    const Document::Ptr &doc = Document::Ptr(0)) const;
192     ViewerContext defaultVContext(Dialect language = Dialect::Qml,
193                                   const Document::Ptr &doc = Document::Ptr(0),
194                                   bool autoComplete = true) const;
195     void setDefaultVContext(const ViewerContext &vContext);
196     virtual ProjectInfo defaultProjectInfo() const;
197     virtual ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project) const;
198 
199 
200     // Blocks until all parsing threads are done. Used for testing.
201     void joinAllThreads();
202 
203     QmlJS::Document::Ptr ensuredGetDocumentForPath(const QString &filePath);
204     static void importScan(QFutureInterface<void> &future,
205                     WorkingCopy workingCopyInternal,
206                     PathsAndLanguages paths,
207                     ModelManagerInterface *modelManager,
208                     bool emitDocChangedOnDisk, bool libOnly = true, bool forceRescan = false);
209 
210     virtual void resetCodeModel();
211     void removeProjectInfo(ProjectExplorer::Project *project);
212 //     void maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc);
213 
214 Q_SIGNALS:
215     void documentUpdated(QmlJS::Document::Ptr doc);
216     void documentChangedOnDisk(QmlJS::Document::Ptr doc);
217     void aboutToRemoveFiles(const QStringList &files);
218     void libraryInfoUpdated(const QString &path, const QmlJS::LibraryInfo &info);
219     void projectInfoUpdated(const ProjectInfo &pinfo);
220     void projectPathChanged(const QString &projectPath);
221 
222 protected:
223 //     Q_INVOKABLE void queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc, bool scan);
224     Q_INVOKABLE void asyncReset();
225 //     virtual void startCppQmlTypeUpdate();
226     QMutex *mutex() const;
227     virtual QHash<QString,Dialect> languageForSuffix() const;
228     virtual void writeMessageInternal(const QString &msg) const;
229     virtual WorkingCopy workingCopyInternal() const;
230     virtual void addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const;
231 
232     QFuture<void> refreshSourceFiles(const QStringList &sourceFiles,
233                                      bool emitDocumentOnDiskChanged);
234 
235     static void parseLoop(QSet<QString> &scannedPaths, QSet<QString> &newLibraries,
236                           WorkingCopy workingCopyInternal, QStringList files, ModelManagerInterface *modelManager,
237                           QmlJS::Dialect mainLanguage, bool emitDocChangedOnDisk,
238                           std::function<bool (qreal)> reportProgress);
239     static void parse(QFutureInterface<void> &future,
240                       WorkingCopy workingCopyInternal,
241                       QStringList files,
242                       ModelManagerInterface *modelManager,
243                       QmlJS::Dialect mainLanguage,
244                       bool emitDocChangedOnDisk);
245 //     static void updateCppQmlTypes(QFutureInterface<void> &futureInterface,
246 //                                   ModelManagerInterface *qmlModelManager,
247 //                                   CPlusPlus::Snapshot snapshot,
248 //                                   QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents);
249 
250     void maybeScan(const PathsAndLanguages &importPaths);
251     void updateImportPaths();
252     void loadQmlTypeDescriptionsInternal(const QString &path);
253     void setDefaultProject(const ProjectInfo &pInfo, ProjectExplorer::Project *p);
254 
255 private:
256     void cleanupFutures();
257     void iterateQrcFiles(ProjectExplorer::Project *project,
258                          QrcResourceSelector resources,
259                          std::function<void(QrcParser::ConstPtr)> callback);
260 
261     mutable QMutex m_mutex;
262     QmlJS::Snapshot m_validSnapshot;
263     QmlJS::Snapshot m_newestSnapshot;
264     PathsAndLanguages m_allImportPaths;
265     QStringList m_defaultImportPaths;
266     QmlJS::QmlLanguageBundles m_activeBundles;
267     QmlJS::QmlLanguageBundles m_extendedBundles;
268     QHash<Dialect, QmlJS::ViewerContext> m_defaultVContexts;
269     bool m_shouldScanImports;
270     QSet<QString> m_scannedPaths;
271 
272     QTimer *m_updateCppQmlTypesTimer;
273     QTimer *m_asyncResetTimer;
274 //     QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > m_queuedCppDocuments;
275     QFuture<void> m_cppQmlTypesUpdater;
276     QrcCache m_qrcCache;
277     QHash<QString, QString> m_qrcContents;
278 
279     CppDataHash m_cppDataHash;
280 //     QHash<QString, QList<CPlusPlus::Document::Ptr> > m_cppDeclarationFiles;
281     mutable QMutex m_cppDataMutex;
282 
283     // project integration
284     QMap<ProjectExplorer::Project *, ProjectInfo> m_projects;
285     ProjectInfo m_defaultProjectInfo;
286     ProjectExplorer::Project *m_defaultProject;
287     QMultiHash<QString, ProjectExplorer::Project *> m_fileToProject;
288 
289     PluginDumper *m_pluginDumper;
290 
291     QList<QFuture<void>> m_futures;
292     bool m_indexerEnabled;
293 };
294 
295 } // namespace QmlJS
296