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 "Macro.h"
29 
30 #include <cplusplus/CPlusPlusForwardDeclarations.h>
31 #include <cplusplus/PreprocessorClient.h>
32 #include <cplusplus/DependencyTable.h>
33 
34 #include <utils/fileutils.h>
35 
36 #include <QSharedPointer>
37 #include <QDateTime>
38 #include <QHash>
39 #include <QFileInfo>
40 #include <QAtomicInt>
41 
42 QT_BEGIN_NAMESPACE
43 class QFutureInterfaceBase;
44 QT_END_NAMESPACE
45 
46 namespace CPlusPlus {
47 
48 class Macro;
49 class MacroArgumentReference;
50 class LookupContext;
51 
52 class CPLUSPLUS_EXPORT Document
53 {
54     Document(const Document &other);
55     void operator =(const Document &other);
56 
57     Document(const QString &fileName);
58 
59 public:
60     typedef QSharedPointer<Document> Ptr;
61 
62 public:
63     ~Document();
64 
65     unsigned revision() const;
66     void setRevision(unsigned revision);
67 
68     unsigned editorRevision() const;
69     void setEditorRevision(unsigned editorRevision);
70 
71     QDateTime lastModified() const;
72     void setLastModified(const QDateTime &lastModified);
73 
74     QString fileName() const;
75 
76     void appendMacro(const Macro &macro);
77     void addMacroUse(const Macro &macro,
78                      int bytesOffset, int bytesLength,
79                      int utf16charsOffset, int utf16charLength,
80                      int beginLine, const QVector<MacroArgumentReference> &range);
81     void addUndefinedMacroUse(const QByteArray &name,
82                               int bytesOffset, int utf16charsOffset);
83 
84     Control *control() const;
85     Control *swapControl(Control *newControl);
86     TranslationUnit *translationUnit() const;
87 
88     bool skipFunctionBody() const;
89     void setSkipFunctionBody(bool skipFunctionBody);
90 
91     int globalSymbolCount() const;
92     Symbol *globalSymbolAt(int index) const;
93 
94     Namespace *globalNamespace() const;
95     void setGlobalNamespace(Namespace *globalNamespace); // ### internal
96 
definedMacros()97     QList<Macro> definedMacros() const
98     { return _definedMacros; }
99 
100     QString functionAt(int line, int column, int *lineOpeningDeclaratorParenthesis = nullptr,
101                        int *lineClosingBrace = nullptr) const;
102     Symbol *lastVisibleSymbolAt(int line, int column = 0) const;
103     Scope *scopeAt(int line, int column = 0);
104 
105     QByteArray utf8Source() const;
106     void setUtf8Source(const QByteArray &utf8Source);
107 
fingerprint()108     QByteArray fingerprint() const { return m_fingerprint; }
setFingerprint(const QByteArray & fingerprint)109     void setFingerprint(const QByteArray &fingerprint)
110     { m_fingerprint = fingerprint; }
111 
112     LanguageFeatures languageFeatures() const;
113     void setLanguageFeatures(LanguageFeatures features);
114 
115     void startSkippingBlocks(int utf16charsOffset);
116     void stopSkippingBlocks(int utf16charsOffset);
117 
118     enum ParseMode { // ### keep in sync with CPlusPlus::TranslationUnit
119         ParseTranlationUnit,
120         ParseDeclaration,
121         ParseExpression,
122         ParseDeclarator,
123         ParseStatement
124     };
125 
126     bool isTokenized() const;
127     void tokenize();
128 
129     bool isParsed() const;
130     bool parse(ParseMode mode = ParseTranlationUnit);
131 
132     enum CheckMode {
133         Unchecked,
134         FullCheck,
135         FastCheck
136     };
137 
138     void check(CheckMode mode = FullCheck);
139 
140     static Ptr create(const QString &fileName);
141 
142     class CPLUSPLUS_EXPORT DiagnosticMessage
143     {
144     public:
145         enum Level {
146             Warning,
147             Error,
148             Fatal
149         };
150 
151     public:
152         DiagnosticMessage(int level, const QString &fileName,
153                           int line, int column,
154                           const QString &text,
155                           int length = 0)
_level(level)156             : _level(level),
157               _line(line),
158               _fileName(fileName),
159               _column(column),
160               _length(length),
161               _text(text)
162         { }
163 
level()164         int level() const
165         { return _level; }
166 
isWarning()167         bool isWarning() const
168         { return _level == Warning; }
169 
isError()170         bool isError() const
171         { return _level == Error; }
172 
isFatal()173         bool isFatal() const
174         { return _level == Fatal; }
175 
fileName()176         QString fileName() const
177         { return _fileName; }
178 
line()179         int line() const
180         { return _line; }
181 
column()182         int column() const
183         { return _column; }
184 
length()185         int length() const
186         { return _length; }
187 
text()188         QString text() const
189         { return _text; }
190 
191         bool operator==(const DiagnosticMessage &other) const;
192         bool operator!=(const DiagnosticMessage &other) const;
193 
194     private:
195         int _level;
196         int _line;
197         QString _fileName;
198         int _column;
199         int _length;
200         QString _text;
201     };
202 
addDiagnosticMessage(const DiagnosticMessage & d)203     void addDiagnosticMessage(const DiagnosticMessage &d)
204     { _diagnosticMessages.append(d); }
205 
clearDiagnosticMessages()206     void clearDiagnosticMessages()
207     { _diagnosticMessages.clear(); }
208 
diagnosticMessages()209     QList<DiagnosticMessage> diagnosticMessages() const
210     { return _diagnosticMessages; }
211 
212     class Block
213     {
214         int _bytesBegin;
215         int _bytesEnd;
216         int _utf16charsBegin;
217         int _utf16charsEnd;
218 
219     public:
220         inline Block(int bytesBegin = 0, int bytesEnd = 0,
221                      int utf16charsBegin = 0, int utf16charsEnd = 0)
_bytesBegin(bytesBegin)222             : _bytesBegin(bytesBegin),
223               _bytesEnd(bytesEnd),
224               _utf16charsBegin(utf16charsBegin),
225               _utf16charsEnd(utf16charsEnd)
226         {}
227 
bytesBegin()228         inline int bytesBegin() const
229         { return _bytesBegin; }
230 
bytesEnd()231         inline int bytesEnd() const
232         { return _bytesEnd; }
233 
utf16charsBegin()234         inline int utf16charsBegin() const
235         { return _utf16charsBegin; }
236 
utf16charsEnd()237         inline int utf16charsEnd() const
238         { return _utf16charsEnd; }
239 
containsUtf16charOffset(int utf16charOffset)240         bool containsUtf16charOffset(int utf16charOffset) const
241         { return utf16charOffset >= _utf16charsBegin && utf16charOffset < _utf16charsEnd; }
242     };
243 
244     class Include {
245         QString _resolvedFileName;
246         QString _unresolvedFileName;
247         int _line;
248         Client::IncludeType _type;
249 
250     public:
Include(const QString & unresolvedFileName,const QString & resolvedFileName,int line,Client::IncludeType type)251         Include(const QString &unresolvedFileName, const QString &resolvedFileName, int line,
252                 Client::IncludeType type)
253             : _resolvedFileName(resolvedFileName)
254             , _unresolvedFileName(unresolvedFileName)
255             , _line(line)
256             , _type(type)
257         { }
258 
resolvedFileName()259         QString resolvedFileName() const
260         { return _resolvedFileName; }
261 
unresolvedFileName()262         QString unresolvedFileName() const
263         { return _unresolvedFileName; }
264 
line()265         int line() const
266         { return _line; }
267 
type()268         Client::IncludeType type() const
269         { return _type; }
270     };
271 
272     class MacroUse: public Block {
273         Macro _macro;
274         QVector<Block> _arguments;
275         int _beginLine;
276 
277     public:
MacroUse(const Macro & macro,int bytesBegin,int bytesEnd,int utf16charsBegin,int utf16charsEnd,int beginLine)278         inline MacroUse(const Macro &macro,
279                         int bytesBegin, int bytesEnd,
280                         int utf16charsBegin, int utf16charsEnd,
281                         int beginLine)
282             : Block(bytesBegin, bytesEnd, utf16charsBegin, utf16charsEnd),
283               _macro(macro),
284               _beginLine(beginLine)
285         { }
286 
macro()287         const Macro &macro() const
288         { return _macro; }
289 
isFunctionLike()290         bool isFunctionLike() const
291         { return _macro.isFunctionLike(); }
292 
arguments()293         QVector<Block> arguments() const
294         { return _arguments; }
295 
beginLine()296         int beginLine() const
297         { return _beginLine; }
298 
299     private:
addArgument(const Block & block)300         void addArgument(const Block &block)
301         { _arguments.append(block); }
302 
303         friend class Document;
304     };
305 
306     class UndefinedMacroUse: public Block {
307         QByteArray _name;
308 
309     public:
UndefinedMacroUse(const QByteArray & name,int bytesBegin,int utf16charsBegin)310         inline UndefinedMacroUse(
311                 const QByteArray &name,
312                 int bytesBegin,
313                 int utf16charsBegin)
314             : Block(bytesBegin,
315                     bytesBegin + name.length(),
316                     utf16charsBegin,
317                     utf16charsBegin + QString::fromUtf8(name, name.size()).size()),
318               _name(name)
319         { }
320 
name()321         QByteArray name() const
322         {
323             return _name;
324         }
325     };
326 
327     QStringList includedFiles() const;
328     void addIncludeFile(const Include &include);
329 
resolvedIncludes()330     QList<Include> resolvedIncludes() const
331     { return _resolvedIncludes; }
332 
unresolvedIncludes()333     QList<Include> unresolvedIncludes() const
334     { return _unresolvedIncludes; }
335 
skippedBlocks()336     QList<Block> skippedBlocks() const
337     { return _skippedBlocks; }
338 
macroUses()339     QList<MacroUse> macroUses() const
340     { return _macroUses; }
341 
undefinedMacroUses()342     QList<UndefinedMacroUse> undefinedMacroUses() const
343     { return _undefinedMacroUses; }
344 
setIncludeGuardMacroName(const QByteArray & includeGuardMacroName)345     void setIncludeGuardMacroName(const QByteArray &includeGuardMacroName)
346     { _includeGuardMacroName = includeGuardMacroName; }
includeGuardMacroName()347     QByteArray includeGuardMacroName() const
348     { return _includeGuardMacroName; }
349 
350     const Macro *findMacroDefinitionAt(int line) const;
351     const MacroUse *findMacroUseAt(int utf16charsOffset) const;
352     const UndefinedMacroUse *findUndefinedMacroUseAt(int utf16charsOffset) const;
353 
354     void keepSourceAndAST();
355     void releaseSourceAndAST();
356 
checkMode()357     CheckMode checkMode() const
358     { return static_cast<CheckMode>(_checkMode); }
359 
360 private:
361     QString _fileName;
362     Control *_control;
363     TranslationUnit *_translationUnit;
364     Namespace *_globalNamespace;
365 
366     /// All messages generated during lexical/syntactic/semantic analysis.
367     QList<DiagnosticMessage> _diagnosticMessages;
368 
369     QList<Include> _resolvedIncludes;
370     QList<Include> _unresolvedIncludes;
371     QList<Macro> _definedMacros;
372     QList<Block> _skippedBlocks;
373     QList<MacroUse> _macroUses;
374     QList<UndefinedMacroUse> _undefinedMacroUses;
375 
376      /// the macro name of the include guard, if there is one.
377     QByteArray _includeGuardMacroName;
378 
379     QByteArray m_fingerprint;
380 
381     QByteArray _source;
382     QDateTime _lastModified;
383     QAtomicInt _keepSourceAndASTCount;
384     unsigned _revision;
385     unsigned _editorRevision;
386     quint8 _checkMode;
387 
388     friend class Snapshot;
389 };
390 
391 class CPLUSPLUS_EXPORT Snapshot
392 {
393     typedef QHash<Utils::FilePath, Document::Ptr> Base;
394 
395 public:
396     Snapshot();
397     ~Snapshot();
398 
399     typedef Base::const_iterator iterator;
400     typedef Base::const_iterator const_iterator;
401     typedef QPair<Document::Ptr, int> IncludeLocation;
402 
403     int size() const; // ### remove
404     bool isEmpty() const;
405 
406     void insert(Document::Ptr doc); // ### remove
407     void remove(const Utils::FilePath &fileName); // ### remove
remove(const QString & fileName)408     void remove(const QString &fileName)
409     { remove(Utils::FilePath::fromString(fileName)); }
410 
begin()411     const_iterator begin() const { return _documents.begin(); }
end()412     const_iterator end() const { return _documents.end(); }
413 
414     bool contains(const Utils::FilePath &fileName) const;
contains(const QString & fileName)415     bool contains(const QString &fileName) const
416     { return contains(Utils::FilePath::fromString(fileName)); }
417 
418     Document::Ptr document(const Utils::FilePath &fileName) const;
document(const QString & fileName)419     Document::Ptr document(const QString &fileName) const
420     { return document(Utils::FilePath::fromString(fileName)); }
421 
422     const_iterator find(const Utils::FilePath &fileName) const;
find(const QString & fileName)423     const_iterator find(const QString &fileName) const
424     { return find(Utils::FilePath::fromString(fileName)); }
425 
426     Snapshot simplified(Document::Ptr doc) const;
427 
428     Document::Ptr preprocessedDocument(const QByteArray &source,
429                                        const Utils::FilePath &fileName,
430                                        int withDefinedMacrosFromDocumentUntilLine = -1) const;
431     Document::Ptr preprocessedDocument(const QByteArray &source,
432                                        const QString &fileName,
433                                        int withDefinedMacrosFromDocumentUntilLine = -1) const
434     {
435         return preprocessedDocument(source,
436                                     Utils::FilePath::fromString(fileName),
437                                     withDefinedMacrosFromDocumentUntilLine);
438     }
439 
440     Document::Ptr documentFromSource(const QByteArray &preprocessedDocument,
441                                      const QString &fileName) const;
442 
443     QSet<QString> allIncludesForDocument(const QString &fileName) const;
444     QList<IncludeLocation> includeLocationsOfDocument(const QString &fileName) const;
445 
446     Utils::FilePaths filesDependingOn(const Utils::FilePath &fileName) const;
filesDependingOn(const QString & fileName)447     Utils::FilePaths filesDependingOn(const QString &fileName) const
448     { return filesDependingOn(Utils::FilePath::fromString(fileName)); }
449     void updateDependencyTable() const;
450     void updateDependencyTable(QFutureInterfaceBase &futureInterface) const;
451 
452     bool operator==(const Snapshot &other) const;
453 
454 private:
455     mutable DependencyTable m_deps;
456     Base _documents;
457 };
458 
459 } // namespace CPlusPlus
460