forked from qt-creator/qt-creator
		
	Generalize support for extra compilers
Allow for different extra compilers which may get called to generate additional code for the code model. The build system is expected to know what files are generated from which source file and the extra compilers know how to generate the content of those files, without touching the build directory. the uic adapter is refactored to be the first such extra compiler. The extra compiler is run when an editor for its source document loses focus, or after a timeout of 1s when the source document has been changed. Change-Id: I13c110c61120c812f02639a3684144daf8979b37 Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
This commit is contained in:
		@@ -41,13 +41,15 @@
 | 
			
		||||
#include <coreplugin/vcsmanager.h>
 | 
			
		||||
#include <coreplugin/dialogs/readonlyfilesdialog.h>
 | 
			
		||||
 | 
			
		||||
#include <extensionsystem/pluginmanager.h>
 | 
			
		||||
 | 
			
		||||
#include <projectexplorer/buildmanager.h>
 | 
			
		||||
#include <projectexplorer/projectexplorer.h>
 | 
			
		||||
#include <projectexplorer/target.h>
 | 
			
		||||
#include <projectexplorer/projecttree.h>
 | 
			
		||||
#include <qtsupport/profilereader.h>
 | 
			
		||||
#include <qtsupport/qtkitinformation.h>
 | 
			
		||||
#include <qtsupport/uicodemodelsupport.h>
 | 
			
		||||
#include <cpptools/generatedcodemodelsupport.h>
 | 
			
		||||
 | 
			
		||||
#include <resourceeditor/resourcenode.h>
 | 
			
		||||
 | 
			
		||||
