Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -1963,6 +1963,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\n" + "the configuration file.\n" "Use -style=\"{key: value, ...}\" to set specific\n" "parameters, e.g.:\n" " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\""; @@ -2009,6 +2011,30 @@ return Style; } + // Check for explicit config filename + if (StyleName.startswith_lower("file:")) { + SmallString<128> ConfigFile(StyleName.substr(5)); + auto Status = FS->status(ConfigFile.str()); + bool FoundConfigFile = + Status && (Status->getType() == llvm::sys::fs::file_type::regular_file); + if (!FoundConfigFile) { + return make_string_error("Configuration file " + ConfigFile + " not found"); + } + 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) { + return make_string_error("Configuration file " + ConfigFile + + " does not support " + getLanguageName(Style.Language)); + } + return make_string_error("Error reading " + ConfigFile + ": " + ec.message()); + } + DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n"); + return Style; + } + if (!StyleName.equals_lower("file")) { if (!getPredefinedStyle(StyleName, Style.Language, &Style)) return make_string_error("Invalid value for -style"); Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -10409,6 +10409,24 @@ auto Style7 = getStyle("file", "/d/.clang-format", "LLVM", "", &FS); ASSERT_FALSE((bool)Style7); llvm::consumeError(Style7.takeError()); + + // Test 8: 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 9: missing explicit format file + auto Style9 = getStyle("file:/e/missing.clang-format", "/e/sub/sub/sub/test.cpp", "LLVM", "", &FS); + ASSERT_FALSE((bool)Style9); + llvm::consumeError(Style9.takeError()); } TEST_F(ReplacementTest, FormatCodeAfterReplacements) {