Index: tools/clang-format/ClangFormat.cpp =================================================================== --- tools/clang-format/ClangFormat.cpp +++ tools/clang-format/ClangFormat.cpp @@ -36,13 +36,20 @@ "Can only be used with one input file.")); static cl::opt Style( "style", - cl::desc("Coding style, currently supports: LLVM, Google, Chromium, Mozilla."), + cl::desc( + "Coding style, currently supports: LLVM, Google, Chromium, Mozilla. " + "Use '-style file' to load style configuration from .clang-format file " + "located in one of the parent directories of the source file (or " + "current directory for stdin)."), cl::init("LLVM")); static cl::opt Inplace("i", cl::desc("Inplace edit s, if specified.")); static cl::opt OutputXML( "output-replacements-xml", cl::desc("Output replacements as XML.")); +static cl::opt + DumpConfig("dump-config", + cl::desc("Dump configuration options to stdout and exit. Can be used with -style option.")); static cl::list FileNames(cl::Positional, cl::desc("[ ...]")); @@ -59,18 +66,36 @@ return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); } -static FormatStyle getStyle() { - FormatStyle TheStyle = getGoogleStyle(); - if (Style == "LLVM") - TheStyle = getLLVMStyle(); - else if (Style == "Chromium") - TheStyle = getChromiumStyle(); - else if (Style == "Mozilla") - TheStyle = getMozillaStyle(); - else if (Style != "Google") - llvm::errs() << "Unknown style " << Style << ", using Google style.\n"; - - return TheStyle; +FormatStyle getStyle(StringRef StyleName, StringRef FileName) { + if (!StyleName.equals_lower("file")) + return getPredefinedStyle(StyleName); + + SmallString<128> Path(FileName); + llvm::sys::fs::make_absolute(Path); + StringRef Directory = llvm::sys::path::parent_path(Path); + while (!Directory.empty()) { + std::string ConfigFile = Directory.str(); + ConfigFile += "/.clang-format"; + bool IsFile; + llvm::sys::fs::is_regular_file(ConfigFile, IsFile); + if (IsFile) { + OwningPtr Text; + if (error_code ec = MemoryBuffer::getFile(ConfigFile, Text)) { + llvm::errs() << ec.message() << "\n"; + continue; + } + FormatStyle Style; + if (error_code ec = parseConfiguration(Text->getBuffer(), &Style)) { + llvm::errs() << ec.message() << "\n"; + continue; + } + llvm::errs() << "Using configuration file " << ConfigFile << "\n"; + return Style; + } + Directory = llvm::sys::path::parent_path(Directory); + } + llvm::errs() << "Can't find .clang-format, using LLVM style\n"; + return getLLVMStyle(); } // Returns true on error. @@ -118,7 +143,8 @@ } Ranges.push_back(CharSourceRange::getCharRange(Start, End)); } - tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges); + tooling::Replacements Replaces = + reformat(getStyle(Style, FileName), Lex, Sources, Ranges); if (OutputXML) { llvm::outs() << "\n\n"; @@ -171,6 +197,13 @@ if (Help) cl::PrintHelpMessage(); + if (DumpConfig) { + std::string Config = clang::format::configurationAsText( + clang::format::getStyle(Style, FileNames.empty() ? "-" : FileNames[0])); + llvm::outs() << Config << "\n"; + return 0; + } + bool Error = false; switch (FileNames.size()) { case 0: