Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4782,7 +4782,13 @@ the configuration (without a prefix: ``Auto``).
.. _Language:

**Language** (``LanguageKind``) :versionbadge:`clang-format 3.5` :ref:`¶ <Language>`
Language, this format style is targeted at.
The language that this format style targets.

.. note::

You can also specify the language (``Cpp`` or ``ObjC``) for ``.h`` files
by adding a ``// clang-format Language:`` line before the first
non-comment and non-empty line, e.g. ``// clang-format Language: ObjC``.

Possible values:

Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ clang-format
- Adds ``BreakBeforeTemplateCloser`` option.
- Adds ``BinPackLongBracedList`` option to override bin packing options in
long (20 item or more) braced list initializer lists.
- Allow specifying the language (C++ or Objective-C) for a ``.h`` file by adding
a special comment (e.g. ``// clang-format Language: ObjC``) near the top of
the file.

libclang
--------
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3353,7 +3353,12 @@ struct FormatStyle {
}
bool isTableGen() const { return Language == LK_TableGen; }

/// Language, this format style is targeted at.
/// The language that this format style targets.
/// \note
/// You can also specify the language (``Cpp`` or ``ObjC``) for ``.h`` files
/// by adding a ``// clang-format Language:`` line before the first
/// non-comment and non-empty line, e.g. ``// clang-format Language: ObjC``.
/// \endnote
/// \version 3.5
LanguageKind Language;

Expand Down
33 changes: 33 additions & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4021,6 +4021,35 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
return FormatStyle::LK_Cpp;
}

static FormatStyle::LanguageKind getLanguageByComment(const Environment &Env) {
const auto ID = Env.getFileID();
const auto &SourceMgr = Env.getSourceManager();

LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
LangOpts.LineComment = 1;

Lexer Lex(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts);
Lex.SetCommentRetentionState(true);

for (Token Tok; !Lex.LexFromRawLexer(Tok) && Tok.is(tok::comment);) {
auto Text = StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
Tok.getLength());
if (!Text.consume_front("// clang-format Language:"))
continue;

Text = Text.trim();
// if (Text == "C")
// return FormatStyle::LK_C;
if (Text == "Cpp")
return FormatStyle::LK_Cpp;
if (Text == "ObjC")
return FormatStyle::LK_ObjC;
}

return FormatStyle::LK_None;
}

FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
const auto GuessedLanguage = getLanguageByFileName(FileName);
if (GuessedLanguage == FormatStyle::LK_Cpp) {
Expand All @@ -4030,6 +4059,10 @@ FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
if (!Code.empty() && (Extension.empty() || Extension == ".h")) {
auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName;
Environment Env(Code, NonEmptyFileName, /*Ranges=*/{});
if (const auto Language = getLanguageByComment(Env);
Language != FormatStyle::LK_None) {
return Language;
}
ObjCHeaderStyleGuesser Guesser(Env, getLLVMStyle());
Guesser.process();
if (Guesser.isObjC())
Expand Down
9 changes: 9 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25136,6 +25136,15 @@ TEST_F(FormatTest, GuessLanguageWithChildLines) {
guessLanguage("foo.h", "#define FOO ({ foo(); ({ NSString *s; }) })"));
}

TEST_F(FormatTest, GetLanguageByComment) {
EXPECT_EQ(FormatStyle::LK_Cpp,
guessLanguage("foo.h", "// clang-format Language: Cpp\n"
"int DoStuff(CGRect rect);"));
EXPECT_EQ(FormatStyle::LK_ObjC,
guessLanguage("foo.h", "// clang-format Language: ObjC\n"
"int i;"));
}

TEST_F(FormatTest, TypenameMacros) {
std::vector<std::string> TypenameMacros = {"STACK_OF", "LIST", "TAILQ_ENTRY"};

Expand Down
Loading