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 "FastPreprocessor.h"
27
28 #include <cplusplus/Literals.h>
29 #include <cplusplus/TranslationUnit.h>
30
31 #include <QDir>
32
33 using namespace CPlusPlus;
34
FastPreprocessor(const Snapshot & snapshot)35 FastPreprocessor::FastPreprocessor(const Snapshot &snapshot)
36 : _snapshot(snapshot)
37 , _preproc(this, &_env)
38 , _addIncludesToCurrentDoc(false)
39 { }
40
run(Document::Ptr newDoc,const QByteArray & source,bool mergeDefinedMacrosOfDocument)41 QByteArray FastPreprocessor::run(Document::Ptr newDoc,
42 const QByteArray &source,
43 bool mergeDefinedMacrosOfDocument)
44 {
45 std::swap(newDoc, _currentDoc);
46 _addIncludesToCurrentDoc = _currentDoc->resolvedIncludes().isEmpty()
47 && _currentDoc->unresolvedIncludes().isEmpty();
48 const QString fileName = _currentDoc->fileName();
49 _preproc.setExpandFunctionlikeMacros(false);
50 _preproc.setKeepComments(true);
51
52 if (Document::Ptr doc = _snapshot.document(fileName)) {
53 _merged.insert(fileName);
54
55 for (Snapshot::const_iterator i = _snapshot.begin(), ei = _snapshot.end(); i != ei; ++i) {
56 if (isInjectedFile(i.key().toString()))
57 mergeEnvironment(i.key().toString());
58 }
59
60 foreach (const Document::Include &i, doc->resolvedIncludes())
61 mergeEnvironment(i.resolvedFileName());
62
63 if (mergeDefinedMacrosOfDocument)
64 _env.addMacros(_currentDoc->definedMacros());
65 }
66
67 const QByteArray preprocessed = _preproc.run(fileName, source);
68 // qDebug("FastPreprocessor::run for %s produced [[%s]]", fileName.toUtf8().constData(), preprocessed.constData());
69 std::swap(newDoc, _currentDoc);
70 return preprocessed;
71 }
72
sourceNeeded(int line,const QString & fileName,IncludeType mode,const QStringList & initialIncludes)73 void FastPreprocessor::sourceNeeded(int line, const QString &fileName, IncludeType mode,
74 const QStringList &initialIncludes)
75 {
76 Q_UNUSED(initialIncludes)
77 Q_ASSERT(_currentDoc);
78 if (_addIncludesToCurrentDoc) {
79 // CHECKME: Is that cleanName needed?
80 const QString cleanName = QDir::cleanPath(fileName);
81 _currentDoc->addIncludeFile(Document::Include(fileName, cleanName, line, mode));
82 }
83 mergeEnvironment(fileName);
84 }
85
mergeEnvironment(const QString & fileName)86 void FastPreprocessor::mergeEnvironment(const QString &fileName)
87 {
88 if (! _merged.contains(fileName)) {
89 _merged.insert(fileName);
90
91 if (Document::Ptr doc = _snapshot.document(fileName)) {
92 foreach (const Document::Include &i, doc->resolvedIncludes())
93 mergeEnvironment(i.resolvedFileName());
94
95 _env.addMacros(doc->definedMacros());
96 }
97 }
98 }
99
macroAdded(const Macro & macro)100 void FastPreprocessor::macroAdded(const Macro ¯o)
101 {
102 Q_ASSERT(_currentDoc);
103
104 _currentDoc->appendMacro(macro);
105 }
106
revision(const Snapshot & s,const Macro & m)107 static const Macro revision(const Snapshot &s, const Macro &m)
108 {
109 if (Document::Ptr d = s.document(m.fileName())) {
110 Macro newMacro(m);
111 newMacro.setFileRevision(d->revision());
112 return newMacro;
113 }
114
115 return m;
116 }
117
passedMacroDefinitionCheck(int bytesOffset,int utf16charsOffset,int line,const Macro & macro)118 void FastPreprocessor::passedMacroDefinitionCheck(int bytesOffset, int utf16charsOffset,
119 int line, const Macro ¯o)
120 {
121 Q_ASSERT(_currentDoc);
122
123 _currentDoc->addMacroUse(revision(_snapshot, macro),
124 bytesOffset, macro.name().size(),
125 utf16charsOffset, macro.nameToQString().size(),
126 line, QVector<MacroArgumentReference>());
127 }
128
failedMacroDefinitionCheck(int bytesOffset,int utf16charsOffset,const ByteArrayRef & name)129 void FastPreprocessor::failedMacroDefinitionCheck(int bytesOffset, int utf16charsOffset,
130 const ByteArrayRef &name)
131 {
132 Q_ASSERT(_currentDoc);
133
134 _currentDoc->addUndefinedMacroUse(QByteArray(name.start(), name.size()),
135 bytesOffset, utf16charsOffset);
136 }
137
notifyMacroReference(int bytesOffset,int utf16charsOffset,int line,const Macro & macro)138 void FastPreprocessor::notifyMacroReference(int bytesOffset, int utf16charsOffset,
139 int line, const Macro ¯o)
140 {
141 Q_ASSERT(_currentDoc);
142
143 _currentDoc->addMacroUse(revision(_snapshot, macro),
144 bytesOffset, macro.name().size(),
145 utf16charsOffset, macro.nameToQString().size(),
146 line, QVector<MacroArgumentReference>());
147 }
148
startExpandingMacro(int bytesOffset,int utf16charsOffset,int line,const Macro & macro,const QVector<MacroArgumentReference> & actuals)149 void FastPreprocessor::startExpandingMacro(int bytesOffset, int utf16charsOffset,
150 int line, const Macro ¯o,
151 const QVector<MacroArgumentReference> &actuals)
152 {
153 Q_ASSERT(_currentDoc);
154
155 _currentDoc->addMacroUse(revision(_snapshot, macro),
156 bytesOffset, macro.name().size(),
157 utf16charsOffset, macro.nameToQString().size(),
158 line, actuals);
159 }
160
markAsIncludeGuard(const QByteArray & macroName)161 void FastPreprocessor::markAsIncludeGuard(const QByteArray ¯oName)
162 {
163 if (!_currentDoc)
164 return;
165
166 _currentDoc->setIncludeGuardMacroName(macroName);
167 }
168