| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | /****************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Copyright (C) 2018 The Qt Company Ltd. | 
					
						
							|  |  |  | ** Contact: https://www.qt.io/licensing/
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** 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 The Qt Company. For licensing terms | 
					
						
							|  |  |  | ** and conditions see https://www.qt.io/terms-conditions. For further
 | 
					
						
							|  |  |  | ** information use the contact form at https://www.qt.io/contact-us.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** GNU General Public License Usage | 
					
						
							|  |  |  | ** Alternatively, this file may be used under the terms of the GNU | 
					
						
							|  |  |  | ** General Public License version 3 as published by the Free Software | 
					
						
							|  |  |  | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
					
						
							|  |  |  | ** included in the packaging of this file. Please review the following | 
					
						
							|  |  |  | ** information to ensure the GNU General Public License requirements will | 
					
						
							|  |  |  | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ****************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "compilationdatabaseproject.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "compilationdatabaseconstants.h"
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | #include "compilationdatabaseutils.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <coreplugin/icontext.h>
 | 
					
						
							|  |  |  | #include <cpptools/projectinfo.h>
 | 
					
						
							| 
									
										
										
										
											2019-01-08 12:33:18 +01:00
										 |  |  | #include <cpptools/cppkitinfo.h>
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | #include <cpptools/cppprojectupdater.h>
 | 
					
						
							|  |  |  | #include <projectexplorer/gcctoolchain.h>
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | #include <projectexplorer/headerpath.h>
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | #include <projectexplorer/kitinformation.h>
 | 
					
						
							|  |  |  | #include <projectexplorer/kitmanager.h>
 | 
					
						
							|  |  |  | #include <projectexplorer/projectexplorerconstants.h>
 | 
					
						
							|  |  |  | #include <projectexplorer/projectnodes.h>
 | 
					
						
							| 
									
										
										
										
											2018-11-01 15:10:52 +01:00
										 |  |  | #include <projectexplorer/target.h>
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | #include <projectexplorer/toolchainconfigwidget.h>
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | #include <projectexplorer/toolchainmanager.h>
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | #include <texteditor/textdocument.h>
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <utils/algorithm.h>
 | 
					
						
							|  |  |  | #include <utils/qtcassert.h>
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | #include <utils/runextensions.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QJsonArray>
 | 
					
						
							|  |  |  | #include <QJsonDocument>
 | 
					
						
							|  |  |  | #include <QJsonObject>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  | #include <Windows.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace ProjectExplorer; | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace CompilationDatabaseProjectManager { | 
					
						
							|  |  |  | namespace Internal { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | namespace { | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | QStringList jsonObjectFlags(const QJsonObject &object) | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     QStringList flags; | 
					
						
							|  |  |  |     const QJsonArray arguments = object["arguments"].toArray(); | 
					
						
							|  |  |  |     if (arguments.isEmpty()) { | 
					
						
							|  |  |  |         flags = splitCommandLine(object["command"].toString()); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |         flags.reserve(arguments.size()); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |         for (const QJsonValue &arg : arguments) | 
					
						
							|  |  |  |             flags.append(arg.toString()); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return flags; | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | bool isGccCompiler(const QString &compilerName) | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     return compilerName.contains("gcc") || compilerName.contains("g++"); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | Core::Id getCompilerId(QString compilerName) | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     if (Utils::HostOsInfo::isWindowsHost()) { | 
					
						
							|  |  |  |         if (compilerName.endsWith(".exe")) | 
					
						
							|  |  |  |             compilerName.chop(4); | 
					
						
							|  |  |  |         if (isGccCompiler(compilerName)) | 
					
						
							|  |  |  |             return ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Default is clang-cl
 | 
					
						
							|  |  |  |         return ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (isGccCompiler(compilerName)) | 
					
						
							|  |  |  |         return ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID; | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     // Default is clang
 | 
					
						
							|  |  |  |     return ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | ToolChain *toolchainFromCompilerId(const Core::Id &compilerId, const Core::Id &language) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return ToolChainManager::toolChain([&compilerId, &language](const ToolChain *tc) { | 
					
						
							|  |  |  |         if (!tc->isValid() || tc->language() != language) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         return tc->typeId() == compilerId; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | QString compilerPath(QString pathFlag) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (pathFlag.isEmpty()) | 
					
						
							|  |  |  |         return pathFlag; | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  |     // Handle short DOS style file names (cmake can generate them).
 | 
					
						
							|  |  |  |     const DWORD pathLength = GetLongPathNameW((LPCWSTR)pathFlag.utf16(), 0, 0); | 
					
						
							|  |  |  |     wchar_t* buffer = new wchar_t[pathLength]; | 
					
						
							|  |  |  |     GetLongPathNameW((LPCWSTR)pathFlag.utf16(), buffer, pathLength); | 
					
						
							|  |  |  |     pathFlag = QString::fromUtf16((ushort *)buffer, pathLength - 1); | 
					
						
							|  |  |  |     delete[] buffer; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     return QDir::fromNativeSeparators(pathFlag); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | ToolChain *toolchainFromFlags(const Kit *kit, const QStringList &flags, const Core::Id &language) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (flags.empty()) | 
					
						
							| 
									
										
										
										
											2019-02-06 12:50:51 +01:00
										 |  |  |         return ToolChainKitAspect::toolChain(kit, language); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     // Try exact compiler match.
 | 
					
						
							|  |  |  |     const Utils::FileName compiler = Utils::FileName::fromString(compilerPath(flags.front())); | 
					
						
							|  |  |  |     ToolChain *toolchain = ToolChainManager::toolChain([&compiler, &language](const ToolChain *tc) { | 
					
						
							|  |  |  |         return tc->isValid() && tc->language() == language && tc->compilerCommand() == compiler; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     if (toolchain) | 
					
						
							|  |  |  |         return toolchain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Core::Id compilerId = getCompilerId(compiler.fileName()); | 
					
						
							|  |  |  |     if ((toolchain = toolchainFromCompilerId(compilerId, language))) | 
					
						
							|  |  |  |         return toolchain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (compilerId != ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID && | 
					
						
							|  |  |  |             compilerId != ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) { | 
					
						
							|  |  |  |         compilerId = Utils::HostOsInfo::isWindowsHost() | 
					
						
							|  |  |  |                 ? ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID | 
					
						
							|  |  |  |                 : ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID; | 
					
						
							|  |  |  |         if ((toolchain = toolchainFromCompilerId(compilerId, language))) | 
					
						
							|  |  |  |             return toolchain; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-06 12:50:51 +01:00
										 |  |  |     toolchain = ToolChainKitAspect::toolChain(kit, language); | 
					
						
							| 
									
										
										
										
											2018-11-14 12:11:33 +01:00
										 |  |  |     qWarning() << "No matching toolchain found, use the default."; | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     return toolchain; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | Utils::FileName jsonObjectFilename(const QJsonObject &object) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  |     const QString workingDir = QDir::fromNativeSeparators(object["directory"].toString()); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     Utils::FileName fileName = Utils::FileName::fromString( | 
					
						
							|  |  |  |                 QDir::fromNativeSeparators(object["file"].toString())); | 
					
						
							|  |  |  |     if (fileName.toFileInfo().isRelative()) { | 
					
						
							|  |  |  |         fileName = Utils::FileUtils::canonicalPath( | 
					
						
							|  |  |  |                     Utils::FileName::fromString(workingDir + "/" + fileName.toString())); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     return fileName; | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | void addDriverModeFlagIfNeeded(const ToolChain *toolchain, QStringList &flags) | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     if (toolchain->typeId() == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID | 
					
						
							|  |  |  |             && !flags.empty() && !flags.front().endsWith("cl") | 
					
						
							|  |  |  |             && !flags.front().endsWith("cl.exe")) { | 
					
						
							| 
									
										
										
										
											2018-11-01 09:22:52 +01:00
										 |  |  |         flags.prepend("--driver-mode=g++"); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | CppTools::RawProjectPart makeRawProjectPart(const Utils::FileName &projectFile, | 
					
						
							|  |  |  |                                             Kit *kit, | 
					
						
							|  |  |  |                                             ToolChain *&cToolchain, | 
					
						
							|  |  |  |                                             ToolChain *&cxxToolchain, | 
					
						
							|  |  |  |                                             const QString &workingDir, | 
					
						
							|  |  |  |                                             const Utils::FileName &fileName, | 
					
						
							|  |  |  |                                             QStringList flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HeaderPaths headerPaths; | 
					
						
							|  |  |  |     Macros macros; | 
					
						
							|  |  |  |     CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::Unclassified; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QStringList originalFlags = flags; | 
					
						
							|  |  |  |     filteredFlags(fileName.fileName(), | 
					
						
							|  |  |  |                   workingDir, | 
					
						
							|  |  |  |                   flags, | 
					
						
							|  |  |  |                   headerPaths, | 
					
						
							|  |  |  |                   macros, | 
					
						
							|  |  |  |                   fileKind); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     CppTools::RawProjectPart rpp; | 
					
						
							|  |  |  |     rpp.setProjectFileLocation(projectFile.toString()); | 
					
						
							|  |  |  |     rpp.setBuildSystemTarget(workingDir); | 
					
						
							|  |  |  |     rpp.setDisplayName(fileName.fileName()); | 
					
						
							|  |  |  |     rpp.setFiles({fileName.toString()}); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     rpp.setHeaderPaths(headerPaths); | 
					
						
							|  |  |  |     rpp.setMacros(macros); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fileKind == CppTools::ProjectFile::Kind::CHeader | 
					
						
							|  |  |  |             || fileKind == CppTools::ProjectFile::Kind::CSource) { | 
					
						
							|  |  |  |         if (!cToolchain) { | 
					
						
							|  |  |  |             cToolchain = toolchainFromFlags(kit, originalFlags, | 
					
						
							|  |  |  |                                             ProjectExplorer::Constants::C_LANGUAGE_ID); | 
					
						
							| 
									
										
										
										
											2019-02-06 12:50:51 +01:00
										 |  |  |             ToolChainKitAspect::setToolChain(kit, cToolchain); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         addDriverModeFlagIfNeeded(cToolchain, flags); | 
					
						
							|  |  |  |         rpp.setFlagsForC({cToolchain, flags}); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (!cxxToolchain) { | 
					
						
							|  |  |  |             cxxToolchain = toolchainFromFlags(kit, originalFlags, | 
					
						
							|  |  |  |                                               ProjectExplorer::Constants::CXX_LANGUAGE_ID); | 
					
						
							| 
									
										
										
										
											2019-02-06 12:50:51 +01:00
										 |  |  |             ToolChainKitAspect::setToolChain(kit, cxxToolchain); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         addDriverModeFlagIfNeeded(cxxToolchain, flags); | 
					
						
							|  |  |  |         rpp.setFlagsForCxx({cxxToolchain, flags}); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return rpp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | QStringList relativeDirsList(Utils::FileName currentPath, const Utils::FileName &rootPath) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QStringList dirsList; | 
					
						
							|  |  |  |     while (!currentPath.isEmpty() && currentPath != rootPath) { | 
					
						
							|  |  |  |         QString dirName = currentPath.fileName(); | 
					
						
							|  |  |  |         if (dirName.isEmpty()) | 
					
						
							|  |  |  |             dirName = currentPath.toString(); | 
					
						
							|  |  |  |         dirsList.prepend(dirName); | 
					
						
							|  |  |  |         currentPath = currentPath.parentDir(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return dirsList; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FolderNode *addChildFolderNode(FolderNode *parent, const QString &childName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Utils::FileName parentPath = parent->filePath(); | 
					
						
							| 
									
										
										
										
											2019-02-25 18:32:12 +01:00
										 |  |  |     auto node = std::make_unique<FolderNode>(parentPath.appendPath(childName)); | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  |     FolderNode *childNode = node.get(); | 
					
						
							| 
									
										
										
										
											2019-02-25 18:08:36 +01:00
										 |  |  |     childNode->setDisplayName(childName); | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  |     parent->addNode(std::move(node)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return childNode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FolderNode *addOrGetChildFolderNode(FolderNode *parent, const QString &childName) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-12-14 12:56:57 +01:00
										 |  |  |     for (FolderNode *folder : parent->folderNodes()) { | 
					
						
							|  |  |  |         if (folder->filePath().fileName() == childName) { | 
					
						
							|  |  |  |             return folder; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return addChildFolderNode(parent, childName); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Return the node for folderPath.
 | 
					
						
							|  |  |  | FolderNode *createFoldersIfNeeded(FolderNode *root, const Utils::FileName &folderPath) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QStringList dirsList = relativeDirsList(folderPath, root->filePath()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FolderNode *parent = root; | 
					
						
							|  |  |  |     for (const QString &dir : dirsList) | 
					
						
							|  |  |  |         parent = addOrGetChildFolderNode(parent, dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return parent; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  | FileType fileTypeForName(const QString &fileName) | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::classify(fileName); | 
					
						
							|  |  |  |     if (CppTools::ProjectFile::isHeader(fileKind)) | 
					
						
							|  |  |  |         return FileType::Header; | 
					
						
							|  |  |  |     return FileType::Source; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  | void createTree(FolderNode *root, | 
					
						
							|  |  |  |                 const Utils::FileName &rootPath, | 
					
						
							|  |  |  |                 const CppTools::RawProjectParts &rpps) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     root->setAbsoluteFilePathAndLine(rootPath, -1); | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     for (const CppTools::RawProjectPart &rpp : rpps) { | 
					
						
							|  |  |  |         for (const QString &filePath : rpp.files) { | 
					
						
							|  |  |  |             Utils::FileName fileName = Utils::FileName::fromString(filePath); | 
					
						
							|  |  |  |             FolderNode *parentNode = createFoldersIfNeeded(root, fileName.parentDir()); | 
					
						
							|  |  |  |             if (!parentNode->fileNode(fileName)) { | 
					
						
							|  |  |  |                 parentNode->addNode(std::make_unique<FileNode>(fileName, | 
					
						
							| 
									
										
										
										
											2019-02-25 12:08:58 +01:00
										 |  |  |                                                                fileTypeForName(fileName.fileName()))); | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  | struct Entry | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QStringList flags; | 
					
						
							|  |  |  |     Utils::FileName fileName; | 
					
						
							|  |  |  |     QString workingDir; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::vector<Entry> readJsonObjects(const QString &filePath) | 
					
						
							| 
									
										
										
										
											2018-11-01 13:05:34 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     std::vector<Entry> result; | 
					
						
							| 
									
										
										
										
											2018-11-01 13:05:34 +01:00
										 |  |  |     QFile file(filePath); | 
					
						
							|  |  |  |     if (!file.open(QIODevice::ReadOnly)) | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QByteArray contents = file.readAll(); | 
					
						
							|  |  |  |     int objectStart = contents.indexOf('{'); | 
					
						
							|  |  |  |     int objectEnd = contents.indexOf('}', objectStart + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (objectStart >= 0 && objectEnd >= 0) { | 
					
						
							|  |  |  |         const QJsonDocument document = QJsonDocument::fromJson( | 
					
						
							|  |  |  |                     contents.mid(objectStart, objectEnd - objectStart + 1)); | 
					
						
							|  |  |  |         if (document.isNull()) { | 
					
						
							|  |  |  |             // The end was found incorrectly, search for the next one.
 | 
					
						
							|  |  |  |             objectEnd = contents.indexOf('}', objectEnd + 1); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |         const QJsonObject object = document.object(); | 
					
						
							|  |  |  |         const Utils::FileName fileName = jsonObjectFilename(object); | 
					
						
							|  |  |  |         const QStringList flags | 
					
						
							|  |  |  |                 = filterFromFileName(jsonObjectFlags(object), fileName.toFileInfo().baseName()); | 
					
						
							|  |  |  |         result.push_back({flags, fileName, object["directory"].toString()}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-01 13:05:34 +01:00
										 |  |  |         objectStart = contents.indexOf('{', objectEnd + 1); | 
					
						
							|  |  |  |         objectEnd = contents.indexOf('}', objectStart + 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName &projectFile) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     std::vector<Entry> array = readJsonObjects(projectFilePath().toString()); | 
					
						
							| 
									
										
										
										
											2018-11-01 13:05:34 +01:00
										 |  |  |     if (array.empty()) { | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |         emitParsingFinished(false); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-25 18:35:34 +01:00
										 |  |  |     auto root = std::make_unique<ProjectNode>(projectDirectory()); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-08 12:33:18 +01:00
										 |  |  |     CppTools::KitInfo kitInfo(this); | 
					
						
							|  |  |  |     QTC_ASSERT(kitInfo.isValid(), return); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     CppTools::RawProjectParts rpps; | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  |     Utils::FileName commonPath; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     std::sort(array.begin(), array.end(), [](const Entry &lhs, const Entry &rhs) { | 
					
						
							|  |  |  |         return std::lexicographical_compare(lhs.flags.begin(), lhs.flags.end(), | 
					
						
							|  |  |  |                                             rhs.flags.begin(), rhs.flags.end()); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     const Entry *prevEntry = nullptr; | 
					
						
							|  |  |  |     for (const Entry &entry : array) { | 
					
						
							|  |  |  |         if (prevEntry && prevEntry->flags == entry.flags) { | 
					
						
							|  |  |  |             rpps.back().files.append(entry.fileName.toString()); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         prevEntry = &entry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         commonPath = rpps.empty() | 
					
						
							|  |  |  |                 ? entry.fileName.parentDir() | 
					
						
							|  |  |  |                 : Utils::FileUtils::commonPath(commonPath, entry.fileName); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         CppTools::RawProjectPart rpp = makeRawProjectPart(projectFile, | 
					
						
							|  |  |  |                                                           m_kit.get(), | 
					
						
							| 
									
										
										
										
											2019-01-08 12:33:18 +01:00
										 |  |  |                                                           kitInfo.cToolChain, | 
					
						
							|  |  |  |                                                           kitInfo.cxxToolChain, | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |                                                           entry.workingDir, | 
					
						
							|  |  |  |                                                           entry.fileName, | 
					
						
							|  |  |  |                                                           entry.flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rpps.append(rpp); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 16:07:42 +01:00
										 |  |  |     createTree(root.get(), commonPath, rpps); | 
					
						
							| 
									
										
										
										
											2018-10-30 14:21:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-25 12:08:58 +01:00
										 |  |  |     root->addNode(std::make_unique<FileNode>(projectFile, FileType::Project)); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     setRootProjectNode(std::move(root)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-08 12:33:18 +01:00
										 |  |  |     m_cppCodeModelUpdater->update({this, kitInfo, rpps}); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     emitParsingFinished(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &projectFile) | 
					
						
							|  |  |  |     : Project(Constants::COMPILATIONDATABASEMIMETYPE, projectFile) | 
					
						
							| 
									
										
										
										
											2018-12-11 15:37:59 +01:00
										 |  |  |     , m_cppCodeModelUpdater(std::make_unique<CppTools::CppProjectUpdater>()) | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     setId(Constants::COMPILATIONDATABASEPROJECT_ID); | 
					
						
							|  |  |  |     setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); | 
					
						
							|  |  |  |     setDisplayName(projectDirectory().fileName()); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     setRequiredKitPredicate([](const Kit *) { return false; }); | 
					
						
							|  |  |  |     setPreferredKitPredicate([](const Kit *) { return false; }); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     m_kit.reset(KitManager::defaultKit()->clone()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 11:09:36 +01:00
										 |  |  |     connect(this, &CompilationDatabaseProject::parsingFinished, this, [this]() { | 
					
						
							|  |  |  |         if (!m_hasTarget) { | 
					
						
							|  |  |  |             addTarget(createTarget(m_kit.get())); | 
					
						
							|  |  |  |             m_hasTarget = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-11-02 10:00:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 11:09:36 +01:00
										 |  |  |     reparseProject(projectFile); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 11:09:36 +01:00
										 |  |  |     m_fileSystemWatcher.addFile(projectFile.toString(), Utils::FileSystemWatcher::WatchModifiedDate); | 
					
						
							|  |  |  |     connect(&m_fileSystemWatcher, | 
					
						
							|  |  |  |             &Utils::FileSystemWatcher::fileChanged, | 
					
						
							|  |  |  |             this, | 
					
						
							|  |  |  |             [this](const QString &projectFile) { | 
					
						
							|  |  |  |                 reparseProject(Utils::FileName::fromString(projectFile)); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CompilationDatabaseProject::reparseProject(const Utils::FileName &projectFile) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     emitParsingStarted(); | 
					
						
							|  |  |  |     const QFuture<void> future = ::Utils::runAsync( | 
					
						
							|  |  |  |         [this, projectFile]() { buildTreeAndProjectParts(projectFile); }); | 
					
						
							| 
									
										
										
										
											2018-10-30 10:31:34 +01:00
										 |  |  |     m_parserWatcher.setFuture(future); | 
					
						
							| 
									
										
										
										
											2018-08-13 11:15:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CompilationDatabaseProject::~CompilationDatabaseProject() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_parserWatcher.cancel(); | 
					
						
							|  |  |  |     m_parserWatcher.waitForFinished(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static TextEditor::TextDocument *createCompilationDatabaseDocument() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto doc = new TextEditor::TextDocument; | 
					
						
							|  |  |  |     doc->setId(Constants::COMPILATIONDATABASEPROJECT_ID); | 
					
						
							|  |  |  |     doc->setMimeType(Constants::COMPILATIONDATABASEMIMETYPE); | 
					
						
							|  |  |  |     return doc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CompilationDatabaseEditorFactory::CompilationDatabaseEditorFactory() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     setId(Constants::COMPILATIONDATABASEPROJECT_ID); | 
					
						
							|  |  |  |     setDisplayName("Compilation Database"); | 
					
						
							|  |  |  |     addMimeType(Constants::COMPILATIONDATABASEMIMETYPE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     setEditorCreator([]() { return new TextEditor::BaseTextEditor; }); | 
					
						
							|  |  |  |     setEditorWidgetCreator([]() { return new TextEditor::TextEditorWidget; }); | 
					
						
							|  |  |  |     setDocumentCreator(createCompilationDatabaseDocument); | 
					
						
							|  |  |  |     setUseGenericHighlighter(true); | 
					
						
							|  |  |  |     setCommentDefinition(Utils::CommentDefinition::HashStyle); | 
					
						
							|  |  |  |     setCodeFoldingSupported(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Internal
 | 
					
						
							|  |  |  | } // namespace CompilationDatabaseProjectManager
 |