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 &macro)
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 &macro)
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 &macro)
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 &macro,
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 &macroName)
162 {
163     if (!_currentDoc)
164         return;
165 
166     _currentDoc->setIncludeGuardMacroName(macroName);
167 }
168