r181589 - Config file support for clang-format, part 2.

Alexander Kornienko alexfh at google.com
Fri May 10 04:56:10 PDT 2013


Author: alexfh
Date: Fri May 10 06:56:10 2013
New Revision: 181589

URL: http://llvm.org/viewvc/llvm-project?rev=181589&view=rev
Log:
Config file support for clang-format, part 2.

Summary:
Adds actual config file reading to the clang-format utility.
Configuration file name is .clang-format. It is looked up for each input file
in its parent directories starting from immediate one. First found .clang-format
file is used. When using standard input, .clang-format is searched starting from
the current directory.
Added -dump-config option to easily create configuration files.

Reviewers: djasper, klimek

Reviewed By: klimek

CC: cfe-commits, jordan_rose, kimgr

Differential Revision: http://llvm-reviews.chandlerc.com/D758

Modified:
    cfe/trunk/include/clang/Format/Format.h
    cfe/trunk/lib/Format/Format.cpp
    cfe/trunk/tools/clang-format/ClangFormat.cpp
    cfe/trunk/unittests/Format/FormatTest.cpp

Modified: cfe/trunk/include/clang/Format/Format.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=181589&r1=181588&r2=181589&view=diff
==============================================================================
--- cfe/trunk/include/clang/Format/Format.h (original)
+++ cfe/trunk/include/clang/Format/Format.h Fri May 10 06:56:10 2013
@@ -93,6 +93,29 @@ struct FormatStyle {
   /// \brief If \c true, aligns escaped newlines as far left as possible.
   /// Otherwise puts them into the right-most column.
   bool AlignEscapedNewlinesLeft;
+
+  bool operator==(const FormatStyle &R) const {
+    return AccessModifierOffset == R.AccessModifierOffset &&
+           AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
+           AllowAllParametersOfDeclarationOnNextLine ==
+               R.AllowAllParametersOfDeclarationOnNextLine &&
+           AllowShortIfStatementsOnASingleLine ==
+               R.AllowShortIfStatementsOnASingleLine &&
+           BinPackParameters == R.BinPackParameters &&
+           ColumnLimit == R.ColumnLimit &&
+           ConstructorInitializerAllOnOneLineOrOnePerLine ==
+               R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
+           DerivePointerBinding == R.DerivePointerBinding &&
+           IndentCaseLabels == R.IndentCaseLabels &&
+           MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
+           ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
+           PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
+           PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
+           PointerBindsToType == R.PointerBindsToType &&
+           SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
+           Standard == R.Standard;
+  }
+
 };
 
 /// \brief Returns a format style complying with the LLVM coding standards:

Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=181589&r1=181588&r2=181589&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Fri May 10 06:56:10 2013
@@ -46,10 +46,19 @@ struct ScalarEnumerationTraits<clang::fo
 
 template <> struct MappingTraits<clang::format::FormatStyle> {
   static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) {
-    if (!IO.outputting()) {
+    if (IO.outputting()) {
+      StringRef StylesArray[] = { "LLVM", "Google", "Chromium", "Mozilla" };
+      ArrayRef<StringRef> Styles(StylesArray);
+      for (size_t i = 0, e = Styles.size(); i < e; ++i) {
+        StringRef StyleName(Styles[i]);
+        if (Style == clang::format::getPredefinedStyle(StyleName)) {
+          IO.mapOptional("# BasedOnStyle", StyleName);
+          break;
+        }
+      }
+    } else {
       StringRef BasedOnStyle;
       IO.mapOptional("BasedOnStyle", BasedOnStyle);
-
       if (!BasedOnStyle.empty())
         Style = clang::format::getPredefinedStyle(BasedOnStyle);
     }
@@ -245,9 +254,9 @@ public:
 private:
   void DebugTokenState(const AnnotatedToken &AnnotatedTok) {
     const Token &Tok = AnnotatedTok.FormatTok.Tok;
-    llvm::errs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
+    llvm::dbgs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
                               Tok.getLength());
-    llvm::errs();
+    llvm::dbgs();
   }
 
   struct ParenState {
@@ -825,7 +834,7 @@ private:
       unsigned Penalty = Queue.top().first.first;
       StateNode *Node = Queue.top().second;
       if (Node->State.NextToken == NULL) {
-        DEBUG(llvm::errs() << "\n---\nPenalty for line: " << Penalty << "\n");
+        DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
         break;
       }
       Queue.pop();
@@ -845,8 +854,8 @@ private:
 
     // Reconstruct the solution.
     reconstructPath(InitialState, Queue.top().second);
-    DEBUG(llvm::errs() << "Total number of analyzed states: " << Count << "\n");
-    DEBUG(llvm::errs() << "---\n");
+    DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
+    DEBUG(llvm::dbgs() << "---\n");
 
     // Return the column after the last token of the solution.
     return Queue.top().second->State.Column;
@@ -862,7 +871,7 @@ private:
     reconstructPath(State, Current->Previous);
     DEBUG({
       if (Current->NewLine) {
-        llvm::errs()
+        llvm::dbgs()
             << "Penalty for splitting before "
             << Current->Previous->State.NextToken->FormatTok.Tok.getName()
             << ": " << Current->Previous->State.NextToken->SplitPenalty << "\n";

Modified: cfe/trunk/tools/clang-format/ClangFormat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-format/ClangFormat.cpp?rev=181589&r1=181588&r2=181589&view=diff
==============================================================================
--- cfe/trunk/tools/clang-format/ClangFormat.cpp (original)
+++ cfe/trunk/tools/clang-format/ClangFormat.cpp Fri May 10 06:56:10 2013
@@ -20,6 +20,7 @@
 #include "clang/Format/Format.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Signals.h"
 
@@ -36,13 +37,20 @@ Lengths("length", cl::desc("Format a ran
                            "Can only be used with one input file."));
 static cl::opt<std::string> 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<bool> Inplace("i",
                              cl::desc("Inplace edit <file>s, if specified."));
 
 static cl::opt<bool> OutputXML(
     "output-replacements-xml", cl::desc("Output replacements as XML."));
+static cl::opt<bool>
+    DumpConfig("dump-config",
+               cl::desc("Dump configuration options to stdout and exit. Can be used with -style option."));
 
 static cl::list<std::string> FileNames(cl::Positional,
                                        cl::desc("[<file> ...]"));
@@ -59,18 +67,38 @@ static FileID createInMemoryFile(StringR
   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);
+  for (StringRef Directory = llvm::sys::path::parent_path(Path);
+       !Directory.empty();
+       Directory = llvm::sys::path::parent_path(Directory)) {
+    SmallString<128> ConfigFile(Directory);
+    llvm::sys::path::append(ConfigFile, ".clang-format");
+    DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+    bool IsFile = false;
+    llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
+    if (IsFile) {
+      OwningPtr<MemoryBuffer> 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() << "Error reading " << ConfigFile << ": " << ec.message()
+                     << "\n";
+        continue;
+      }
+      DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
+      return Style;
+    }
+  }
+  llvm::errs() << "Can't find usable .clang-format, using LLVM style\n";
+  return getLLVMStyle();
 }
 
 // Returns true on error.
@@ -118,7 +146,8 @@ static bool format(std::string FileName)
     }
     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()
         << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
@@ -171,6 +200,13 @@ int main(int argc, const char **argv) {
   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:

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=181589&r1=181588&r2=181589&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Fri May 10 06:56:10 2013
@@ -3933,28 +3933,6 @@ TEST_F(FormatTest, DoNotCreateUnreasonab
                "}");
 }
 
-bool operator==(const FormatStyle &L, const FormatStyle &R) {
-  return L.AccessModifierOffset == R.AccessModifierOffset &&
-         L.AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
-         L.AllowAllParametersOfDeclarationOnNextLine ==
-             R.AllowAllParametersOfDeclarationOnNextLine &&
-         L.AllowShortIfStatementsOnASingleLine ==
-             R.AllowShortIfStatementsOnASingleLine &&
-         L.BinPackParameters == R.BinPackParameters &&
-         L.ColumnLimit == R.ColumnLimit &&
-         L.ConstructorInitializerAllOnOneLineOrOnePerLine ==
-             R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
-         L.DerivePointerBinding == R.DerivePointerBinding &&
-         L.IndentCaseLabels == R.IndentCaseLabels &&
-         L.MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
-         L.ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
-         L.PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
-         L.PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
-         L.PointerBindsToType == R.PointerBindsToType &&
-         L.SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
-         L.Standard == R.Standard;
-}
-
 bool allStylesEqual(ArrayRef<FormatStyle> Styles) {
   for (size_t i = 1; i < Styles.size(); ++i)
     if (!(Styles[0] == Styles[i]))





More information about the cfe-commits mailing list