Clang-format: allow -style="{yaml/json}" on command line
Summary: + improved handling of default style and predefined styles.
Reviewers: djasper, klimek
Reviewed By: klimek
CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D813
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182205 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
index a9687bc..8df7d24 100644
--- a/docs/ClangFormat.rst
+++ b/docs/ClangFormat.rst
@@ -20,8 +20,8 @@
If no arguments are specified, it formats the code from standard input
and writes the result to the standard output.
- If <file>s are given, it reformats the files. If -i is specified
- together with <file>s, the files are edited in-place. Otherwise, the
+ If <file>s are given, it reformats the files. If -i is specified
+ together with <file>s, the files are edited in-place. Otherwise, the
result is written to the standard output.
USAGE: clang-format [options] [<file> ...]
@@ -47,10 +47,13 @@
-output-replacements-xml - Output replacements as XML.
-style=<string> - Coding style, currently supports:
LLVM, Google, Chromium, Mozilla.
- Use '-style file' to load style configuration from
+ 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).
+ Use -style="{key: value, ...}" to set specific
+ parameters, e.g.:
+ -style="{BasedOnStyle: llvm, IndentWidth: 8}"
General options:
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 021073b..1bc1996 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -161,11 +161,13 @@
/// https://developer.mozilla.org/en-US/docs/Developer_Guide/Coding_Style.
FormatStyle getMozillaStyle();
-/// \brief Returns a predefined style by name.
+/// \brief Gets a predefined style by name.
///
/// Currently supported names: LLVM, Google, Chromium, Mozilla. Names are
/// compared case-insensitively.
-FormatStyle getPredefinedStyle(StringRef Name);
+///
+/// Returns true if the Style has been set.
+bool getPredefinedStyle(StringRef Name, FormatStyle *Style);
/// \brief Parse configuration from YAML-formatted text.
llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style);
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 3dd0002..64a988d 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -60,7 +60,9 @@
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)) {
+ clang::format::FormatStyle PredefinedStyle;
+ if (clang::format::getPredefinedStyle(StyleName, &PredefinedStyle) &&
+ Style == PredefinedStyle) {
IO.mapOptional("# BasedOnStyle", StyleName);
break;
}
@@ -69,7 +71,10 @@
StringRef BasedOnStyle;
IO.mapOptional("BasedOnStyle", BasedOnStyle);
if (!BasedOnStyle.empty())
- Style = clang::format::getPredefinedStyle(BasedOnStyle);
+ if (!clang::format::getPredefinedStyle(BasedOnStyle, &Style)) {
+ IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
+ return;
+ }
}
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
@@ -180,18 +185,19 @@
return MozillaStyle;
}
-FormatStyle getPredefinedStyle(StringRef Name) {
+bool getPredefinedStyle(StringRef Name, FormatStyle *Style) {
if (Name.equals_lower("llvm"))
- return getLLVMStyle();
- if (Name.equals_lower("chromium"))
- return getChromiumStyle();
- if (Name.equals_lower("mozilla"))
- return getMozillaStyle();
- if (Name.equals_lower("google"))
- return getGoogleStyle();
+ *Style = getLLVMStyle();
+ else if (Name.equals_lower("chromium"))
+ *Style = getChromiumStyle();
+ else if (Name.equals_lower("mozilla"))
+ *Style = getMozillaStyle();
+ else if (Name.equals_lower("google"))
+ *Style = getGoogleStyle();
+ else
+ return false;
- llvm::errs() << "Unknown style " << Name << ", using Google style.\n";
- return getGoogleStyle();
+ return true;
}
llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
diff --git a/test/Format/style-on-command-line.cpp b/test/Format/style-on-command-line.cpp
new file mode 100644
index 0000000..679236f
--- /dev/null
+++ b/test/Format/style-on-command-line.cpp
@@ -0,0 +1,23 @@
+// RUN: grep -Ev "// *[A-Z0-9]+:" %s > %t.cpp
+// RUN: clang-format -style="{BasedOnStyle: Google, IndentWidth: 8}" %t.cpp | FileCheck -strict-whitespace -check-prefix=CHECK1 %s
+// RUN: clang-format -style="{BasedOnStyle: LLVM, IndentWidth: 7}" %t.cpp | FileCheck -strict-whitespace -check-prefix=CHECK2 %s
+// RUN: clang-format -style="{BasedOnStyle: invalid, IndentWidth: 7}" %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK3 %s
+// RUN: clang-format -style="{lsjd}" %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK4 %s
+// RUN: [ ! -e %T/.clang-format ] || rm %T/.clang-format
+// RUN: clang-format -style=file %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK5 %s
+// RUN: echo -e "BasedOnStyle: google\nIndentWidth: 5" > %T/.clang-format
+// RUN: clang-format -style=file %t.cpp 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK6 %s
+void f() {
+// CHECK1: {{^ int\* i;$}}
+// CHECK2: {{^ int \*i;$}}
+// CHECK3: Unknown value for BasedOnStyle: invalid
+// CHECK3: Error parsing -style: Invalid argument, using LLVM style
+// CHECK3: {{^ int \*i;$}}
+// CHECK4: Error parsing -style: Invalid argument, using LLVM style
+// CHECK4: {{^ int \*i;$}}
+// CHECK5: Can't find usable .clang-format, using LLVM style
+// CHECK5: {{^ int \*i;$}}
+// CHECK6: {{^ int\* i;$}}
+int*i;
+int j;
+}
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index f779348..fccd6bf 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -27,6 +27,9 @@
using namespace llvm;
+// Default style to use when no style specified or specified style not found.
+static const char *DefaultStyle = "LLVM";
+
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
// Mark all our options with this category, everything else (except for -version
@@ -54,11 +57,14 @@
Style("style",
cl::desc("Coding style, currently supports:\n"
" LLVM, Google, Chromium, Mozilla.\n"
- "Use '-style file' to load style configuration from\n"
+ "Use -style=file to load style configuration from\n"
".clang-format file located in one of the parent\n"
"directories of the source file (or current\n"
- "directory for stdin)."),
- cl::init("LLVM"), cl::cat(ClangFormatCategory));
+ "directory for stdin).\n"
+ "Use -style=\"{key: value, ...}\" to set specific\n"
+ "parameters, e.g.:\n"
+ " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\""),
+ cl::init(DefaultStyle), cl::cat(ClangFormatCategory));
static cl::opt<bool> Inplace("i",
cl::desc("Inplace edit <file>s, if specified."),
cl::cat(ClangFormatCategory));
@@ -88,8 +94,24 @@
}
FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
- if (!StyleName.equals_lower("file"))
- return getPredefinedStyle(StyleName);
+ FormatStyle Style;
+ getPredefinedStyle(DefaultStyle, &Style);
+
+ if (StyleName.startswith("{")) {
+ // Parse YAML/JSON style from the command line.
+ if (error_code ec = parseConfiguration(StyleName, &Style)) {
+ llvm::errs() << "Error parsing -style: " << ec.message()
+ << ", using " << DefaultStyle << " style\n";
+ }
+ return Style;
+ }
+
+ if (!StyleName.equals_lower("file")) {
+ if (!getPredefinedStyle(StyleName, &Style))
+ llvm::errs() << "Invalid value for -style, using " << DefaultStyle
+ << " style\n";
+ return Style;
+ }
SmallString<128> Path(FileName);
llvm::sys::fs::make_absolute(Path);
@@ -109,7 +131,6 @@
llvm::errs() << ec.message() << "\n";
continue;
}
- FormatStyle Style;
if (error_code ec = parseConfiguration(Text->getBuffer(), &Style)) {
llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()
<< "\n";
@@ -119,8 +140,9 @@
return Style;
}
}
- llvm::errs() << "Can't find usable .clang-format, using LLVM style\n";
- return getLLVMStyle();
+ llvm::errs() << "Can't find usable .clang-format, using " << DefaultStyle
+ << " style\n";
+ return Style;
}
// Returns true on error.
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index e143603..e0ef3d1 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -4209,27 +4209,29 @@
}
TEST_F(FormatTest, GetsPredefinedStyleByName) {
- FormatStyle LLVMStyles[] = { getLLVMStyle(), getPredefinedStyle("LLVM"),
- getPredefinedStyle("llvm"),
- getPredefinedStyle("lLvM") };
- EXPECT_TRUE(allStylesEqual(LLVMStyles));
+ FormatStyle Styles[3];
- FormatStyle GoogleStyles[] = { getGoogleStyle(), getPredefinedStyle("Google"),
- getPredefinedStyle("google"),
- getPredefinedStyle("gOOgle") };
- EXPECT_TRUE(allStylesEqual(GoogleStyles));
+ Styles[0] = getLLVMStyle();
+ EXPECT_TRUE(getPredefinedStyle("LLVM", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("lLvM", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
- FormatStyle ChromiumStyles[] = { getChromiumStyle(),
- getPredefinedStyle("Chromium"),
- getPredefinedStyle("chromium"),
- getPredefinedStyle("chROmiUM") };
- EXPECT_TRUE(allStylesEqual(ChromiumStyles));
+ Styles[0] = getGoogleStyle();
+ EXPECT_TRUE(getPredefinedStyle("Google", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("gOOgle", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
- FormatStyle MozillaStyles[] = { getMozillaStyle(),
- getPredefinedStyle("Mozilla"),
- getPredefinedStyle("mozilla"),
- getPredefinedStyle("moZilla") };
- EXPECT_TRUE(allStylesEqual(MozillaStyles));
+ Styles[0] = getChromiumStyle();
+ EXPECT_TRUE(getPredefinedStyle("Chromium", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("cHRoMiUM", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ Styles[0] = getMozillaStyle();
+ EXPECT_TRUE(getPredefinedStyle("Mozilla", &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("moZILla", &Styles[2]));
+ EXPECT_TRUE(allStylesEqual(Styles));
+
+ EXPECT_FALSE(getPredefinedStyle("qwerty", &Styles[0]));
}
TEST_F(FormatTest, ParsesConfiguration) {
@@ -4242,7 +4244,7 @@
#define CHECK_PARSE_BOOL(FIELD) \
Style.FIELD = false; \
EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); \
- EXPECT_TRUE(Style.FIELD); \
+ EXPECT_TRUE(Style.FIELD); \
EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \
EXPECT_FALSE(Style.FIELD);