diff options
| author | Christian Kandeler <christian.kandeler@qt.io> | 2022-09-06 17:52:22 +0200 |
|---|---|---|
| committer | Christian Kandeler <christian.kandeler@qt.io> | 2022-09-14 07:42:49 +0000 |
| commit | 8beeea5b5ea4e1207600c238044c72356e1a4fb8 (patch) | |
| tree | 9418736e2cef2eada2a11945a527403c5e90fa19 /src/plugins/cppeditor/cppmodelmanager.cpp | |
| parent | 0867d6f6a5054491ed826a77760a85134f410e5a (diff) | |
| download | qt-creator-8beeea5b5ea4e1207600c238044c72356e1a4fb8.tar.gz | |
CppEditor: Add support for showing pre-processed source files
Fixes: QTCREATORBUG-4
Change-Id: I819709e69e604849264e745da98065829f7cb228
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
Diffstat (limited to 'src/plugins/cppeditor/cppmodelmanager.cpp')
| -rw-r--r-- | src/plugins/cppeditor/cppmodelmanager.cpp | 135 |
1 files changed, 134 insertions, 1 deletions
diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 94f292a6be..d5c8a28870 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -4,18 +4,21 @@ #include "cppmodelmanager.h" #include "abstracteditorsupport.h" -#include "cppoutlinemodel.h" #include "baseeditordocumentprocessor.h" #include "builtinindexingsupport.h" +#include "compileroptionsbuilder.h" #include "cppcodemodelinspectordumper.h" +#include "cppcodemodelsettings.h" #include "cppcurrentdocumentfilter.h" #include "cppeditorconstants.h" +#include "cppeditortr.h" #include "cppfindreferences.h" #include "cppincludesfilter.h" #include "cppindexingsupport.h" #include "cpplocatordata.h" #include "cpplocatorfilter.h" #include "cppbuiltinmodelmanagersupport.h" +#include "cppprojectfile.h" #include "cppsourceprocessor.h" #include "cpptoolsjsextension.h" #include "cpptoolsreuse.h" @@ -23,10 +26,12 @@ #include "symbolfinder.h" #include "symbolsfindfilter.h" +#include <coreplugin/coreconstants.h> #include <coreplugin/documentmanager.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/icore.h> #include <coreplugin/jsexpander.h> +#include <coreplugin/messagemanager.h> #include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/vcsmanager.h> #include <cplusplus/ASTPath.h> @@ -34,13 +39,17 @@ #include <cplusplus/TypeOfExpression.h> #include <extensionsystem/pluginmanager.h> +#include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/gcctoolchain.h> #include <projectexplorer/kitinformation.h> #include <projectexplorer/kitmanager.h> #include <projectexplorer/project.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectmacro.h> +#include <projectexplorer/projecttree.h> #include <projectexplorer/session.h> +#include <projectexplorer/target.h> #include <texteditor/textdocument.h> @@ -48,6 +57,9 @@ #include <utils/fileutils.h> #include <utils/hostosinfo.h> #include <utils/qtcassert.h> +#include <utils/qtcprocess.h> +#include <utils/savefile.h> +#include <utils/temporarydirectory.h> #include <QCoreApplication> #include <QDebug> @@ -320,6 +332,127 @@ void CppModelManager::switchHeaderSource(bool inNextSplit, Backend backend) inNextSplit); } +void CppModelManager::showPreprocessedFile(bool inNextSplit) +{ + const Core::IDocument *doc = Core::EditorManager::currentDocument(); + QTC_ASSERT(doc, return); + + static const auto showError = [](const QString &reason) { + Core::MessageManager::writeFlashing(Tr::tr("Cannot show preprocessed file: %1") + .arg(reason)); + }; + static const auto showFallbackWarning = [](const QString &reason) { + Core::MessageManager::writeSilently(Tr::tr("%1, falling back to built-in preprocessor") + .arg(reason)); + }; + static const auto saveAndOpen = [](const FilePath &filePath, const QByteArray &contents, + bool inNextSplit) { + SaveFile f(filePath.toString()); + if (!f.open()) { + showError(Tr::tr("Failed to open output file \"%1\"").arg(filePath.toUserOutput())); + return; + } + f.write(contents); + if (!f.commit()) { + showError(Tr::tr("Failed to write output file \"%1\"").arg(filePath.toUserOutput())); + return; + } + f.close(); + openEditor(filePath, inNextSplit, Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); + }; + + const FilePath &filePath = doc->filePath(); + const QString outFileName = filePath.completeBaseName() + "_preprocessed." + filePath.suffix(); + const auto outFilePath = FilePath::fromString( + TemporaryDirectory::masterTemporaryDirectory()->filePath(outFileName)); + const auto useBuiltinPreprocessor = [filePath, outFilePath, inNextSplit, + contents = doc->contents()] { + const Document::Ptr preprocessedDoc = instance()->snapshot() + .preprocessedDocument(contents, filePath); + QByteArray content = R"(/* Created using Qt Creator's built-in preprocessor. */ +/* See Tools -> Debug Qt Creator -> Inspect C++ Code Model for the parameters used. + * Adapt the respective setting in Edit -> Preferences -> C++ -> Code Model to invoke + * the actual compiler instead. + */ +)"; + saveAndOpen(outFilePath, content.append(preprocessedDoc->utf8Source()), inNextSplit); + }; + + if (codeModelSettings()->useBuiltinPreprocessor()) { + useBuiltinPreprocessor(); + return; + } + + const Project * const project = ProjectTree::currentProject(); + if (!project || !project->activeTarget() + || !project->activeTarget()->activeBuildConfiguration()) { + showFallbackWarning(Tr::tr("Could not determine which compiler to invoke")); + useBuiltinPreprocessor(); + return; + } + + const ToolChain * tc = nullptr; + const ProjectFile classifier(filePath.toString(), ProjectFile::classify(filePath.toString())); + if (classifier.isC()) { + tc = ToolChainKitAspect::cToolChain(project->activeTarget()->kit()); + } else if (classifier.isCxx() || classifier.isHeader()) { + tc = ToolChainKitAspect::cxxToolChain(project->activeTarget()->kit()); + } else { + showFallbackWarning(Tr::tr("Could not determine which compiler to invoke")); + useBuiltinPreprocessor(); + return; + } + + const bool isGcc = dynamic_cast<const GccToolChain *>(tc); + const bool isMsvc = !isGcc + && (tc->typeId() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + || tc->typeId() == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID); + if (!isGcc && !isMsvc) { + showFallbackWarning(Tr::tr("Could not determine compiler command line")); + useBuiltinPreprocessor(); + return; + } + + const ProjectPart::ConstPtr projectPart = Utils::findOrDefault( + instance()->projectPart(filePath), [](const ProjectPart::ConstPtr &pp) { + return pp->belongsToProject(ProjectTree::currentProject()); + }); + if (!projectPart) { + showFallbackWarning(Tr::tr("Could not determine compiler command line")); + useBuiltinPreprocessor(); + return; + } + + CompilerOptionsBuilder optionsBuilder(*projectPart); + optionsBuilder.setNativeMode(); + optionsBuilder.setClStyle(isMsvc); + optionsBuilder.build(classifier.kind, UsePrecompiledHeaders::No); + QStringList compilerArgs = optionsBuilder.options(); + if (isGcc) + compilerArgs.append({"-E", "-o", outFilePath.toUserOutput()}); + else + compilerArgs.append("/E"); + compilerArgs.append(filePath.toUserOutput()); + const CommandLine compilerCommandLine(tc->compilerCommand(), compilerArgs); + const auto compiler = new QtcProcess(instance()); + compiler->setCommand(compilerCommandLine); + compiler->setEnvironment(project->activeTarget()->activeBuildConfiguration()->environment()); + connect(compiler, &QtcProcess::done, instance(), [compiler, outFilePath, inNextSplit, + useBuiltinPreprocessor, isMsvc] { + compiler->deleteLater(); + if (compiler->result() != ProcessResult::FinishedWithSuccess) { + showFallbackWarning("Compiler failed to run"); + useBuiltinPreprocessor(); + return; + } + if (isMsvc) + saveAndOpen(outFilePath, compiler->readAllStandardOutput(), inNextSplit); + else + openEditor(outFilePath, inNextSplit, Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); + }); + compiler->start(); +} + int argumentPositionOf(const AST *last, const CallAST *callAst) { if (!callAst || !callAst->expression_list) |
