diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 63b84036bd3..8db56aa4d42 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -5,6 +5,7 @@ #include "clangformatconstants.h" #include "clangformatsettings.h" #include "clangformatutils.h" +#include "llvmfilesystem.h" #include #include @@ -25,6 +26,8 @@ namespace ClangFormat { +Internal::LlvmFileSystemAdapter llvmFileSystemAdapter; + namespace { void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, ReplacementsToKeep replacementsToKeep) @@ -735,8 +738,8 @@ void ClangFormatBaseIndenter::autoIndent(const QTextCursor &cursor, clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const { - llvm::Expected styleFromProjectFolder - = clang::format::getStyle("file", m_fileName.path().toStdString(), "none"); + llvm::Expected styleFromProjectFolder = clang::format::getStyle( + "file", m_fileName.toFSPathString().toStdString(), "none", "", &llvmFileSystemAdapter); const ProjectExplorer::Project *projectForFile = ProjectExplorer::SessionManager::projectForFile(m_fileName); @@ -748,7 +751,7 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const ? projectForFile->editorConfiguration()->codeStyle("Cpp")->currentPreferences() : TextEditor::TextEditorSettings::codeStyle("Cpp")->currentPreferences(); - if (overrideStyleFile || !styleFromProjectFolder + if (!styleFromProjectFolder || overrideStyleFile || *styleFromProjectFolder == clang::format::getNoStyle()) { Utils::FilePath filePath = filePathToCurrentSettings(preferences); diff --git a/src/plugins/clangformat/llvmfilesystem.h b/src/plugins/clangformat/llvmfilesystem.h new file mode 100644 index 00000000000..cb4fa508602 --- /dev/null +++ b/src/plugins/clangformat/llvmfilesystem.h @@ -0,0 +1,171 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include + +namespace ClangFormat::Internal { + +using namespace llvm; +using namespace llvm::vfs; +using namespace llvm::sys::fs; +using namespace Utils; + +class LlvmFileAdapter : public File +{ +public: + LlvmFileAdapter(const Twine &Path) + : m_path(FilePath::fromString(QString::fromStdString(Path.str()))) + {} + /// Destroy the file after closing it (if open). + /// Sub-classes should generally call close() inside their destructors. We + /// cannot do that from the base class, since close is virtual. + ~LlvmFileAdapter() { close(); } + + /// Get the status of the file. + ErrorOr status() override + { + Q_UNIMPLEMENTED(); + return std::make_error_code(std::errc::not_supported); + } + + /// Get the name of the file + ErrorOr getName() override + { + Q_UNIMPLEMENTED(); + return std::make_error_code(std::errc::not_supported); + } + + /// Get the contents of the file as a \p MemoryBuffer. + ErrorOr> getBuffer(const Twine &Name, + int64_t FileSize = -1, + bool RequiresNullTerminator = true, + bool IsVolatile = false) override + { + Q_UNUSED(RequiresNullTerminator); + Q_UNUSED(IsVolatile); + + const FilePath path = FilePath::fromString(QString::fromStdString(Name.str())); + const std::optional contents = path.fileContents(FileSize, 0); + QTC_ASSERT(contents, return std::error_code()); + + return MemoryBuffer::getMemBufferCopy(contents->data(), Name); + } + + /// Closes the file. + std::error_code close() override { return {}; } + +protected: + // Set the file's underlying path. + void setPath(const Twine &Path) override + { + m_path = FilePath::fromString(QString::fromStdString(Path.str())); + } + + FilePath m_path; +}; + +class LlvmFileSystemAdapter : public FileSystem +{ +public: + LlvmFileSystemAdapter() + : m_workingDirectory(FilePath::currentWorkingPath()) + {} + + ErrorOr status(const Twine &Path) override + { + const Utils::FilePath path = FilePath::fromString(QString::fromStdString(Path.str())); + + QFileInfo fInfo(QString::fromStdString(Path.str())); + if (!fInfo.exists()) + return std::error_code(); + + const std::chrono::seconds modInSeconds = std::chrono::seconds( + fInfo.lastModified().toSecsSinceEpoch()); + const std::chrono::time_point modTime(modInSeconds); + file_type type = file_type::status_error; + if (fInfo.isDir()) + type = file_type::directory_file; + else if (fInfo.isFile()) + type = file_type::regular_file; + else + QTC_ASSERT(false, return std::error_code()); + + Status result(Path, {0, 0}, modTime, 0, 0, fInfo.size(), type, perms::all_perms); + return result; + }; + + virtual ErrorOr> openFileForRead(const Twine &Path) override + { + return std::make_unique(Path); + } + + /// Get a directory_iterator for \p Dir. + /// \note The 'end' iterator is directory_iterator(). + vfs::directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override + { + Q_UNIMPLEMENTED(); + return {}; + } + + /// Set the working directory. This will affect all following operations on + /// this file system and may propagate down for nested file systems. + std::error_code setCurrentWorkingDirectory(const Twine &Path) override + { + Q_UNUSED(Path); + Q_UNIMPLEMENTED(); + return std::make_error_code(std::errc::not_supported); + } + + /// Get the working directory of this file system. + ErrorOr getCurrentWorkingDirectory() const override + { + Q_UNIMPLEMENTED(); + return std::make_error_code(std::errc::not_supported); + } + + /// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve + /// symlinks. For real file system, this uses `llvm::sys::fs::real_path`. + /// This returns errc::operation_not_permitted if not implemented by subclass. + std::error_code getRealPath(const Twine &Path, SmallVectorImpl &Output) const override + { + Q_UNUSED(Path); + Q_UNUSED(Output); + + Q_UNIMPLEMENTED(); + return std::make_error_code(std::errc::not_supported); + } + + /// Is the file mounted on a local filesystem? + std::error_code isLocal(const Twine &Path, bool &Result) override + { + const FilePath filePath = FilePath::fromString(QString::fromStdString(Path.str())); + Result = !filePath.needsDevice(); + return {}; + } + + std::error_code makeAbsolute(SmallVectorImpl &Path) const override + { + if (Path.empty()) { + const std::string asString = m_workingDirectory.toFSPathString().toStdString(); + Path.assign(asString.begin(), asString.end()); + return {}; + } + const FilePath filePath = FilePath::fromString(QString::fromStdString(Path.data())); + if (filePath.isRelativePath()) { + const std::string asString + = m_workingDirectory.resolvePath(filePath).toFSPathString().toStdString(); + Path.assign(asString.begin(), asString.end()); + } + return {}; + } + +private: + FilePath m_workingDirectory; +}; + +} // namespace ClangFormat::Internal