summaryrefslogtreecommitdiffstats
path: root/clang/lib/Format/Format.cpp
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2013-12-10 11:28:13 +0000
committerAlexander Kornienko <alexfh@google.com>2013-12-10 11:28:13 +0000
commitc1637f167c7a2b6a3b4f30634b074a04bd60cd9a (patch)
treedf0f7c9170c667d5059dd191a2a050bd7893b9ec /clang/lib/Format/Format.cpp
parentb5c4b876907c3af47e1141a9221b5cb1f9372e06 (diff)
downloadbcm5719-llvm-c1637f167c7a2b6a3b4f30634b074a04bd60cd9a.tar.gz
bcm5719-llvm-c1637f167c7a2b6a3b4f30634b074a04bd60cd9a.zip
Allow predefined styles to define different options for different languages.
Summary: Allow predefined styles to define different options for different languages so that one can run: clang-format -style=google file1.cpp file2.js or use a single .clang-format file with "BasedOnStyle: Google" for both c++ and JS files. Added Google style for JavaScript with "BreakBeforeTernaryOperators" set to false. Reviewers: djasper Reviewed By: djasper CC: cfe-commits, klimek Differential Revision: http://llvm-reviews.chandlerc.com/D2364 llvm-svn: 196909
Diffstat (limited to 'clang/lib/Format/Format.cpp')
-rw-r--r--clang/lib/Format/Format.cpp131
1 files changed, 74 insertions, 57 deletions
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 91469a66ee9..da088bf5cbc 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -97,7 +97,10 @@ struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
};
template <> struct MappingTraits<FormatStyle> {
- static void mapping(llvm::yaml::IO &IO, FormatStyle &Style) {
+ static void mapping(IO &IO, FormatStyle &Style) {
+ // When reading, read the language first, we need it for getPredefinedStyle.
+ IO.mapOptional("Language", Style.Language);
+
if (IO.outputting()) {
StringRef StylesArray[] = { "LLVM", "Google", "Chromium",
"Mozilla", "WebKit" };
@@ -105,7 +108,7 @@ template <> struct MappingTraits<FormatStyle> {
for (size_t i = 0, e = Styles.size(); i < e; ++i) {
StringRef StyleName(Styles[i]);
FormatStyle PredefinedStyle;
- if (getPredefinedStyle(StyleName, &PredefinedStyle) &&
+ if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Style == PredefinedStyle) {
IO.mapOptional("# BasedOnStyle", StyleName);
break;
@@ -115,16 +118,17 @@ template <> struct MappingTraits<FormatStyle> {
StringRef BasedOnStyle;
IO.mapOptional("BasedOnStyle", BasedOnStyle);
if (!BasedOnStyle.empty()) {
- FormatStyle::LanguageKind Language = Style.Language;
- if (!getPredefinedStyle(BasedOnStyle, &Style)) {
+ FormatStyle::LanguageKind OldLanguage = Style.Language;
+ FormatStyle::LanguageKind Language =
+ ((FormatStyle *)IO.getContext())->Language;
+ if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
return;
}
- Style.Language = Language;
+ Style.Language = OldLanguage;
}
}
- IO.mapOptional("Language", Style.Language);
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
IO.mapOptional("ConstructorInitializerIndentWidth",
Style.ConstructorInitializerIndentWidth);
@@ -199,30 +203,28 @@ template <> struct MappingTraits<FormatStyle> {
};
// Allows to read vector<FormatStyle> while keeping default values.
-// Elements will be written or read starting from the 1st element.
-// When writing, the 0th element is ignored.
-// When reading, keys that are not present in the serialized form will be
-// copied from the 0th element of the vector. If the first element had no
-// Language specified, it will be treated as the default one for the following
-// elements.
+// IO.getContext() should contain a pointer to the FormatStyle structure, that
+// will be used to get default values for missing keys.
+// If the first element has no Language specified, it will be treated as the
+// default one for the following elements.
template <> struct DocumentListTraits<std::vector<FormatStyle> > {
- static size_t size(IO &io, std::vector<FormatStyle> &Seq) {
- return Seq.size() - 1;
+ static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
+ return Seq.size();
}
- static FormatStyle &element(IO &io, std::vector<FormatStyle> &Seq,
+ static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
size_t Index) {
- if (Index + 2 > Seq.size()) {
- assert(Index + 2 == Seq.size() + 1);
+ if (Index >= Seq.size()) {
+ assert(Index == Seq.size());
FormatStyle Template;
- if (Seq.size() > 1 && Seq[1].Language == FormatStyle::LK_None) {
- Template = Seq[1];
- } else {
+ if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
Template = Seq[0];
+ } else {
+ Template = *((const FormatStyle*)IO.getContext());
Template.Language = FormatStyle::LK_None;
}
- Seq.resize(Index + 2, Template);
+ Seq.resize(Index + 1, Template);
}
- return Seq[Index + 1];
+ return Seq[Index];
}
};
}
@@ -336,6 +338,16 @@ FormatStyle getGoogleStyle() {
return GoogleStyle;
}
+FormatStyle getGoogleJSStyle() {
+ FormatStyle GoogleJSStyle = getGoogleStyle();
+ GoogleJSStyle.Language = FormatStyle::LK_JavaScript;
+ GoogleJSStyle.BreakBeforeTernaryOperators = false;
+ // FIXME: Currently unimplemented:
+ // var arr = [1, 2, 3]; // No space after [ or before ].
+ // var obj = {a: 1, b: 2, c: 3}; // No space after ':'.
+ return GoogleJSStyle;
+}
+
FormatStyle getChromiumStyle() {
FormatStyle ChromiumStyle = getGoogleStyle();
ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
@@ -373,56 +385,67 @@ FormatStyle getWebKitStyle() {
return Style;
}
-bool getPredefinedStyle(StringRef Name, FormatStyle *Style) {
- if (Name.equals_lower("llvm"))
+bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
+ FormatStyle *Style) {
+ if (Name.equals_lower("llvm")) {
*Style = getLLVMStyle();
- else if (Name.equals_lower("chromium"))
+ } else if (Name.equals_lower("chromium")) {
*Style = getChromiumStyle();
- else if (Name.equals_lower("mozilla"))
+ } else if (Name.equals_lower("mozilla")) {
*Style = getMozillaStyle();
- else if (Name.equals_lower("google"))
- *Style = getGoogleStyle();
- else if (Name.equals_lower("webkit"))
+ } else if (Name.equals_lower("google")) {
+ *Style = Language == FormatStyle::LK_JavaScript ? getGoogleJSStyle()
+ : getGoogleStyle();
+ } else if (Name.equals_lower("webkit")) {
*Style = getWebKitStyle();
- else
+ } else {
return false;
+ }
+ Style->Language = Language;
return true;
}
llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
assert(Style);
- assert(Style->Language != FormatStyle::LK_None);
+ FormatStyle::LanguageKind Language = Style->Language;
+ assert(Language != FormatStyle::LK_None);
if (Text.trim().empty())
return llvm::make_error_code(llvm::errc::invalid_argument);
std::vector<FormatStyle> Styles;
- // DocumentListTraits<vector<FormatStyle>> uses 0th element as the default one
- // for the fields, keys for which are missing from the configuration.
- Styles.push_back(*Style);
llvm::yaml::Input Input(Text);
+ // DocumentListTraits<vector<FormatStyle>> uses the context to get default
+ // values for the fields, keys for which are missing from the configuration.
+ // Mapping also uses the context to get the language to find the correct
+ // base style.
+ Input.setContext(Style);
Input >> Styles;
if (Input.error())
return Input.error();
- for (unsigned i = 1; i < Styles.size(); ++i) {
+ for (unsigned i = 0; i < Styles.size(); ++i) {
// Ensures that only the first configuration can skip the Language option.
- if (Styles[i].Language == FormatStyle::LK_None && i != 1)
+ if (Styles[i].Language == FormatStyle::LK_None && i != 0)
return llvm::make_error_code(llvm::errc::invalid_argument);
// Ensure that each language is configured at most once.
- for (unsigned j = 1; j < i; ++j) {
- if (Styles[i].Language == Styles[j].Language)
+ for (unsigned j = 0; j < i; ++j) {
+ if (Styles[i].Language == Styles[j].Language) {
+ DEBUG(llvm::dbgs()
+ << "Duplicate languages in the config file on positions " << j
+ << " and " << i << "\n");
return llvm::make_error_code(llvm::errc::invalid_argument);
+ }
}
}
// Look for a suitable configuration starting from the end, so we can
// find the configuration for the specific language first, and the default
- // configuration (which can only be at slot 1) after it.
- for (unsigned i = Styles.size() - 1; i > 0; --i) {
- if (Styles[i].Language == Styles[0].Language ||
+ // configuration (which can only be at slot 0) after it.
+ for (int i = Styles.size() - 1; i >= 0; --i) {
+ if (Styles[i].Language == Language ||
Styles[i].Language == FormatStyle::LK_None) {
*Style = Styles[i];
- Style->Language = Styles[0].Language;
+ Style->Language = Language;
return llvm::make_error_code(llvm::errc::success);
}
}
@@ -1667,28 +1690,22 @@ const char *StyleOptionHelpDescription =
"parameters, e.g.:\n"
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
-static void fillLanguageByFileName(StringRef FileName, FormatStyle *Style) {
- if (FileName.endswith_lower(".c") || FileName.endswith_lower(".h") ||
- FileName.endswith_lower(".cpp") || FileName.endswith_lower(".hpp") ||
- FileName.endswith_lower(".cc") || FileName.endswith_lower(".hh") ||
- FileName.endswith_lower(".cxx") || FileName.endswith_lower(".hxx") ||
- FileName.endswith_lower(".m") || FileName.endswith_lower(".mm")) {
- Style->Language = FormatStyle::LK_Cpp;
- }
+static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
if (FileName.endswith_lower(".js")) {
- Style->Language = FormatStyle::LK_JavaScript;
+ return FormatStyle::LK_JavaScript;
}
+ return FormatStyle::LK_Cpp;
}
FormatStyle getStyle(StringRef StyleName, StringRef FileName,
StringRef FallbackStyle) {
- FormatStyle Style;
- if (!getPredefinedStyle(FallbackStyle, &Style)) {
+ FormatStyle Style = getLLVMStyle();
+ Style.Language = getLanguageByFileName(FileName);
+ if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) {
llvm::errs() << "Invalid fallback style \"" << FallbackStyle
<< "\" using LLVM style\n";
- return getLLVMStyle();
+ return Style;
}
- fillLanguageByFileName(FileName, &Style);
if (StyleName.startswith("{")) {
// Parse YAML/JSON style from the command line.
@@ -1700,13 +1717,13 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName,
}
if (!StyleName.equals_lower("file")) {
- if (!getPredefinedStyle(StyleName, &Style))
+ if (!getPredefinedStyle(StyleName, Style.Language, &Style))
llvm::errs() << "Invalid value for -style, using " << FallbackStyle
<< " style\n";
- fillLanguageByFileName(FileName, &Style);
return Style;
}
+ // Look for .clang-format/_clang-format file in the file's parent directories.
SmallString<128> UnsuitableConfigFiles;
SmallString<128> Path(FileName);
llvm::sys::fs::make_absolute(Path);
OpenPOWER on IntegriCloud