Skip to content

Commit

Permalink
[clang-format] New API guessLanguage()
Browse files Browse the repository at this point in the history
Summary:
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

Reviewers: jolesiak, krasimir

Reviewed By: jolesiak, krasimir

Subscribers: klimek, cfe-commits, sammccall

Differential Revision: https://reviews.llvm.org/D43522

llvm-svn: 325691
  • Loading branch information
bhamiltoncx committed Feb 21, 2018
1 parent f3a9ab0 commit 3b345c3
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1981,6 +1981,10 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
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) {
Expand Down
31 changes: 20 additions & 11 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2294,24 +2294,33 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
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))
Expand Down
28 changes: 28 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11952,6 +11952,34 @@ TEST_F(FormatTest, StructuredBindings) {
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

0 comments on commit 3b345c3

Please sign in to comment.