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

llvm-svn: 182205
This commit is contained in:
Alexander Kornienko 2013-05-19 00:53:30 +00:00
parent 8cfbaa6988
commit 006b5c89ce
6 changed files with 102 additions and 44 deletions

View File

@ -20,8 +20,8 @@ to format C/C++/Obj-C code.
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 @@ to format C/C++/Obj-C code.
-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:

View File

@ -161,11 +161,13 @@ FormatStyle getChromiumStyle();
/// 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);

View File

@ -60,7 +60,9 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
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 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
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 @@ FormatStyle getMozillaStyle() {
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) {

View File

@ -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;
}

View File

@ -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 @@ static cl::opt<std::string>
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 @@ static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source,
}
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 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
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 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
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.

View File

@ -4209,27 +4209,29 @@ bool allStylesEqual(ArrayRef<FormatStyle> Styles) {
}
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 @@ TEST_F(FormatTest, ParsesConfiguration) {
#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);