// Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangformatutils.h" #include "clangformatconstants.h" #include #include #include #include #include #include #include #include #include #include using namespace clang; using namespace format; using namespace llvm; using namespace CppEditor; using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; namespace ClangFormat { clang::format::FormatStyle qtcStyle() { clang::format::FormatStyle style = getLLVMStyle(); style.Language = FormatStyle::LK_Cpp; style.AccessModifierOffset = -4; style.AlignAfterOpenBracket = FormatStyle::BAS_Align; #if LLVM_VERSION_MAJOR >= 15 style.AlignConsecutiveAssignments = {false, false, false, false, false}; style.AlignConsecutiveDeclarations = {false, false, false, false, false}; #elif LLVM_VERSION_MAJOR >= 12 style.AlignConsecutiveAssignments = FormatStyle::ACS_None; style.AlignConsecutiveDeclarations = FormatStyle::ACS_None; #else style.AlignConsecutiveAssignments = false; style.AlignConsecutiveDeclarations = false; #endif style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; #if LLVM_VERSION_MAJOR >= 11 style.AlignOperands = FormatStyle::OAS_Align; #else style.AlignOperands = true; #endif #if LLVM_VERSION_MAJOR >= 16 style.AlignTrailingComments = {FormatStyle::TCAS_Always, 0}; #else style.AlignTrailingComments = true; #endif style.AllowAllParametersOfDeclarationOnNextLine = true; #if LLVM_VERSION_MAJOR >= 10 style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; #else style.AllowShortBlocksOnASingleLine = false; #endif style.AllowShortCaseLabelsOnASingleLine = false; style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; #if LLVM_VERSION_MAJOR >= 9 style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; #else style.AllowShortIfStatementsOnASingleLine = false; #endif style.AllowShortLoopsOnASingleLine = false; style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakBeforeMultilineStrings = false; style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; style.BinPackArguments = false; style.BinPackParameters = false; style.BraceWrapping.AfterClass = true; #if LLVM_VERSION_MAJOR >= 10 style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Never; #else style.BraceWrapping.AfterControlStatement = false; #endif style.BraceWrapping.AfterEnum = false; style.BraceWrapping.AfterFunction = true; style.BraceWrapping.AfterNamespace = false; style.BraceWrapping.AfterObjCDeclaration = false; style.BraceWrapping.AfterStruct = true; style.BraceWrapping.AfterUnion = false; style.BraceWrapping.BeforeCatch = false; style.BraceWrapping.BeforeElse = false; style.BraceWrapping.IndentBraces = false; style.BraceWrapping.SplitEmptyFunction = false; style.BraceWrapping.SplitEmptyRecord = false; style.BraceWrapping.SplitEmptyNamespace = false; style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; style.BreakBeforeBraces = FormatStyle::BS_Custom; style.BreakBeforeTernaryOperators = true; style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; style.BreakAfterJavaFieldAnnotations = false; style.BreakStringLiterals = true; style.ColumnLimit = 100; style.CommentPragmas = "^ IWYU pragma:"; style.CompactNamespaces = false; #if LLVM_VERSION_MAJOR >= 15 style.PackConstructorInitializers = FormatStyle::PCIS_BinPack; #else style.ConstructorInitializerAllOnOneLineOrOnePerLine = false; #endif style.ConstructorInitializerIndentWidth = 4; style.ContinuationIndentWidth = 4; style.Cpp11BracedListStyle = true; style.DerivePointerAlignment = false; style.DisableFormat = false; style.ExperimentalAutoDetectBinPacking = false; style.FixNamespaceComments = true; style.ForEachMacros = {"forever", "foreach", "Q_FOREACH", "BOOST_FOREACH"}; #if LLVM_VERSION_MAJOR >= 12 style.IncludeStyle.IncludeCategories = {{"^= 13 style.SortIncludes = FormatStyle::SI_CaseSensitive; #else style.SortIncludes = true; #endif style.SortUsingDeclarations = true; style.SpaceAfterCStyleCast = true; style.SpaceAfterTemplateKeyword = false; style.SpaceBeforeAssignmentOperators = true; style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; style.SpaceInEmptyParentheses = false; style.SpacesBeforeTrailingComments = 1; #if LLVM_VERSION_MAJOR >= 13 style.SpacesInAngles = FormatStyle::SIAS_Never; #else style.SpacesInAngles = false; #endif style.SpacesInContainerLiterals = false; style.SpacesInCStyleCastParentheses = false; style.SpacesInParentheses = false; style.SpacesInSquareBrackets = false; style.StatementMacros.emplace_back("Q_OBJECT"); style.StatementMacros.emplace_back("QT_BEGIN_NAMESPACE"); style.StatementMacros.emplace_back("QT_END_NAMESPACE"); style.Standard = FormatStyle::LS_Cpp11; style.TabWidth = 4; style.UseTab = FormatStyle::UT_Never; return style; } static bool useGlobalOverriddenSettings() { return ClangFormatSettings::instance().overrideDefaultFile(); } QString currentProjectUniqueId() { return projectUniqueId(SessionManager::startupProject()); } QString projectUniqueId(ProjectExplorer::Project *project) { if (!project) return QString(); return QString::fromUtf8(QCryptographicHash::hash(project->projectFilePath().toString().toUtf8(), QCryptographicHash::Md5) .toHex(0)); } static bool useProjectOverriddenSettings() { const Project *project = SessionManager::startupProject(); return getProjectOverriddenSettings(project); } bool getProjectUseGlobalSettings(const ProjectExplorer::Project *project) { const QVariant projectUseGlobalSettings = project ? project->namedSettings( Constants::USE_GLOBAL_SETTINGS) : QVariant(); return projectUseGlobalSettings.isValid() ? projectUseGlobalSettings.toBool() : true; } bool getProjectOverriddenSettings(const ProjectExplorer::Project *project) { const QVariant projectOverride = project ? project->namedSettings(Constants::OVERRIDE_FILE_ID) : QVariant(); return projectOverride.isValid() ? projectOverride.toBool() : ClangFormatSettings::instance().overrideDefaultFile(); } bool getCurrentOverriddenSettings(const Utils::FilePath &filePath) { const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( filePath); return getProjectUseGlobalSettings(project) ? ClangFormatSettings::instance().overrideDefaultFile() : getProjectOverriddenSettings(project); } ClangFormatSettings::Mode getProjectIndentationOrFormattingSettings( const ProjectExplorer::Project *project) { const QVariant projectIndentationOrFormatting = project ? project->namedSettings(Constants::MODE_ID) : QVariant(); return projectIndentationOrFormatting.isValid() ? static_cast(projectIndentationOrFormatting.toInt()) : ClangFormatSettings::instance().mode(); } ClangFormatSettings::Mode getCurrentIndentationOrFormattingSettings(const Utils::FilePath &filePath) { const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( filePath); return getProjectUseGlobalSettings(project) ? ClangFormatSettings::instance().mode() : getProjectIndentationOrFormattingSettings(project); } static Utils::FilePath globalPath() { return Core::ICore::userResourcePath(); } static Utils::FilePath projectPath() { const Project *project = SessionManager::startupProject(); if (project) return globalPath().pathAppended("clang-format/" + currentProjectUniqueId()); return Utils::FilePath(); } static QString findConfig(Utils::FilePath fileName) { QDir parentDir(fileName.parentDir().toString()); while (!parentDir.exists(Constants::SETTINGS_FILE_NAME) && !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { if (!parentDir.cdUp()) return QString(); } if (parentDir.exists(Constants::SETTINGS_FILE_NAME)) return parentDir.filePath(Constants::SETTINGS_FILE_NAME); return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); } static QString configForFile(Utils::FilePath fileName, bool checkForSettings) { QDir overrideDir; if (!checkForSettings || useProjectOverriddenSettings()) { overrideDir.setPath(projectPath().toString()); if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); } if (!checkForSettings || useGlobalOverriddenSettings()) { overrideDir.setPath(globalPath().toString()); if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); } return findConfig(fileName); } QString configForFile(Utils::FilePath fileName) { return configForFile(fileName, true); } void addQtcStatementMacros(clang::format::FormatStyle &style) { static const std::vector macros = {"Q_OBJECT", "QT_BEGIN_NAMESPACE", "QT_END_NAMESPACE"}; for (const std::string ¯o : macros) { if (std::find(style.StatementMacros.begin(), style.StatementMacros.end(), macro) == style.StatementMacros.end()) style.StatementMacros.emplace_back(macro); } } Utils::FilePath filePathToCurrentSettings(const TextEditor::ICodeStylePreferences *codeStyle) { return Core::ICore::userResourcePath() / "clang-format/" / Utils::FileUtils::fileSystemFriendlyName(codeStyle->displayName()) / QLatin1String(Constants::SETTINGS_FILE_NAME); } } // namespace ClangFormat