@@ -1576,9 +1578,14 @@ static QmakeProjectType proFileTemplateTypeToProjectType(ProFileEvaluator::Templ
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
    // find all ui files in project
 | 
			
		||||
    class FindUiFileNodesVisitor : public NodesVisitor {
 | 
			
		||||
    // feed all files accepted by any of the factories to the callback.
 | 
			
		||||
    class FindGeneratorSourcesVisitor : public NodesVisitor {
 | 
			
		||||
    public:
 | 
			
		||||
        FindGeneratorSourcesVisitor(
 | 
			
		||||
                const QList<ProjectExplorer::ExtraCompilerFactory *> &factories,
 | 
			
		||||
                std::function<void(FileNode *, ProjectExplorer::ExtraCompilerFactory *)> callback) :
 | 
			
		||||
            factories(factories), callback(callback) {}
 | 
			
		||||
 | 
			
		||||
        void visitProjectNode(ProjectNode *projectNode)
 | 
			
		||||
        {
 | 
			
		||||
            visitFolderNode(projectNode);
 | 
			
		||||
@@ -1586,11 +1593,15 @@ namespace {
 | 
			
		||||
        void visitFolderNode(FolderNode *folderNode)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (FileNode *fileNode, folderNode->fileNodes()) {
 | 
			
		||||
                if (fileNode->fileType() == FormType)
 | 
			
		||||
                    uiFileNodes << fileNode;
 | 
			
		||||
                foreach (ProjectExplorer::ExtraCompilerFactory *factory, factories) {
 | 
			
		||||
                    if (factory->sourceType() == fileNode->fileType())
 | 
			
		||||
                        callback(fileNode, factory);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        QList<FileNode*> uiFileNodes;
 | 
			
		||||
 | 
			
		||||
        const QList<ProjectExplorer::ExtraCompilerFactory *> factories;
 | 
			
		||||
        std::function<void(FileNode *, ProjectExplorer::ExtraCompilerFactory *)> callback;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1674,6 +1685,7 @@ QmakeProFileNode::QmakeProFileNode(QmakeProject *project,
 | 
			
		||||
 | 
			
		||||
QmakeProFileNode::~QmakeProFileNode()
 | 
			
		||||
{
 | 
			
		||||
    qDeleteAll(m_extraCompilers);
 | 
			
		||||
    m_parseFutureWatcher.waitForFinished();
 | 
			
		||||
    if (m_readerExact)
 | 
			
		||||
        applyAsyncEvaluate();
 | 
			
		||||
@@ -1732,11 +1744,6 @@ QString QmakeProFileNode::singleVariableValue(const QmakeVariable var) const
 | 
			
		||||
    return values.isEmpty() ? QString() : values.first();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHash<QString, QString> QmakeProFileNode::uiFiles() const
 | 
			
		||||
{
 | 
			
		||||
    return m_uiFiles;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QmakeProFileNode::emitProFileUpdatedRecursive()
 | 
			
		||||
{
 | 
			
		||||
    emit m_project->proFileUpdated(this, m_validParse, m_parseInProgress);
 | 
			
		||||
@@ -2309,7 +2316,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
 | 
			
		||||
 | 
			
		||||
    setParseInProgress(false);
 | 
			
		||||
 | 
			
		||||
    updateUiFiles(buildDirectory);
 | 
			
		||||
    updateGeneratedFiles(buildDirectory);
 | 
			
		||||
 | 
			
		||||
    cleanupProFileReaders();
 | 
			
		||||
}
 | 
			
		||||
@@ -2542,48 +2549,63 @@ QString QmakeProFileNode::buildDir(QmakeBuildConfiguration *bc) const
 | 
			
		||||
    return QDir::cleanPath(QDir(bc->buildDirectory().toString()).absoluteFilePath(relativeDir));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Utils::FileName QmakeProFileNode::uiDirectory(const Utils::FileName &buildDir) const
 | 
			
		||||
QStringList QmakeProFileNode::generatedFiles(const QString &buildDir,
 | 
			
		||||
                                             const ProjectExplorer::FileNode *sourceFile) const
 | 
			
		||||
{
 | 
			
		||||
    if (buildDir.isEmpty())
 | 
			
		||||
        return buildDir;
 | 
			
		||||
    const QmakeVariablesHash::const_iterator it = m_varValues.constFind(UiDirVar);
 | 
			
		||||
    if (it != m_varValues.constEnd() && !it.value().isEmpty())
 | 
			
		||||
        return Utils::FileName::fromString(it.value().front());
 | 
			
		||||
    return buildDir;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString QmakeProFileNode::uiHeaderFile(const Utils::FileName &uiDir, const FileName &formFile,
 | 
			
		||||
                                       const QString &extension)
 | 
			
		||||
{
 | 
			
		||||
    if (uiDir.isEmpty())
 | 
			
		||||
        return QString();
 | 
			
		||||
 | 
			
		||||
    Utils::FileName uiHeaderFilePath = uiDir;
 | 
			
		||||
    uiHeaderFilePath.appendPath(QLatin1String("ui_") + formFile.toFileInfo().completeBaseName()
 | 
			
		||||
                                + extension);
 | 
			
		||||
    return QDir::cleanPath(uiHeaderFilePath.toString());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QmakeProFileNode::updateUiFiles(const QString &buildDir)
 | 
			
		||||
{
 | 
			
		||||
    m_uiFiles.clear();
 | 
			
		||||
 | 
			
		||||
    // Only those two project types can have ui files for us
 | 
			
		||||
    if (m_projectType == ApplicationTemplate ||
 | 
			
		||||
            m_projectType == SharedLibraryTemplate ||
 | 
			
		||||
            m_projectType == StaticLibraryTemplate) {
 | 
			
		||||
        // Find all ui files
 | 
			
		||||
        FindUiFileNodesVisitor uiFilesVisitor;
 | 
			
		||||
        this->accept(&uiFilesVisitor);
 | 
			
		||||
        const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes;
 | 
			
		||||
 | 
			
		||||
        // Find the UiDir, there can only ever be one
 | 
			
		||||
        const Utils::FileName uiDir = uiDirectory(Utils::FileName::fromString(buildDir));
 | 
			
		||||
        const QString uiExtensions = singleVariableValue(HeaderExtensionVar);
 | 
			
		||||
        foreach (const FileNode *uiFile, uiFiles) {
 | 
			
		||||
            QString headerFile = uiHeaderFile(uiDir, uiFile->filePath(), uiExtensions);
 | 
			
		||||
            if (!headerFile.isEmpty())
 | 
			
		||||
                m_uiFiles.insert(uiFile->filePath().toString(), headerFile);
 | 
			
		||||
        }
 | 
			
		||||
    // The mechanism for finding the file names is rather crude, but as we
 | 
			
		||||
    // cannot parse QMAKE_EXTRA_COMPILERS and qmake has facilities to put
 | 
			
		||||
    // ui_*.h files into a special directory, or even change the .h suffix, we
 | 
			
		||||
    // cannot help doing this here.
 | 
			
		||||
    if (sourceFile->fileType() == FormType) {
 | 
			
		||||
        FileName location;
 | 
			
		||||
        auto it = m_varValues.constFind(UiDirVar);
 | 
			
		||||
        if (it != m_varValues.constEnd() && !it.value().isEmpty())
 | 
			
		||||
            location = FileName::fromString(it.value().front());
 | 
			
		||||
        else
 | 
			
		||||
            location = FileName::fromString(buildDir);
 | 
			
		||||
        if (location.isEmpty())
 | 
			
		||||
            return QStringList();
 | 
			
		||||
        location.appendPath(QLatin1String("ui_")
 | 
			
		||||
                            + sourceFile->filePath().toFileInfo().completeBaseName()
 | 
			
		||||
                            + singleVariableValue(HeaderExtensionVar));
 | 
			
		||||
        return QStringList(QDir::cleanPath(location.toString()));
 | 
			
		||||
    } else {
 | 
			
		||||
        // TODO: Other types will be added when adapters for their compilers become available.
 | 
			
		||||
        return QStringList();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QList<ExtraCompiler *> QmakeProFileNode::extraCompilers() const
 | 
			
		||||
{
 | 
			
		||||
    return m_extraCompilers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QmakeProFileNode::updateGeneratedFiles(const QString &buildDir)
 | 
			
		||||
{
 | 
			
		||||
    // We can do this because other plugins are not supposed to keep the compilers around.
 | 
			
		||||
    qDeleteAll(m_extraCompilers);
 | 
			
		||||
    m_extraCompilers.clear();
 | 
			
		||||
 | 
			
		||||
    // Only those project types can have generated files for us
 | 
			
		||||
    if (m_projectType != ApplicationTemplate && m_projectType != SharedLibraryTemplate &&
 | 
			
		||||
            m_projectType != StaticLibraryTemplate) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QList<ExtraCompilerFactory *> factories =
 | 
			
		||||
            ProjectExplorer::ExtraCompilerFactory::extraCompilerFactories();
 | 
			
		||||
 | 
			
		||||
    FindGeneratorSourcesVisitor filesVisitor(factories, [&](
 | 
			
		||||
                                             FileNode *file, ExtraCompilerFactory *factory) {
 | 
			
		||||
        QStringList generated = generatedFiles(buildDir, file);
 | 
			
		||||
        if (!generated.isEmpty()) {
 | 
			
		||||
            FileNameList fileNames = Utils::transform(generated, [](const QString &name) {
 | 
			
		||||
                return FileName::fromString(name);
 | 
			
		||||
            });
 | 
			
		||||
            m_extraCompilers.append(factory->create(m_project, file->filePath(), fileNames));
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Find all generated files
 | 
			
		||||
    accept(&filesVisitor);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user