builtineditordocumentparser.cpp 8.55 KB
Newer Older
1 2
/****************************************************************************
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

30
#include "builtineditordocumentparser.h"
31
#include "cppsourceprocessor.h"
32
#include "editordocumenthandle.h"
33 34 35 36 37 38 39

#include <utils/qtcassert.h>

using namespace CPlusPlus;
using namespace CppTools;
using namespace CppTools::Internal;

40
BuiltinEditorDocumentParser::BuiltinEditorDocumentParser(const QString &filePath)
41
    : BaseEditorDocumentParser(filePath)
42
    , m_forceSnapshotInvalidation(false)
43
    , m_releaseSourceAndAST(true)
44
{
45
    qRegisterMetaType<CPlusPlus::Snapshot>("CPlusPlus::Snapshot");
46 47
}

48
void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy)
49 50 51
{
    QMutexLocker locker(&m_mutex);

52
    if (filePath().isEmpty())
53 54
        return;

55
    bool invalidateSnapshot = false, invalidateConfig = false, editorDefinesChanged_ = false;
56 57 58 59

    CppModelManager *modelManager
        = dynamic_cast<CppModelManager *>(CppModelManagerInterface::instance());
    QByteArray configFile = modelManager->codeModelConfiguration();
60
    ProjectPart::HeaderPaths headerPaths;
61
    QStringList precompiledHeaders;
62
    QString projectConfigFile;
63 64 65

    updateProjectPart();

66 67 68 69 70
    if (m_forceSnapshotInvalidation) {
        invalidateSnapshot = true;
        m_forceSnapshotInvalidation = false;
    }

71 72 73 74 75 76 77
    if (const ProjectPart::Ptr part = projectPart()) {
        configFile += part->toolchainDefines;
        configFile += part->projectDefines;
        headerPaths = part->headerPaths;
        projectConfigFile = part->projectConfigFile;
        if (usePrecompiledHeaders())
            precompiledHeaders = part->precompiledHeaders;
78 79 80 81 82 83 84 85
    }

    if (configFile != m_configFile) {
        m_configFile = configFile;
        invalidateSnapshot = true;
        invalidateConfig = true;
    }

86
    if (editorDefinesChanged()) {
87
        invalidateSnapshot = true;
88 89
        editorDefinesChanged_ = true;
        resetEditorDefinesChanged();
90 91
    }

92 93
    if (headerPaths != m_headerPaths) {
        m_headerPaths = headerPaths;
94 95 96
        invalidateSnapshot = true;
    }

97 98 99 100 101
    if (projectConfigFile != m_projectConfigFile) {
        m_projectConfigFile = projectConfigFile;
        invalidateSnapshot = true;
    }

102 103 104 105 106
    if (precompiledHeaders != m_precompiledHeaders) {
        m_precompiledHeaders = precompiledHeaders;
        invalidateSnapshot = true;
    }

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    unsigned rev = 0;
    if (Document::Ptr doc = document())
        rev = doc->revision();
    else
        invalidateSnapshot = true;

    Snapshot globalSnapshot = modelManager->snapshot();

    if (invalidateSnapshot) {
        m_snapshot = Snapshot();
    } else {
        // Remove changed files from the snapshot
        QSet<QString> toRemove;
        foreach (const Document::Ptr &doc, m_snapshot) {
            QString fileName = doc->fileName();
            if (workingCopy.contains(fileName)) {
                if (workingCopy.get(fileName).second != doc->editorRevision())
                    addFileAndDependencies(&toRemove, fileName);
                continue;
            }
            Document::Ptr otherDoc = globalSnapshot.document(fileName);
            if (!otherDoc.isNull() && otherDoc->revision() != doc->revision())
                addFileAndDependencies(&toRemove, fileName);
        }

        if (!toRemove.isEmpty()) {
            invalidateSnapshot = true;
            foreach (const QString &fileName, toRemove)
                m_snapshot.remove(fileName);
        }
    }

    // Update the snapshot
    if (invalidateSnapshot) {
        const QString configurationFileName = modelManager->configurationFileName();
        if (invalidateConfig)
            m_snapshot.remove(configurationFileName);
        if (!m_snapshot.contains(configurationFileName))
            workingCopy.insert(configurationFileName, m_configFile);
146
        m_snapshot.remove(filePath());
147

148 149
        static const QString editorDefinesFileName
            = CppModelManagerInterface::editorConfigurationFileName();
150
        if (editorDefinesChanged_) {
151
            m_snapshot.remove(editorDefinesFileName);
152
            workingCopy.insert(editorDefinesFileName, editorDefines());
153 154
        }

155 156
        CppSourceProcessor sourceProcessor(m_snapshot, [&](const Document::Ptr &doc) {
            const QString fileName = doc->fileName();
157
            const bool isInEditor = fileName == filePath();
158 159 160 161 162 163
            Document::Ptr otherDoc = modelManager->document(fileName);
            unsigned newRev = otherDoc.isNull() ? 1U : otherDoc->revision() + 1;
            if (isInEditor)
                newRev = qMax(rev + 1, newRev);
            doc->setRevision(newRev);
            modelManager->emitDocumentUpdated(doc);
164 165
            if (m_releaseSourceAndAST)
                doc->releaseSourceAndAST();
166
        });
167
        Snapshot globalSnapshot = modelManager->snapshot();
168
        globalSnapshot.remove(filePath());
169 170
        sourceProcessor.setGlobalSnapshot(globalSnapshot);
        sourceProcessor.setWorkingCopy(workingCopy);
171
        sourceProcessor.setHeaderPaths(m_headerPaths);
172
        sourceProcessor.run(configurationFileName);
173
        if (!m_projectConfigFile.isEmpty())
174
            sourceProcessor.run(m_projectConfigFile);
175
        if (usePrecompiledHeaders()) {
176
            foreach (const QString &precompiledHeader, m_precompiledHeaders)
177
                sourceProcessor.run(precompiledHeader);
178
        }
179
        if (!editorDefines().isEmpty())
180
            sourceProcessor.run(editorDefinesFileName);
181
        sourceProcessor.run(filePath(), usePrecompiledHeaders() ? m_precompiledHeaders
182
                                                                    : QStringList());
183
        m_snapshot = sourceProcessor.snapshot();
184 185 186 187 188 189
        Snapshot newSnapshot = m_snapshot.simplified(document());
        for (Snapshot::const_iterator i = m_snapshot.begin(), ei = m_snapshot.end(); i != ei; ++i) {
            if (Client::isInjectedFile(i.key()))
                newSnapshot.insert(i.value());
        }
        m_snapshot = newSnapshot;
190
        m_snapshot.updateDependencyTable();
191 192

        emit finished(document(), m_snapshot);
193 194 195
    }
}

196
void BuiltinEditorDocumentParser::releaseResources()
197 198 199 200 201 202
{
    QMutexLocker locker(&m_mutex);
    m_snapshot = Snapshot();
    m_forceSnapshotInvalidation = true;
}

203
Document::Ptr BuiltinEditorDocumentParser::document() const
204 205
{
    QMutexLocker locker(&m_mutex);
206
    return m_snapshot.document(filePath());
207 208
}

209
Snapshot BuiltinEditorDocumentParser::snapshot() const
210 211 212 213 214
{
    QMutexLocker locker(&m_mutex);
    return m_snapshot;
}

215
ProjectPart::HeaderPaths BuiltinEditorDocumentParser::headerPaths() const
216 217
{
    QMutexLocker locker(&m_mutex);
218
    return m_headerPaths;
219
}
220

221
void BuiltinEditorDocumentParser::setReleaseSourceAndAST(bool onoff)
222 223 224 225 226
{
    QMutexLocker locker(&m_mutex);
    m_releaseSourceAndAST = onoff;
}

227 228 229 230 231 232 233
BuiltinEditorDocumentParser *BuiltinEditorDocumentParser::get(const QString &filePath)
{
    if (BaseEditorDocumentParser *b = BaseEditorDocumentParser::get(filePath))
        return qobject_cast<BuiltinEditorDocumentParser *>(b);
    return 0;
}

234
void BuiltinEditorDocumentParser::addFileAndDependencies(QSet<QString> *toRemove,
235
                                                         const QString &fileName) const
236 237
{
    toRemove->insert(fileName);
238
    if (fileName != filePath()) {
239
        QStringList deps = m_snapshot.filesDependingOn(fileName);
240 241 242
        toRemove->unite(QSet<QString>::fromList(deps));
    }
}