Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -2338,6 +2338,7 @@ /// * "file" - Load style configuration from a file called ``.clang-format`` /// located in one of the parent directories of ``FileName`` or the current /// directory if ``FileName`` is empty. +/// * "file=" to explicitly specify the configuration file to use. /// /// \param[in] StyleName Style name to interpret according to the description /// above. Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -2519,6 +2519,8 @@ ".clang-format file located in one of the parent\n" "directories of the source file (or current\n" "directory for stdin).\n" + "Use -style=file: to explicitly specify" + "the configuration file.\n" "Use -style=\"{key: value, ...}\" to set specific\n" "parameters, e.g.:\n" " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\""; @@ -2568,6 +2570,22 @@ const char *DefaultFallbackStyle = "LLVM"; +/// Attempts to load a format file +llvm::Expected LoadConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS) { + llvm::ErrorOr> Text = + FS->getBufferForFile(ConfigFile.str()); + std::error_code ReadFileError = Text.getError(); + if (ReadFileError) { + return make_string_error("Error reading config file " + ReadFileError.message()); + } + FormatStyle Style = getLLVMStyle(); + std::error_code ParseFileError = parseConfiguration(Text.get()->getBuffer(), &Style); + if (ParseFileError != ParseError::Success) { + return make_string_error("Error parsing config file " + ParseFileError.message()); + } + return Style; +} + llvm::Expected getStyle(StringRef StyleName, StringRef FileName, StringRef FallbackStyleName, StringRef Code, @@ -2588,6 +2606,12 @@ return Style; } + // User provided clang-format file using -style=file:/path/to/format/file + // Check for explicit config filename + if (StyleName.startswith_lower("file:")) { + return LoadConfigFile(StyleName.substr(5), FS); + } + if (!StyleName.equals_lower("file")) { if (!getPredefinedStyle(StyleName, Style.Language, &Style)) return make_string_error("Invalid value for -style"); @@ -2628,24 +2652,7 @@ } if (FoundConfigFile) { - llvm::ErrorOr> Text = - FS->getBufferForFile(ConfigFile.str()); - if (std::error_code EC = Text.getError()) - return make_string_error(EC.message()); - if (std::error_code ec = - parseConfiguration(Text.get()->getBuffer(), &Style)) { - if (ec == ParseError::Unsuitable) { - if (!UnsuitableConfigFiles.empty()) - UnsuitableConfigFiles.append(", "); - UnsuitableConfigFiles.append(ConfigFile); - continue; - } - return make_string_error("Error reading " + ConfigFile + ": " + - ec.message()); - } - LLVM_DEBUG(llvm::dbgs() - << "Using configuration file " << ConfigFile << "\n"); - return Style; + return LoadConfigFile(ConfigFile, FS); } } if (!UnsuitableConfigFiles.empty()) Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -14350,6 +14350,35 @@ auto StyleTd = getStyle("file", "x.td", "llvm", "", &FS); ASSERT_TRUE((bool)StyleTd); ASSERT_EQ(*StyleTd, getLLVMStyle(FormatStyle::LK_TableGen)); + + // Test 9: explicit format file in parent directory. + ASSERT_TRUE( + FS.addFile("/e/.clang-format", 0, + llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: LLVM"))); + ASSERT_TRUE( + FS.addFile("/e/explicit.clang-format", 0, + llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google"))); + ASSERT_TRUE(FS.addFile("/e/sub/sub/sub/test.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("int i;"))); + auto Style8 = getStyle("file:/e/explicit.clang-format", + "/e/sub/sub/sub/test.cpp", "LLVM", "", &FS); + ASSERT_TRUE((bool)Style8); + ASSERT_EQ(*Style8, getGoogleStyle()); + + // Test 10: relative pah to a format file + ASSERT_TRUE( + FS.addFile("../../e/explicit.clang-format", 0, + llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google"))); + auto Style9 = getStyle("file:../../e/explicit.clang-format", + "/e/sub/sub/sub/test.cpp", "LLVM", "", &FS); + ASSERT_TRUE((bool)Style9); + ASSERT_EQ(*Style9, getGoogleStyle()); + + // Test 11: missing explicit format file + auto Style10 = getStyle("file:/e/missing.clang-format", + "/e/sub/sub/sub/test.cpp", "LLVM", "", &FS); + ASSERT_FALSE((bool)Style10); + llvm::consumeError(Style10.takeError()); } TEST_F(ReplacementTest, FormatCodeAfterReplacements) {