From 2501100c1f8ba4ae760237c1de3159f33a887121 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 21 Feb 2019 13:45:18 +0100 Subject: [PATCH] ClangFormat: Fix configuration files handling 1. Fallback to the base style from the invalid config file: If the .clang-format file from the earlier clang version is used and can't be parsed by LibFormat try to find a base style and generate the updated config based on that information. 2. Do not create new .clang-format configuration for each project. Rely on the global one until the user explicitly creates the configuration for the project. Fixes: QTCREATORBUG-22004 Change-Id: I75bd89eebc3ebae57c1f1de94da2e78924ae510c Reviewed-by: Marco Bubke --- src/plugins/clangformat/clangformatutils.cpp | 72 ++++++++++++++++---- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 6b151020d68..babe94da24f 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -106,19 +106,44 @@ static Utils::FileName globalPath() return Utils::FileName::fromString(Core::ICore::userResourcePath()); } -static bool configForFileExists(Utils::FileName fileName) +static QString configForFile(Utils::FileName fileName) { + Utils::FileName topProjectPath = projectPath(); + if (topProjectPath.isEmpty()) + return QString(); + QDir projectDir(fileName.parentDir().toString()); while (!projectDir.exists(Constants::SETTINGS_FILE_NAME) && !projectDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { - if (!projectDir.cdUp()) - return false; + if (projectDir.path() == topProjectPath.toString() + || !Utils::FileName::fromString(projectDir.path()).isChildOf(topProjectPath) + || !projectDir.cdUp()) { + return QString(); + } } - return true; + + if (projectDir.exists(Constants::SETTINGS_FILE_NAME)) + return projectDir.filePath(Constants::SETTINGS_FILE_NAME); + return projectDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); } -static clang::format::FormatStyle constructStyle(bool isGlobal) +static clang::format::FormatStyle constructStyle(bool isGlobal, + const QByteArray &baseStyle = QByteArray()) { + if (!baseStyle.isEmpty()) { + // Try to get the style for this base style. + Expected style = getStyle(baseStyle.toStdString(), + "dummy.cpp", + baseStyle.toStdString()); + if (style) + return *style; + + handleAllErrors(style.takeError(), [](const ErrorInfoBase &) { + // do nothing + }); + // Fallthrough to the default style. + } + FormatStyle style = getLLVMStyle(); style.BreakBeforeBraces = FormatStyle::BS_Custom; @@ -151,18 +176,37 @@ void createStyleFileIfNeeded(bool isGlobal) } } +static QByteArray configBaseStyleName(const QString &configFile) +{ + if (configFile.isEmpty()) + return QByteArray(); + + QFile config(configFile); + if (!config.open(QIODevice::ReadOnly)) + return QByteArray(); + + const QByteArray content = config.readAll(); + const char basedOnStyle[] = "BasedOnStyle:"; + int basedOnStyleIndex = content.indexOf(basedOnStyle); + if (basedOnStyleIndex < 0) + return QByteArray(); + + basedOnStyleIndex += sizeof(basedOnStyle) - 1; + const int endOfLineIndex = content.indexOf('\n', basedOnStyleIndex); + return content + .mid(basedOnStyleIndex, endOfLineIndex < 0 ? -1 : endOfLineIndex - basedOnStyleIndex) + .trimmed(); +} + clang::format::FormatStyle styleForFile(Utils::FileName fileName) { bool isGlobal = false; - if (!configForFileExists(fileName)) { - if (fileName.isChildOf(projectPath()) && CppCodeStyleSettings::currentProjectCodeStyle()) { - fileName = projectPath(); - } else { - fileName = globalPath(); - isGlobal = true; - } + QString configFile = configForFile(fileName); + if (configFile.isEmpty()) { + Utils::FileName path = fileName = globalPath(); fileName.appendPath(Constants::SAMPLE_FILE_NAME); - createStyleFileIfNeeded(isGlobal); + createStyleFileIfNeeded(true); + configFile = path.appendPath(Constants::SETTINGS_FILE_NAME).toString(); } Expected style = format::getStyle("file", @@ -175,7 +219,7 @@ clang::format::FormatStyle styleForFile(Utils::FileName fileName) // do nothing }); - return constructStyle(isGlobal); + return constructStyle(isGlobal, configBaseStyleName(configFile)); } clang::format::FormatStyle currentProjectStyle()