llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Owen Pan (owenca) <details> <summary>Changes</summary> Closes #<!-- -->128119 --- Full diff: https://github.com/llvm/llvm-project/pull/128122.diff 5 Files Affected: - (modified) clang/docs/ClangFormatStyleOptions.rst (+7-1) - (modified) clang/docs/ReleaseNotes.rst (+3) - (modified) clang/include/clang/Format/Format.h (+6-1) - (modified) clang/lib/Format/Format.cpp (+33) - (modified) clang/unittests/Format/FormatTest.cpp (+9) ``````````diff diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index bf6dd9e13915f..2d4ead76cfef2 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -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: diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e1c61992512b5..0e65f72623f28 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 16956b4e0fbd4..55709a0261b12 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -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; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 0898b69528ebc..400f39ecc5483 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -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) { @@ -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()) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 132264486100d..05febf12c17ba 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -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"}; `````````` </details> https://github.com/llvm/llvm-project/pull/128122 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits