builtineditordocumentparser.cpp 8.45 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 46
{
}

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

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

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

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

    updateProjectPart();

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

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

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

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

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

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

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

106 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
    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);
145
        m_snapshot.remove(filePath());
146

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

154 155
        CppSourceProcessor sourceProcessor(m_snapshot, [&](const Document::Ptr &doc) {
            const QString fileName = doc->fileName();
156
            const bool isInEditor = fileName == filePath();
157 158 159 160 161 162
            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);
163 164
            if (m_releaseSourceAndAST)
                doc->releaseSourceAndAST();
165
        });
166
        Snapshot globalSnapshot = modelManager->snapshot();
167
        globalSnapshot.remove(filePath());
168 169
        sourceProcessor.setGlobalSnapshot(globalSnapshot);
        sourceProcessor.setWorkingCopy(workingCopy);
170
        sourceProcessor.setHeaderPaths(m_headerPaths);
171
        sourceProcessor.run(configurationFileName);
172
        if (!m_projectConfigFile.isEmpty())
173
            sourceProcessor.run(m_projectConfigFile);
174
        if (usePrecompiledHeaders()) {
175
            foreach (const QString &precompiledHeader, m_precompiledHeaders)
176
                sourceProcessor.run(precompiledHeader);
177
        }
178
        if (!editorDefines().isEmpty())
179
            sourceProcessor.run(editorDefinesFileName);
180
        sourceProcessor.run(filePath(), usePrecompiledHeaders() ? m_precompiledHeaders
181
                                                                    : QStringList());
182
        m_snapshot = sourceProcessor.snapshot();
183 184 185 186 187 188
        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;
189 190 191 192
        m_deps.build(m_snapshot);
    }
}

193
void BuiltinEditorDocumentParser::releaseResources()
194 195 196 197 198 199 200
{
    QMutexLocker locker(&m_mutex);
    m_snapshot = Snapshot();
    m_deps = DependencyTable();
    m_forceSnapshotInvalidation = true;
}

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

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

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

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

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

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