From d813af73f70f6b2fd41621d640cc35e595b9da4c Mon Sep 17 00:00:00 2001 From: "Ben Hamilton (Ben Gertzfield)" Date: Tue, 23 Jan 2024 13:32:41 -0700 Subject: [PATCH] [Format] Fix detection of languages when reading from stdin (#79051) The code cleanup in #74794 accidentally broke detection of languages by reading file content from stdin, e.g. via `clang-format -dump-config - < /path/to/filename`. This PR adds unit and integration tests to reproduce the issue and adds a fix. Fixes: #79023 --- clang/test/Format/dump-config-objc-stdin.m | 5 +++++ clang/tools/clang-format/ClangFormat.cpp | 24 ++++++++++++---------- clang/unittests/Format/FormatTestObjC.cpp | 8 ++++++++ 3 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 clang/test/Format/dump-config-objc-stdin.m diff --git a/clang/test/Format/dump-config-objc-stdin.m b/clang/test/Format/dump-config-objc-stdin.m new file mode 100644 index 00000000000000..b22ff7b3328caa --- /dev/null +++ b/clang/test/Format/dump-config-objc-stdin.m @@ -0,0 +1,5 @@ +// RUN: clang-format -dump-config - < %s | FileCheck %s + +// CHECK: Language: ObjC +@interface Foo +@end diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 49ab7677a3ee9c..5ee6092bb9bb7f 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -547,18 +547,20 @@ static void PrintVersion(raw_ostream &OS) { // Dump the configuration. static int dumpConfig(bool IsSTDIN) { std::unique_ptr Code; - // We can't read the code to detect the language if there's no file name. - if (!IsSTDIN) { - // Read in the code in case the filename alone isn't enough to detect the - // language. - ErrorOr> CodeOrErr = - MemoryBuffer::getFileOrSTDIN(FileNames[0]); - if (std::error_code EC = CodeOrErr.getError()) { - llvm::errs() << EC.message() << "\n"; - return 1; - } - Code = std::move(CodeOrErr.get()); + + // `FileNames` must have at least "-" in it even if no file was specified. + assert(!FileNames.empty()); + + // Read in the code in case the filename alone isn't enough to detect the + // language. + ErrorOr> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(FileNames[0]); + if (std::error_code EC = CodeOrErr.getError()) { + llvm::errs() << EC.message() << "\n"; + return 1; } + Code = std::move(CodeOrErr.get()); + llvm::Expected FormatStyle = clang::format::getStyle(Style, IsSTDIN ? AssumeFileName : FileNames[0], FallbackStyle, Code ? Code->getBuffer() : ""); diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp index cd4f9d934127bf..d2c3459e0f846d 100644 --- a/clang/unittests/Format/FormatTestObjC.cpp +++ b/clang/unittests/Format/FormatTestObjC.cpp @@ -31,6 +31,14 @@ class FormatTestObjC : public FormatTestBase { _verifyIncompleteFormat(__FILE__, __LINE__, __VA_ARGS__) #define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__) +TEST(FormatTestObjCStyle, DetectsObjCInStdin) { + auto Style = getStyle("LLVM", "", "none", + "@interface\n" + "- (id)init;"); + ASSERT_TRUE((bool)Style); + EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language); +} + TEST(FormatTestObjCStyle, DetectsObjCInHeaders) { auto Style = getStyle("LLVM", "a.h", "none", "@interface\n"