forked from qt-creator/qt-creator
ClangFormat: Support remote filesystems
Change-Id: Ic5c06a826154e1bee92e3c283ab508177e86c428 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Artem Sokolovskii <artem.sokolovskii@qt.io>
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include "clangformatconstants.h"
|
#include "clangformatconstants.h"
|
||||||
#include "clangformatsettings.h"
|
#include "clangformatsettings.h"
|
||||||
#include "clangformatutils.h"
|
#include "clangformatutils.h"
|
||||||
|
#include "llvmfilesystem.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <projectexplorer/editorconfiguration.h>
|
#include <projectexplorer/editorconfiguration.h>
|
||||||
@@ -25,6 +26,8 @@
|
|||||||
|
|
||||||
namespace ClangFormat {
|
namespace ClangFormat {
|
||||||
|
|
||||||
|
Internal::LlvmFileSystemAdapter llvmFileSystemAdapter;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
||||||
ReplacementsToKeep replacementsToKeep)
|
ReplacementsToKeep replacementsToKeep)
|
||||||
@@ -735,8 +738,8 @@ void ClangFormatBaseIndenter::autoIndent(const QTextCursor &cursor,
|
|||||||
|
|
||||||
clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
|
clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
|
||||||
{
|
{
|
||||||
llvm::Expected<clang::format::FormatStyle> styleFromProjectFolder
|
llvm::Expected<clang::format::FormatStyle> styleFromProjectFolder = clang::format::getStyle(
|
||||||
= clang::format::getStyle("file", m_fileName.path().toStdString(), "none");
|
"file", m_fileName.toFSPathString().toStdString(), "none", "", &llvmFileSystemAdapter);
|
||||||
|
|
||||||
const ProjectExplorer::Project *projectForFile
|
const ProjectExplorer::Project *projectForFile
|
||||||
= ProjectExplorer::SessionManager::projectForFile(m_fileName);
|
= ProjectExplorer::SessionManager::projectForFile(m_fileName);
|
||||||
@@ -748,7 +751,7 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
|
|||||||
? projectForFile->editorConfiguration()->codeStyle("Cpp")->currentPreferences()
|
? projectForFile->editorConfiguration()->codeStyle("Cpp")->currentPreferences()
|
||||||
: TextEditor::TextEditorSettings::codeStyle("Cpp")->currentPreferences();
|
: TextEditor::TextEditorSettings::codeStyle("Cpp")->currentPreferences();
|
||||||
|
|
||||||
if (overrideStyleFile || !styleFromProjectFolder
|
if (!styleFromProjectFolder || overrideStyleFile
|
||||||
|| *styleFromProjectFolder == clang::format::getNoStyle()) {
|
|| *styleFromProjectFolder == clang::format::getNoStyle()) {
|
||||||
Utils::FilePath filePath = filePathToCurrentSettings(preferences);
|
Utils::FilePath filePath = filePathToCurrentSettings(preferences);
|
||||||
|
|
||||||
|
171
src/plugins/clangformat/llvmfilesystem.h
Normal file
171
src/plugins/clangformat/llvmfilesystem.h
Normal file
@@ -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 <utils/filepath.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <llvm/Support/VirtualFileSystem.h>
|
||||||
|
|
||||||
|
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> status() override
|
||||||
|
{
|
||||||
|
Q_UNIMPLEMENTED();
|
||||||
|
return std::make_error_code(std::errc::not_supported);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the name of the file
|
||||||
|
ErrorOr<std::string> getName() override
|
||||||
|
{
|
||||||
|
Q_UNIMPLEMENTED();
|
||||||
|
return std::make_error_code(std::errc::not_supported);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the contents of the file as a \p MemoryBuffer.
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> 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<QByteArray> 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> 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<std::chrono::system_clock> 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<std::unique_ptr<File>> openFileForRead(const Twine &Path) override
|
||||||
|
{
|
||||||
|
return std::make_unique<LlvmFileAdapter>(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<std::string> 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<char> &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<char> &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
|
Reference in New Issue
Block a user