benhamilton created this revision.
benhamilton added a reviewer: jolesiak.
Herald added subscribers: cfe-commits, klimek.
benhamilton added a reviewer: krasimir.
For clients which don't have a filesystem, calling getStyle() doesn't
make much sense (there's no .clang-format files to search for).

In this diff, I hoist out the language-guessing logic from getStyle()
and move it into a new API guessLanguage().

I also added support for guessing the language of files which have no
extension (they could be C++ or ObjC).

Test Plan: New tests added. Ran tests with:

  % make -j12 FormatTests && ./tools/clang/unittests/Format/FormatTests


Repository:
  rC Clang

https://reviews.llvm.org/D43522

Files:
  include/clang/Format/Format.h
  lib/Format/Format.cpp
  unittests/Format/FormatTest.cpp

Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -11952,6 +11952,34 @@
   verifyFormat("auto const &[ a, b ] = f();", Spaces);
 }
 
+struct GuessLanguageTestCase {
+  const char *const FileName;
+  const char *const Code;
+  const FormatStyle::LanguageKind ExpectedResult;
+};
+
+class GuessLanguageTest
+    : public FormatTest,
+      public ::testing::WithParamInterface<GuessLanguageTestCase> {};
+
+TEST_P(GuessLanguageTest, FileAndCode) {
+  auto TestCase = GetParam();
+  EXPECT_EQ(TestCase.ExpectedResult,
+            guessLanguage(TestCase.FileName, TestCase.Code));
+}
+
+static const GuessLanguageTestCase TestCases[] = {
+    {"foo.cc", "", FormatStyle::LK_Cpp},
+    {"foo.m", "", FormatStyle::LK_ObjC},
+    {"foo.mm", "", FormatStyle::LK_ObjC},
+    {"foo.h", "", FormatStyle::LK_Cpp},
+    {"foo.h", "@interface Foo\n@end\n", FormatStyle::LK_ObjC},
+    {"foo", "", FormatStyle::LK_Cpp},
+    {"foo", "@interface Foo\n@end\n", FormatStyle::LK_ObjC},
+};
+INSTANTIATE_TEST_CASE_P(ValidLanguages, GuessLanguageTest,
+                        ::testing::ValuesIn(TestCases));
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -2294,24 +2294,33 @@
   return FormatStyle::LK_Cpp;
 }
 
+FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
+  FormatStyle::LanguageKind result = getLanguageByFileName(FileName);
+  if (result == FormatStyle::LK_Cpp) {
+    auto extension = llvm::sys::path::extension(FileName);
+    // If there's no file extension (or it's .h), we need to check the contents
+    // of the code to see if it contains Objective-C.
+    if (extension.empty() || extension == ".h") {
+      std::unique_ptr<Environment> Env =
+          Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
+      ObjCHeaderStyleGuesser Guesser(*Env, getLLVMStyle());
+      Guesser.process();
+      if (Guesser.isObjC()) {
+        result = FormatStyle::LK_ObjC;
+      }
+    }
+  }
+  return result;
+}
+
 llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
                                      StringRef FallbackStyleName,
                                      StringRef Code, vfs::FileSystem *FS) {
   if (!FS) {
     FS = vfs::getRealFileSystem().get();
   }
   FormatStyle Style = getLLVMStyle();
-  Style.Language = getLanguageByFileName(FileName);
-
-  if (Style.Language == FormatStyle::LK_Cpp && FileName.endswith(".h")) {
-    std::unique_ptr<Environment> Env =
-        Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
-    ObjCHeaderStyleGuesser Guesser(*Env, Style);
-    Guesser.process();
-    if (Guesser.isObjC()) {
-      Style.Language = FormatStyle::LK_ObjC;
-    }
-  }
+  Style.Language = guessLanguage(FileName, Code);
 
   FormatStyle FallbackStyle = getNoStyle();
   if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -1981,6 +1981,10 @@
                                      StringRef Code = "",
                                      vfs::FileSystem *FS = nullptr);
 
+// \brief Guesses the language from the ``FileName`` and ``Code`` to be formatted.
+// Defaults to FormatStyle::LK_Cpp.
+FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code);
+
 // \brief Returns a string representation of ``Language``.
 inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
   switch (Language) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to