njames93 updated this revision to Diff 320309.
njames93 added a comment.
Tests pass on my machine, rebasing on main and trigger a fresh rebuild.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D93800/new/
https://reviews.llvm.org/D93800
Files:
clang-tools-extra/clangd/CMakeLists.txt
clang-tools-extra/clangd/ClangdServer.cpp
clang-tools-extra/clangd/ClangdServer.h
clang-tools-extra/clangd/CodeComplete.cpp
clang-tools-extra/clangd/Compiler.h
clang-tools-extra/clangd/FormatProvider.cpp
clang-tools-extra/clangd/FormatProvider.h
clang-tools-extra/clangd/Hover.cpp
clang-tools-extra/clangd/Hover.h
clang-tools-extra/clangd/ParsedAST.cpp
clang-tools-extra/clangd/SourceCode.cpp
clang-tools-extra/clangd/SourceCode.h
clang-tools-extra/clangd/tool/Check.cpp
clang-tools-extra/clangd/tool/ClangdMain.cpp
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
clang-tools-extra/clangd/unittests/TestTU.cpp
clang-tools-extra/clangd/unittests/TestTU.h
Index: clang-tools-extra/clangd/unittests/TestTU.h
===================================================================
--- clang-tools-extra/clangd/unittests/TestTU.h
+++ clang-tools-extra/clangd/unittests/TestTU.h
@@ -19,6 +19,7 @@
#include "../TidyProvider.h"
#include "Compiler.h"
+#include "FormatProvider.h"
#include "ParsedAST.h"
#include "TestFS.h"
#include "index/Index.h"
@@ -60,6 +61,8 @@
std::vector<std::string> ExtraArgs;
TidyProvider ClangTidyProvider = {};
+
+ mutable FormatProvider ClangFormatProvider = &formatFallbackProvider;
// Index to use when building AST.
const SymbolIndex *ExternalIndex = nullptr;
Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -9,6 +9,7 @@
#include "TestTU.h"
#include "Compiler.h"
#include "Diagnostics.h"
+#include "FormatProvider.h"
#include "TestFS.h"
#include "index/FileIndex.h"
#include "index/MemIndex.h"
@@ -61,6 +62,9 @@
Inputs.Opts = ParseOptions();
if (ClangTidyProvider)
Inputs.ClangTidyProvider = ClangTidyProvider;
+ ClangFormatProvider =
+ getClangFormatProvider(FS, format::DefaultFallbackStyle);
+ Inputs.ClangFormatProvider = ClangFormatProvider;
Inputs.Index = ExternalIndex;
return Inputs;
}
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -11,6 +11,7 @@
#include "ClangdServer.h"
#include "CodeComplete.h"
#include "Compiler.h"
+#include "FormatProvider.h"
#include "Matchers.h"
#include "Protocol.h"
#include "Quality.h"
@@ -154,6 +155,7 @@
MockFS FS;
Annotations Test(Text);
ParseInputs ParseInput{tooling::CompileCommand(), &FS, Test.code().str()};
+ ParseInput.ClangFormatProvider = &formatFallbackProvider;
return codeComplete(FilePath, Test.point(), /*Preamble=*/nullptr, ParseInput,
Opts);
}
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===================================================================
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -9,6 +9,7 @@
#include "ClangdLSPServer.h"
#include "CodeComplete.h"
#include "Features.inc"
+#include "FormatProvider.h"
#include "PathMapping.h"
#include "Protocol.h"
#include "TidyProvider.h"
@@ -860,6 +861,9 @@
ClangTidyOptProvider = combine(std::move(Providers));
Opts.ClangTidyProvider = ClangTidyOptProvider;
}
+ FormatProvider ClangFormatOptProvider =
+ getClangFormatProvider(TFS, FallbackStyle);
+ Opts.ClangFormatProvider = ClangFormatOptProvider;
Opts.AsyncPreambleBuilds = AsyncPreamble;
Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
Opts.TweakFilter = [&](const Tweak &T) {
Index: clang-tools-extra/clangd/tool/Check.cpp
===================================================================
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -76,7 +76,7 @@
// from buildInvocation
ParseInputs Inputs;
std::unique_ptr<CompilerInvocation> Invocation;
- format::FormatStyle Style;
+ std::shared_ptr<const format::FormatStyle> Style;
// from buildAST
std::shared_ptr<const PreambleData> Preamble;
llvm::Optional<ParsedAST> AST;
@@ -135,6 +135,7 @@
return false;
}
}
+ Inputs.ClangFormatProvider = Opts.ClangFormatProvider;
log("Parsing command...");
Invocation =
buildCompilerInvocation(Inputs, CaptureInvocationDiags, &CC1Args);
@@ -148,7 +149,7 @@
// FIXME: Check that resource-dir/built-in-headers exist?
- Style = getFormatStyleForFile(File, Inputs.Contents, TFS);
+ Style = Inputs.ClangFormatProvider(File, Inputs.Contents);
return true;
}
@@ -216,7 +217,7 @@
unsigned Definitions = locateSymbolAt(*AST, Pos, &Index).size();
vlog(" definition: {0}", Definitions);
- auto Hover = getHover(*AST, Pos, Style, &Index);
+ auto Hover = getHover(*AST, Pos, *Style, &Index);
vlog(" hover: {0}", Hover.hasValue());
// FIXME: it'd be nice to include code completion, but it's too slow.
Index: clang-tools-extra/clangd/SourceCode.h
===================================================================
--- clang-tools-extra/clangd/SourceCode.h
+++ clang-tools-extra/clangd/SourceCode.h
@@ -161,15 +161,6 @@
llvm::Optional<std::string> getCanonicalPath(const FileEntry *F,
const SourceManager &SourceMgr);
-/// Choose the clang-format style we should apply to a certain file.
-/// This will usually use FS to look for .clang-format directories.
-/// FIXME: should we be caching the .clang-format file search?
-/// This uses format::DefaultFormatStyle and format::DefaultFallbackStyle,
-/// though the latter may have been overridden in main()!
-format::FormatStyle getFormatStyleForFile(llvm::StringRef File,
- llvm::StringRef Content,
- const ThreadsafeFS &TFS);
-
/// Cleanup and format the given replacements.
llvm::Expected<tooling::Replacements>
cleanupAndFormat(StringRef Code, const tooling::Replacements &Replaces,
Index: clang-tools-extra/clangd/SourceCode.cpp
===================================================================
--- clang-tools-extra/clangd/SourceCode.cpp
+++ clang-tools-extra/clangd/SourceCode.cpp
@@ -570,20 +570,6 @@
return digest(Content);
}
-format::FormatStyle getFormatStyleForFile(llvm::StringRef File,
- llvm::StringRef Content,
- const ThreadsafeFS &TFS) {
- auto Style = format::getStyle(format::DefaultFormatStyle, File,
- format::DefaultFallbackStyle, Content,
- TFS.view(/*CWD=*/llvm::None).get());
- if (!Style) {
- log("getStyle() failed for file {0}: {1}. Fallback is LLVM style.", File,
- Style.takeError());
- return format::getLLVMStyle();
- }
- return *Style;
-}
-
llvm::Expected<tooling::Replacements>
cleanupAndFormat(StringRef Code, const tooling::Replacements &Replaces,
const format::FormatStyle &Style) {
Index: clang-tools-extra/clangd/ParsedAST.cpp
===================================================================
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -359,9 +359,9 @@
llvm::Optional<IncludeFixer> FixIncludes;
auto BuildDir = VFS->getCurrentWorkingDirectory();
if (Inputs.Index && !BuildDir.getError()) {
- auto Style = getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS);
+ auto Style = Inputs.ClangFormatProvider(Filename, Inputs.Contents);
auto Inserter = std::make_shared<IncludeInserter>(
- Filename, Inputs.Contents, Style, BuildDir.get(),
+ Filename, Inputs.Contents, *Style, BuildDir.get(),
&Clang->getPreprocessor().getHeaderSearchInfo());
if (Preamble) {
for (const auto &Inc : Preamble->Includes.MainFileIncludes)
Index: clang-tools-extra/clangd/Hover.h
===================================================================
--- clang-tools-extra/clangd/Hover.h
+++ clang-tools-extra/clangd/Hover.h
@@ -115,7 +115,7 @@
/// Get the hover information when hovering at \p Pos.
llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
- format::FormatStyle Style,
+ const format::FormatStyle &Style,
const SymbolIndex *Index);
} // namespace clangd
Index: clang-tools-extra/clangd/Hover.cpp
===================================================================
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -829,7 +829,7 @@
} // namespace
llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
- format::FormatStyle Style,
+ const format::FormatStyle &Style,
const SymbolIndex *Index) {
PrintingPolicy PP =
getPrintingPolicy(AST.getASTContext().getPrintingPolicy());
Index: clang-tools-extra/clangd/FormatProvider.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/FormatProvider.h
@@ -0,0 +1,36 @@
+//===--- FormatProvider.h -----------------------------------*- C++-*------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FORMATPROVIDER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FORMATPROVIDER_H
+
+#include "support/Path.h"
+#include "support/ThreadsafeFS.h"
+#include "clang/Format/Format.h"
+#include "llvm/ADT/FunctionExtras.h"
+
+namespace clang {
+namespace clangd {
+using FormatProvider =
+ llvm::unique_function<std::shared_ptr<const format::FormatStyle>(
+ PathRef, llvm::StringRef) const>;
+using FormatProviderRef =
+ llvm::function_ref<std::shared_ptr<const format::FormatStyle>(
+ PathRef, llvm::StringRef)>;
+
+/// A Fallback style provider mainly designed for tests, just returns the LLVM
+/// style for the detected langauge.
+std::shared_ptr<const format::FormatStyle>
+formatFallbackProvider(PathRef Filename, llvm::StringRef Contents);
+
+FormatProvider getClangFormatProvider(ThreadsafeFS &TFS,
+ StringRef FallbackStyle);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_FORMATPROVIDER_H
Index: clang-tools-extra/clangd/FormatProvider.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/FormatProvider.cpp
@@ -0,0 +1,217 @@
+//===--- FormatProvider.cpp ---------------------------------*- C++-*------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatProvider.h"
+#include "support/FileCache.h"
+#include "support/Logger.h"
+#include "support/Path.h"
+#include "support/ThreadsafeFS.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include <memory>
+#include <tuple>
+#include <utility>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+// Access to config from a clang format configuration file, caching IO and
+// parsing.
+using LanguageKind = format::FormatStyle::LanguageKind;
+class ClangFormatCache : private FileCache {
+ mutable std::shared_ptr<format::FormatStyle> Value;
+ const LanguageKind Lang;
+
+public:
+ ClangFormatCache(PathRef Path, LanguageKind Lang)
+ : FileCache(Path), Lang(Lang) {}
+
+ std::shared_ptr<const format::FormatStyle>
+ get(const ThreadsafeFS &TFS,
+ std::chrono::steady_clock::time_point FreshTime) const {
+ std::shared_ptr<const format::FormatStyle> Result;
+ read(
+ TFS, FreshTime,
+ [this](llvm::Optional<llvm::StringRef> Data) {
+ // Clear any stale config if one exists.
+ Value.reset();
+ if (!Data || !Data->empty())
+ return;
+ format::FormatStyle Style = format::getLLVMStyle(Lang);
+ if (auto EC = format::parseConfiguration(
+ llvm::MemoryBufferRef(*Data, path()), &Style,
+ /*AllowUnknownOptions=*/true))
+ elog("clang-format style parsing error: {0}", EC.message());
+ else
+ Value = std::make_shared<format::FormatStyle>(std::move(Style));
+ },
+ [&]() { Result = Value; });
+ return Result;
+ }
+};
+
+// Clang-Format checks for ".clang-format" then "_clang-format" in each
+// directory, so this wraps those 2 caches into one.
+class ClangFormatDirectoryCache {
+private:
+ SmallString<256> appendDir(StringRef Dir, StringRef Tail) {
+ SmallString<256> Res(Dir);
+ llvm::sys::path::append(Res, Tail);
+ return Res;
+ }
+ ClangFormatCache Items[2];
+
+public:
+ explicit ClangFormatDirectoryCache(StringRef Dir, LanguageKind Lang)
+ : Items{{appendDir(Dir, ".clang-format"), Lang},
+ {appendDir(Dir, "._clang-format"), Lang}} {}
+
+ std::shared_ptr<const format::FormatStyle>
+ get(const ThreadsafeFS &TFS,
+ std::chrono::steady_clock::time_point FreshTime) const {
+ for (const ClangFormatCache &Item : Items) {
+ if (auto Config = Item.get(TFS, FreshTime))
+ return Config;
+ }
+ return nullptr;
+ }
+};
+
+// Bundles format file caches along with a fallback style, should no format file
+// be found.
+class CacheMapAndFallback {
+public:
+ CacheMapAndFallback(StringRef FallbackStyle, LanguageKind Lang)
+ : Fallback(getFallbackStyle(FallbackStyle, Lang)), Lang(Lang) {}
+
+ ClangFormatDirectoryCache &getAncestorCache(PathRef Ancestor) {
+ return Map.try_emplace(Ancestor, Ancestor, Lang).first->getValue();
+ }
+
+ std::shared_ptr<const format::FormatStyle> getFallbackStyle() const {
+ return Fallback;
+ }
+
+private:
+ static std::shared_ptr<const format::FormatStyle>
+ getFallbackStyle(StringRef FallbackStyle, LanguageKind Lang) {
+ auto Result = std::make_shared<format::FormatStyle>(format::getNoStyle());
+ if (!format::getPredefinedStyle(FallbackStyle, Lang, &*Result)) {
+ StringRef PrettyStyle;
+ switch (Lang) {
+ case LanguageKind::LK_Cpp:
+ PrettyStyle = "C/C++";
+ break;
+ case LanguageKind::LK_ObjC:
+ PrettyStyle = "Objective-C/Objective-C++";
+ break;
+ default:
+ llvm_unreachable("Unsupported language kind");
+ }
+
+ elog("error: Couldn't get fallback style for '{0}', using LLVM Style",
+ PrettyStyle);
+ *Result = format::getLLVMStyle(Lang);
+ }
+ return Result;
+ }
+ llvm::StringMap<ClangFormatDirectoryCache> Map;
+ const std::shared_ptr<const format::FormatStyle> Fallback;
+ const LanguageKind Lang;
+};
+
+class ClangFormatConfigTree {
+ const ThreadsafeFS &FS;
+ std::chrono::steady_clock::duration MaxStaleness;
+ mutable std::mutex Mu;
+
+ CacheMapAndFallback CPPConfig, ObjCConfig;
+
+ CacheMapAndFallback &getMapForStyle(LanguageKind Lang) {
+ switch (Lang) {
+ case LanguageKind::LK_Cpp:
+ return CPPConfig;
+ case LanguageKind::LK_ObjC:
+ return ObjCConfig;
+ default:
+ llvm_unreachable("Unsupported language kind");
+ }
+ }
+
+public:
+ ClangFormatConfigTree(const ThreadsafeFS &FS, StringRef FallbackStyle)
+ : FS(FS), MaxStaleness(std::chrono::seconds(5)),
+ CPPConfig(FallbackStyle, LanguageKind::LK_Cpp),
+ ObjCConfig(FallbackStyle, LanguageKind::LK_Cpp) {}
+
+ std::shared_ptr<const format::FormatStyle> get(PathRef AbsPath,
+ LanguageKind Lang) {
+ auto &MapFallback = getMapForStyle(Lang);
+
+ namespace path = llvm::sys::path;
+ assert(path::is_absolute(AbsPath));
+
+ // Compute absolute paths to all ancestors (substrings of P.Path).
+ // Ensure cache entries for each ancestor exist in the map.
+ llvm::StringRef Parent = path::parent_path(AbsPath);
+ llvm::SmallVector<ClangFormatDirectoryCache *> Caches;
+ {
+ std::lock_guard<std::mutex> Lock(Mu);
+ for (auto I = path::begin(Parent), E = path::end(Parent); I != E; ++I) {
+ assert(I->end() >= Parent.begin() && I->end() <= Parent.end() &&
+ "Canonical path components should be substrings");
+ llvm::StringRef Ancestor(Parent.begin(), I->end() - Parent.begin());
+#ifdef _WIN32
+ // C:\ is an ancestor, but skip its (relative!) parent C:.
+ if (Ancestor.size() == 2 && Ancestor.back() == ':')
+ continue;
+#endif
+ assert(path::is_absolute(Ancestor));
+ Caches.push_back(&MapFallback.getAncestorCache(Ancestor));
+ }
+ }
+ std::chrono::steady_clock::time_point FreshTime =
+ std::chrono::steady_clock::now() - MaxStaleness;
+ for (const ClangFormatDirectoryCache *CachePair : Caches) {
+ if (auto Config = CachePair->get(FS, FreshTime))
+ return Config;
+ }
+ return MapFallback.getFallbackStyle();
+ }
+};
+
+} // namespace
+
+FormatProvider getClangFormatProvider(ThreadsafeFS &TFS,
+ StringRef FallbackStyle) {
+ return [Tree = std::make_unique<ClangFormatConfigTree>(TFS, FallbackStyle)](
+ PathRef Filename, StringRef Contents) {
+ LanguageKind Lang = format::guessLanguage(Filename, Contents);
+ return Tree->get(Filename, Lang);
+ };
+}
+
+std::shared_ptr<const format::FormatStyle>
+formatFallbackProvider(PathRef Filename, llvm::StringRef Contents) {
+ LanguageKind Lang = format::guessLanguage(Filename, Contents);
+ if (Lang == LanguageKind::LK_Cpp) {
+ static const auto Result = std::make_shared<const format::FormatStyle>(
+ format::getLLVMStyle(LanguageKind::LK_Cpp));
+ return Result;
+ }
+ if (Lang == LanguageKind::LK_ObjC) {
+ static const auto Result = std::make_shared<const format::FormatStyle>(
+ format::getLLVMStyle(LanguageKind::LK_ObjC));
+ return Result;
+ }
+ llvm_unreachable("Unsupported language kind");
+}
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/Compiler.h
===================================================================
--- clang-tools-extra/clangd/Compiler.h
+++ clang-tools-extra/clangd/Compiler.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H
+#include "FormatProvider.h"
#include "GlobalCompilationDatabase.h"
#include "TidyProvider.h"
#include "index/Index.h"
@@ -54,6 +55,7 @@
const SymbolIndex *Index = nullptr;
ParseOptions Opts = ParseOptions();
TidyProviderRef ClangTidyProvider = {};
+ FormatProviderRef ClangFormatProvider = {};
};
/// Builds compiler invocation that could be used to build AST or preamble.
Index: clang-tools-extra/clangd/CodeComplete.cpp
===================================================================
--- clang-tools-extra/clangd/CodeComplete.cpp
+++ clang-tools-extra/clangd/CodeComplete.cpp
@@ -24,6 +24,7 @@
#include "Diagnostics.h"
#include "ExpectedTypes.h"
#include "FileDistance.h"
+#include "FormatProvider.h"
#include "FuzzyMatch.h"
#include "Headers.h"
#include "Hover.h"
@@ -1279,13 +1280,16 @@
/// set and contains a cached request.
llvm::Optional<FuzzyFindRequest> SpecReq;
+ FormatProviderRef FormatProvider;
+
public:
// A CodeCompleteFlow object is only useful for calling run() exactly once.
CodeCompleteFlow(PathRef FileName, const IncludeStructure &Includes,
SpeculativeFuzzyFind *SpecFuzzyFind,
- const CodeCompleteOptions &Opts)
+ const CodeCompleteOptions &Opts,
+ FormatProviderRef FormatProvider)
: FileName(FileName), Includes(Includes), SpecFuzzyFind(SpecFuzzyFind),
- Opts(Opts) {}
+ Opts(Opts), FormatProvider(FormatProvider) {}
CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) && {
trace::Span Tracer("CodeCompleteFlow");
@@ -1307,9 +1311,8 @@
assert(Recorder && "Recorder is not set");
CCContextKind = Recorder->CCContext.getKind();
IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration();
- auto Style = getFormatStyleForFile(SemaCCInput.FileName,
- SemaCCInput.ParseInput.Contents,
- *SemaCCInput.ParseInput.TFS);
+ auto Style =
+ FormatProvider(SemaCCInput.FileName, SemaCCInput.ParseInput.Contents);
const auto NextToken = Lexer::findNextToken(
Recorder->CCSema->getPreprocessor().getCodeCompletionLoc(),
Recorder->CCSema->getSourceManager(), Recorder->CCSema->LangOpts);
@@ -1318,7 +1321,7 @@
// If preprocessor was run, inclusions from preprocessor callback should
// already be added to Includes.
Inserter.emplace(
- SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style,
+ SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, *Style,
SemaCCInput.ParseInput.CompileCommand.Directory,
&Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
for (const auto &Inc : Includes.MainFileIncludes)
@@ -1397,12 +1400,12 @@
ProxSources[FileName].Cost = 0;
FileProximity.emplace(ProxSources);
- auto Style = getFormatStyleForFile(FileName, Content, TFS);
+ auto Style = FormatProvider(FileName, Content);
// This will only insert verbatim headers.
- Inserter.emplace(FileName, Content, Style,
+ Inserter.emplace(FileName, Content, *Style,
/*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr);
- auto Identifiers = collectIdentifiers(Content, Style);
+ auto Identifiers = collectIdentifiers(Content, *Style);
std::vector<RawIdentifier> IdentifierResults;
for (const auto &IDAndCount : Identifiers) {
RawIdentifier ID;
@@ -1420,7 +1423,7 @@
// - all-scopes query if no qualifier was typed (and it's allowed).
SpecifiedScope Scopes;
Scopes.AccessibleScopes = visibleNamespaces(
- Content.take_front(Offset), format::getFormattingLangOpts(Style));
+ Content.take_front(Offset), format::getFormattingLangOpts(*Style));
for (std::string &S : Scopes.AccessibleScopes)
if (!S.empty())
S.append("::"); // visibleNamespaces doesn't include trailing ::.
@@ -1821,7 +1824,7 @@
}
auto Flow = CodeCompleteFlow(
FileName, Preamble ? Preamble->Includes : IncludeStructure(),
- SpecFuzzyFind, Opts);
+ SpecFuzzyFind, Opts, ParseInput.ClangFormatProvider);
return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse)
? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset,
*ParseInput.TFS)
Index: clang-tools-extra/clangd/ClangdServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdServer.h
+++ clang-tools-extra/clangd/ClangdServer.h
@@ -12,6 +12,7 @@
#include "../clang-tidy/ClangTidyOptions.h"
#include "CodeComplete.h"
#include "ConfigProvider.h"
+#include "FormatProvider.h"
#include "GlobalCompilationDatabase.h"
#include "Hover.h"
#include "Protocol.h"
@@ -132,6 +133,8 @@
/// checks will be disabled.
TidyProviderRef ClangTidyProvider;
+ FormatProviderRef ClangFormatProvider;
+
/// Clangd's workspace root. Relevant for "workspace" operations not bound
/// to a particular file.
/// FIXME: If not set, should use the current working directory.
@@ -377,6 +380,9 @@
// When set, provides clang-tidy options for a specific file.
TidyProviderRef ClangTidyProvider;
+ // When set, provides clang-format options for a specific file.
+ FormatProviderRef ClangFormatProvider;
+
// GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
llvm::StringMap<llvm::Optional<FuzzyFindRequest>>
CachedCompletionFuzzyFindRequestByFile;
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -12,6 +12,7 @@
#include "DumpAST.h"
#include "FindSymbols.h"
#include "Format.h"
+#include "FormatProvider.h"
#include "HeaderSourceSwitch.h"
#include "Headers.h"
#include "ParsedAST.h"
@@ -123,6 +124,7 @@
Opts.AsyncThreadsCount = 4; // Consistent!
Opts.TheiaSemanticHighlighting = true;
Opts.AsyncPreambleBuilds = true;
+ Opts.ClangFormatProvider = formatFallbackProvider;
return Opts;
}
@@ -146,6 +148,7 @@
Opts.CollectMainFileRefs)
: nullptr),
ClangTidyProvider(Opts.ClangTidyProvider),
+ ClangFormatProvider(Opts.ClangFormatProvider),
WorkspaceRoot(Opts.WorkspaceRoot),
// Pass a callback into `WorkScheduler` to extract symbols from a newly
// parsed file and rebuild the file index synchronously each time an AST
@@ -201,6 +204,7 @@
Inputs.Opts = std::move(Opts);
Inputs.Index = Index;
Inputs.ClangTidyProvider = ClangTidyProvider;
+ Inputs.ClangFormatProvider = ClangFormatProvider;
bool NewFile = WorkScheduler.update(File, Inputs, WantDiags);
// If we loaded Foo.h, we want to make sure Foo.cpp is indexed.
if (NewFile && BackgroundIdx)
@@ -316,6 +320,8 @@
ParseInputs ParseInput{IP->Command, &TFS, IP->Contents.str()};
ParseInput.Index = Index;
+ ParseInput.ClangFormatProvider = ClangFormatProvider;
+
CodeCompleteOpts.MainFileSignals = IP->Signals;
// FIXME(ibiryukov): even if Preamble is non-null, we may want to check
// both the old and the new version in case only one of them matches.
@@ -395,11 +401,8 @@
auto Action = [File = File.str(), Code = Code.str(),
TriggerText = TriggerText.str(), CursorPos = *CursorPos,
CB = std::move(CB), this]() mutable {
- auto Style = format::getStyle(format::DefaultFormatStyle, File,
- format::DefaultFallbackStyle, Code,
- TFS.view(/*CWD=*/llvm::None).get());
- if (!Style)
- return CB(Style.takeError());
+ auto Style = ClangFormatProvider(File, Code);
+ assert(Style && "Provider should always return a valid style");
std::vector<TextEdit> Result;
for (const tooling::Replacement &R :
@@ -466,12 +469,11 @@
return CB(R.takeError());
if (Opts.WantFormat) {
- auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents,
- *InpAST->Inputs.TFS);
+ auto Style = ClangFormatProvider(File, InpAST->Inputs.Contents);
llvm::Error Err = llvm::Error::success();
for (auto &E : R->GlobalChanges)
- Err =
- llvm::joinErrors(reformatEdit(E.getValue(), Style), std::move(Err));
+ Err = llvm::joinErrors(reformatEdit(E.getValue(), *Style),
+ std::move(Err));
if (Err)
return CB(std::move(Err));
@@ -572,9 +574,8 @@
// Tweaks don't apply clang-format, do that centrally here.
for (auto &It : (*Effect)->ApplyEdits) {
Edit &E = It.second;
- format::FormatStyle Style =
- getFormatStyleForFile(File, E.InitialCode, TFS);
- if (llvm::Error Err = reformatEdit(E, Style))
+ auto Style = ClangFormatProvider(File, E.InitialCode);
+ if (llvm::Error Err = reformatEdit(E, *Style))
elog("Failed to format {0}: {1}", It.first(), std::move(Err));
}
} else {
@@ -623,15 +624,15 @@
// Call clang-format.
auto Action = [File = File.str(), Code = Code.str(), Ranges = Ranges.vec(),
CB = std::move(CB), this]() mutable {
- format::FormatStyle Style = getFormatStyleForFile(File, Code, TFS);
+ auto Style = ClangFormatProvider(File, Code);
tooling::Replacements IncludeReplaces =
- format::sortIncludes(Style, Code, Ranges, File);
+ format::sortIncludes(*Style, Code, Ranges, File);
auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
if (!Changed)
return CB(Changed.takeError());
CB(IncludeReplaces.merge(format::reformat(
- Style, *Changed,
+ *Style, *Changed,
tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
File)));
};
@@ -657,9 +658,8 @@
this](llvm::Expected<InputsAndAST> InpAST) mutable {
if (!InpAST)
return CB(InpAST.takeError());
- format::FormatStyle Style = getFormatStyleForFile(
- File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS);
- CB(clangd::getHover(InpAST->AST, Pos, std::move(Style), Index));
+ auto Style = ClangFormatProvider(File, InpAST->Inputs.Contents);
+ CB(clangd::getHover(InpAST->AST, Pos, *Style, Index));
};
WorkScheduler.runWithAST("Hover", File, std::move(Action),
Index: clang-tools-extra/clangd/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/CMakeLists.txt
+++ clang-tools-extra/clangd/CMakeLists.txt
@@ -66,6 +66,7 @@
FindTarget.cpp
FileDistance.cpp
Format.cpp
+ FormatProvider.cpp
FS.cpp
FuzzyMatch.cpp
GlobalCompilationDatabase.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits