njames93 updated this revision to Diff 320333.
njames93 added a comment.

Small fix


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,218 @@
+//===--- 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;
+          vlog("Format: Parsing config file {0}", path());
+          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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to