<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Dec 1, 2013 at 12:26 AM, Nico Weber <span dir="ltr"><<a href="mailto:thakis@chromium.org" target="_blank" class="cremed">thakis@chromium.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">unittests/Format/FormatTest.cpp is pretty large by now. Should js-specific tests maybe go into a new file?<br>
</div></blockquote><div><br></div><div>Sounds like a good idea to me. </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
<div class="gmail_extra"><div class="gmail_quote">On Sat, Nov 30, 2013 at 12:19 AM, Alexander Kornienko <span dir="ltr"><<a href="mailto:alexfh@google.com" target="_blank" class="cremed">alexfh@google.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: alexfh<br>
Date: Fri Nov 29 09:19:43 2013<br>
New Revision: 195961<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=195961&view=rev" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project?rev=195961&view=rev</a><br>
Log:<br>
Added LanguageStandard::LS_JavaScript to gate all JS-specific parsing.<br>
<br>
Summary:<br>
Use LS_JavaScript for files ending with ".js". Added support for ">>>="<br>
operator.<br>
<br>
Reviewers: djasper, klimek<br>
<br>
Reviewed By: djasper<br>
<br>
CC: cfe-commits, klimek<br>
<br>
Differential Revision: <a href="http://llvm-reviews.chandlerc.com/D2242" target="_blank" class="cremed">http://llvm-reviews.chandlerc.com/D2242</a><br>
<br>
Added:<br>
    cfe/trunk/test/Format/language-detection.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/Format/Format.h<br>
    cfe/trunk/lib/Format/Format.cpp<br>
    cfe/trunk/unittests/Format/FormatTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Format/Format.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=195961&r1=195960&r2=195961&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=195961&r1=195960&r2=195961&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/include/clang/Format/Format.h (original)<br>
+++ cfe/trunk/include/clang/Format/Format.h Fri Nov 29 09:19:43 2013<br>
@@ -30,6 +30,21 @@ namespace format {<br>
 /// \brief The \c FormatStyle is used to configure the formatting to follow<br>
 /// specific guidelines.<br>
 struct FormatStyle {<br>
+  /// \brief Supported languages. When stored in a configuration file, specifies<br>
+  /// the language, that the configuration targets. When passed to the<br>
+  /// reformat() function, enables syntax features specific to the language.<br>
+  enum LanguageKind {<br>
+    /// Do not use.<br>
+    LK_None,<br>
+    /// Should be used for C, C++, ObjectiveC, ObjectiveC++.<br>
+    LK_Cpp,<br>
+    /// Should be used for JavaScript.<br>
+    LK_JavaScript<br>
+  };<br>
+<br>
+  /// \brief Language, this format style is targeted at.<br>
+  LanguageKind Language;<br>
+<br>
   /// \brief The column limit.<br>
   ///<br>
   /// A column limit of \c 0 means that there is no column limit. In this case,<br>
@@ -283,7 +298,7 @@ struct FormatStyle {<br>
            IndentCaseLabels == R.IndentCaseLabels &&<br>
            IndentFunctionDeclarationAfterType ==<br>
                R.IndentFunctionDeclarationAfterType &&<br>
-           IndentWidth == R.IndentWidth &&<br>
+           IndentWidth == R.IndentWidth && Language == R.Language &&<br>
            MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&<br>
            NamespaceIndentation == R.NamespaceIndentation &&<br>
            ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&<br>
<br>
Modified: cfe/trunk/lib/Format/Format.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=195961&r1=195960&r2=195961&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=195961&r1=195960&r2=195961&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/Format/Format.cpp (original)<br>
+++ cfe/trunk/lib/Format/Format.cpp Fri Nov 29 09:19:43 2013<br>
@@ -34,6 +34,15 @@<br>
 namespace llvm {<br>
 namespace yaml {<br>
 template <><br>
+struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageKind> {<br>
+  static void enumeration(IO &IO,<br>
+                          clang::format::FormatStyle::LanguageKind &Value) {<br>
+    IO.enumCase(Value, "Cpp", clang::format::FormatStyle::LK_Cpp);<br>
+    IO.enumCase(Value, "JavaScript", clang::format::FormatStyle::LK_JavaScript);<br>
+  }<br>
+};<br>
+<br>
+template <><br>
 struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> {<br>
   static void enumeration(IO &IO,<br>
                           clang::format::FormatStyle::LanguageStandard &Value) {<br>
@@ -99,13 +108,17 @@ template <> struct MappingTraits<clang::<br>
     } else {<br>
       StringRef BasedOnStyle;<br>
       IO.mapOptional("BasedOnStyle", BasedOnStyle);<br>
-      if (!BasedOnStyle.empty())<br>
+      if (!BasedOnStyle.empty()) {<br>
+        clang::format::FormatStyle::LanguageKind Language = Style.Language;<br>
         if (!clang::format::getPredefinedStyle(BasedOnStyle, &Style)) {<br>
           IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));<br>
           return;<br>
         }<br>
+        Style.Language = Language;<br>
+      }<br>
     }<br>
<br>
+    IO.mapOptional("Language", Style.Language);<br>
     IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);<br>
     IO.mapOptional("ConstructorInitializerIndentWidth",<br>
                    Style.ConstructorInitializerIndentWidth);<br>
@@ -173,6 +186,36 @@ template <> struct MappingTraits<clang::<br>
     IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);<br>
   }<br>
 };<br>
+<br>
+// Allows to read vector<FormatStyle> while keeping default values.<br>
+// Elements will be written or read starting from the 1st element.<br>
+// When writing, the 0th element is ignored.<br>
+// When reading, keys that are not present in the serialized form will be<br>
+// copied from the 0th element of the vector. If the first element had no<br>
+// Language specified, it will be treated as the default one for the following<br>
+// elements.<br>
+template <><br>
+struct DocumentListTraits<std::vector<clang::format::FormatStyle> > {<br>
+  static size_t size(IO &io, std::vector<clang::format::FormatStyle> &Seq) {<br>
+    return Seq.size() - 1;<br>
+  }<br>
+  static clang::format::FormatStyle &<br>
+  element(IO &io, std::vector<clang::format::FormatStyle> &Seq, size_t Index) {<br>
+    if (Index + 2 > Seq.size()) {<br>
+      assert(Index + 2 == Seq.size() + 1);<br>
+      clang::format::FormatStyle Template;<br>
+      if (Seq.size() > 1 &&<br>
+          Seq[1].Language == clang::format::FormatStyle::LK_None) {<br>
+        Template = Seq[1];<br>
+      } else {<br>
+        Template = Seq[0];<br>
+        Template.Language = clang::format::FormatStyle::LK_None;<br>
+      }<br>
+      Seq.resize(Index + 2, Template);<br>
+    }<br>
+    return Seq[Index + 1];<br>
+  }<br>
+};<br>
 }<br>
 }<br>
<br>
@@ -188,6 +231,7 @@ void setDefaultPenalties(FormatStyle &St<br>
<br>
 FormatStyle getLLVMStyle() {<br>
   FormatStyle LLVMStyle;<br>
+  LLVMStyle.Language = FormatStyle::LK_Cpp;<br>
   LLVMStyle.AccessModifierOffset = -2;<br>
   LLVMStyle.AlignEscapedNewlinesLeft = false;<br>
   LLVMStyle.AlignTrailingComments = true;<br>
@@ -236,6 +280,7 @@ FormatStyle getLLVMStyle() {<br>
<br>
 FormatStyle getGoogleStyle() {<br>
   FormatStyle GoogleStyle;<br>
+  GoogleStyle.Language = FormatStyle::LK_Cpp;<br>
   GoogleStyle.AccessModifierOffset = -1;<br>
   GoogleStyle.AlignEscapedNewlinesLeft = true;<br>
   GoogleStyle.AlignTrailingComments = true;<br>
@@ -337,11 +382,42 @@ bool getPredefinedStyle(StringRef Name,<br>
 }<br>
<br>
 llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {<br>
+  assert(Style);<br>
+  assert(Style->Language != FormatStyle::LK_None);<br>
   if (Text.trim().empty())<br>
     return llvm::make_error_code(llvm::errc::invalid_argument);<br>
+<br>
+  std::vector<FormatStyle> Styles;<br>
+  // DocumentListTraits<vector<FormatStyle>> uses 0th element as the default one<br>
+  // for the fields, keys for which are missing from the configuration.<br>
+  Styles.push_back(*Style);<br>
   llvm::yaml::Input Input(Text);<br>
-  Input >> *Style;<br>
-  return Input.error();<br>
+  Input >> Styles;<br>
+  if (Input.error())<br>
+    return Input.error();<br>
+<br>
+  for (unsigned i = 1; i < Styles.size(); ++i) {<br>
+    // Ensures that only the first configuration can skip the Language option.<br>
+    if (Styles[i].Language == FormatStyle::LK_None && i != 1)<br>
+      return llvm::make_error_code(llvm::errc::invalid_argument);<br>
+    // Ensure that each language is configured at most once.<br>
+    for (unsigned j = 1; j < i; ++j) {<br>
+      if (Styles[i].Language == Styles[j].Language)<br>
+        return llvm::make_error_code(llvm::errc::invalid_argument);<br>
+    }<br>
+  }<br>
+  // Look for a suitable configuration starting from the end, so we can<br>
+  // find the configuration for the specific language first, and the default<br>
+  // configuration (which can only be at slot 1) after it.<br>
+  for (unsigned i = Styles.size() - 1; i > 0; --i) {<br>
+    if (Styles[i].Language == Styles[0].Language ||<br>
+        Styles[i].Language == FormatStyle::LK_None) {<br>
+      *Style = Styles[i];<br>
+      Style->Language = Styles[0].Language;<br>
+      return llvm::make_error_code(llvm::errc::success);<br>
+    }<br>
+  }<br>
+  return llvm::make_error_code(llvm::errc::not_supported);<br>
 }<br>
<br>
 std::string configurationAsText(const FormatStyle &Style) {<br>
@@ -986,24 +1062,44 @@ public:<br>
<br>
 private:<br>
   void tryMergePreviousTokens() {<br>
-    tryMerge_TMacro() || tryMergeJavaScriptIdentityOperators();<br>
+    if (tryMerge_TMacro())<br>
+      return;<br>
+<br>
+    if (Style.Language == FormatStyle::LK_JavaScript) {<br>
+      static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };<br>
+      static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal };<br>
+      static tok::TokenKind JSShiftEqual[] = { tok::greater, tok::greater,<br>
+                                               tok::greaterequal };<br>
+      // FIXME: We probably need to change token type to mimic operator with the<br>
+      // correct priority.<br>
+      if (tryMergeTokens(JSIdentity))<br>
+        return;<br>
+      if (tryMergeTokens(JSNotIdentity))<br>
+        return;<br>
+      if (tryMergeTokens(JSShiftEqual))<br>
+        return;<br>
+    }<br>
   }<br>
<br>
-  bool tryMergeJavaScriptIdentityOperators() {<br>
-    if (Tokens.size() < 2)<br>
-      return false;<br>
-    FormatToken &First = *Tokens[Tokens.size() - 2];<br>
-    if (!First.isOneOf(tok::exclaimequal, tok::equalequal))<br>
+  bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds) {<br>
+    if (Tokens.size() < Kinds.size())<br>
       return false;<br>
-    FormatToken &Second = *Tokens.back();<br>
-    if (!Second.is(tok::equal))<br>
-      return false;<br>
-    if (Second.WhitespaceRange.getBegin() != Second.WhitespaceRange.getEnd())<br>
+<br>
+    SmallVectorImpl<FormatToken *>::const_iterator First =<br>
+        Tokens.end() - Kinds.size();<br>
+    if (!First[0]->is(Kinds[0]))<br>
       return false;<br>
-    First.TokenText =<br>
-        StringRef(First.TokenText.data(), First.TokenText.size() + 1);<br>
-    First.ColumnWidth += 1;<br>
-    Tokens.pop_back();<br>
+    unsigned AddLength = 0;<br>
+    for (unsigned i = 1; i < Kinds.size(); ++i) {<br>
+      if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=<br>
+                                         First[i]->WhitespaceRange.getEnd())<br>
+        return false;<br>
+      AddLength += First[i]->TokenText.size();<br>
+    }<br>
+    Tokens.resize(Tokens.size() - Kinds.size() + 1);<br>
+    First[0]->TokenText = StringRef(First[0]->TokenText.data(),<br>
+                                    First[0]->TokenText.size() + AddLength);<br>
+    First[0]->ColumnWidth += AddLength;<br>
     return true;<br>
   }<br>
<br>
@@ -1201,6 +1297,17 @@ private:<br>
   }<br>
 };<br>
<br>
+static StringRef getLanguageName(FormatStyle::LanguageKind Language) {<br>
+  switch (Language) {<br>
+  case FormatStyle::LK_Cpp:<br>
+    return "C++";<br>
+  case FormatStyle::LK_JavaScript:<br>
+    return "JavaScript";<br>
+  default:<br>
+    return "Unknown";<br>
+  }<br>
+}<br>
+<br>
 class Formatter : public UnwrappedLineConsumer {<br>
 public:<br>
   Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,<br>
@@ -1213,6 +1320,8 @@ public:<br>
                        << (Encoding == encoding::Encoding_UTF8 ? "UTF8"<br>
                                                                : "unknown")<br>
                        << "\n");<br>
+    DEBUG(llvm::dbgs() << "Language: " << getLanguageName(Style.Language)<br>
+                       << "\n");<br>
   }<br>
<br>
   tooling::Replacements format() {<br>
@@ -1538,11 +1647,26 @@ const char *StyleOptionHelpDescription =<br>
     "parameters, e.g.:\n"<br>
     "  -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";<br>
<br>
+static void fillLanguageByFileName(StringRef FileName, FormatStyle *Style) {<br>
+  if (FileName.endswith_lower(".c") || FileName.endswith_lower(".h") ||<br>
+      FileName.endswith_lower(".cpp") || FileName.endswith_lower(".hpp") ||<br>
+      FileName.endswith_lower(".cc") || FileName.endswith_lower(".hh") ||<br>
+      FileName.endswith_lower(".cxx") || FileName.endswith_lower(".hxx") ||<br>
+      FileName.endswith_lower(".m") || FileName.endswith_lower(".mm")) {<br>
+    Style->Language = FormatStyle::LK_Cpp;<br>
+  }<br>
+  if (FileName.endswith_lower(".js")) {<br>
+    Style->Language = FormatStyle::LK_JavaScript;<br>
+  }<br>
+}<br>
+<br>
 FormatStyle getStyle(StringRef StyleName, StringRef FileName) {<br>
+  // FIXME: Configure fallback style from outside (add a command line option).<br>
   // Fallback style in case the rest of this function can't determine a style.<br>
   StringRef FallbackStyle = "LLVM";<br>
   FormatStyle Style;<br>
   getPredefinedStyle(FallbackStyle, &Style);<br>
+  fillLanguageByFileName(FileName, &Style);<br>
<br>
   if (StyleName.startswith("{")) {<br>
     // Parse YAML/JSON style from the command line.<br>
@@ -1557,9 +1681,11 @@ FormatStyle getStyle(StringRef StyleName<br>
     if (!getPredefinedStyle(StyleName, &Style))<br>
       llvm::errs() << "Invalid value for -style, using " << FallbackStyle<br>
                    << " style\n";<br>
+    fillLanguageByFileName(FileName, &Style);<br>
     return Style;<br>
   }<br>
<br>
+  SmallString<128> UnsuitableConfigFiles;<br>
   SmallString<128> Path(FileName);<br>
   llvm::sys::fs::make_absolute(Path);<br>
   for (StringRef Directory = Path; !Directory.empty();<br>
@@ -1591,8 +1717,14 @@ FormatStyle getStyle(StringRef StyleName<br>
         continue;<br>
       }<br>
       if (llvm::error_code ec = parseConfiguration(Text->getBuffer(), &Style)) {<br>
-        llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()<br>
-                     << "\n";<br>
+        if (ec == llvm::errc::not_supported) {<br>
+          if (!UnsuitableConfigFiles.empty())<br>
+            UnsuitableConfigFiles.append(", ");<br>
+          UnsuitableConfigFiles.append(ConfigFile);<br>
+        } else {<br>
+          llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()<br>
+                       << "\n";<br>
+        }<br>
         continue;<br>
       }<br>
       DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");<br>
@@ -1601,6 +1733,11 @@ FormatStyle getStyle(StringRef StyleName<br>
   }<br>
   llvm::errs() << "Can't find usable .clang-format, using " << FallbackStyle<br>
                << " style\n";<br>
+  if (!UnsuitableConfigFiles.empty()) {<br>
+    llvm::errs() << "Configuration file(s) do(es) not support "<br>
+                 << getLanguageName(Style.Language) << ": "<br>
+                 << UnsuitableConfigFiles << "\n";<br>
+  }<br>
   return Style;<br>
 }<br>
<br>
<br>
Added: cfe/trunk/test/Format/language-detection.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Format/language-detection.cpp?rev=195961&view=auto" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Format/language-detection.cpp?rev=195961&view=auto</a><br>


==============================================================================<br>
--- cfe/trunk/test/Format/language-detection.cpp (added)<br>
+++ cfe/trunk/test/Format/language-detection.cpp Fri Nov 29 09:19:43 2013<br>
@@ -0,0 +1,7 @@<br>
+// RUN: grep -Ev "// *[A-Z0-9_]+:" %s > %t.js<br>
+// RUN: grep -Ev "// *[A-Z0-9_]+:" %s > %t.cpp<br>
+// RUN: clang-format -style=llvm %t.js | FileCheck -strict-whitespace -check-prefix=CHECK1 %s<br>
+// RUN: clang-format -style=llvm %t.cpp | FileCheck -strict-whitespace -check-prefix=CHECK2 %s<br>
+// CHECK1: {{^a >>>= b;$}}<br>
+// CHECK2: {{^a >> >= b;$}}<br>
+a >>>= b;<br>
<br>
Modified: cfe/trunk/unittests/Format/FormatTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=195961&r1=195960&r2=195961&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=195961&r1=195960&r2=195961&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)<br>
+++ cfe/trunk/unittests/Format/FormatTest.cpp Fri Nov 29 09:19:43 2013<br>
@@ -6939,8 +6939,6 @@ TEST_F(FormatTest, GetsPredefinedStyleBy<br>
   EXPECT_FALSE(getPredefinedStyle("qwerty", &Styles[0]));<br>
 }<br>
<br>
-TEST_F(FormatTest, ParsesConfiguration) {<br>
-  FormatStyle Style = {};<br>
 #define CHECK_PARSE(TEXT, FIELD, VALUE)                                        \<br>
   EXPECT_NE(VALUE, Style.FIELD);                                               \<br>
   EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value());                      \<br>
@@ -6953,6 +6951,9 @@ TEST_F(FormatTest, ParsesConfiguration)<br>
   EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value());          \<br>
   EXPECT_FALSE(Style.FIELD);<br>
<br>
+TEST_F(FormatTest, ParsesConfiguration) {<br>
+  FormatStyle Style = {};<br>
+  Style.Language = FormatStyle::LK_Cpp;<br>
   CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);<br>
   CHECK_PARSE_BOOL(AlignTrailingComments);<br>
   CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);<br>
@@ -7027,15 +7028,117 @@ TEST_F(FormatTest, ParsesConfiguration)<br>
               FormatStyle::NI_Inner);<br>
   CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,<br>
               FormatStyle::NI_All);<br>
+}<br>
+<br>
+TEST_F(FormatTest, ParsesConfigurationWithLanguages) {<br>
+  FormatStyle Style = {};<br>
+  Style.Language = FormatStyle::LK_Cpp;<br>
+  CHECK_PARSE("Language: Cpp\n"<br>
+              "IndentWidth: 12",<br>
+              IndentWidth, 12u);<br>
+  EXPECT_EQ(llvm::errc::not_supported,<br>
+            parseConfiguration("Language: JavaScript\n"<br>
+                               "IndentWidth: 34",<br>
+                               &Style));<br>
+  EXPECT_EQ(12u, Style.IndentWidth);<br>
+  CHECK_PARSE("IndentWidth: 56", IndentWidth, 56u);<br>
+  EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);<br>
+<br>
+  Style.Language = FormatStyle::LK_JavaScript;<br>
+  CHECK_PARSE("Language: JavaScript\n"<br>
+              "IndentWidth: 12",<br>
+              IndentWidth, 12u);<br>
+  CHECK_PARSE("IndentWidth: 23", IndentWidth, 23u);<br>
+  EXPECT_EQ(llvm::errc::not_supported, parseConfiguration("Language: Cpp\n"<br>
+                                                          "IndentWidth: 34",<br>
+                                                          &Style));<br>
+  EXPECT_EQ(23u, Style.IndentWidth);<br>
+  CHECK_PARSE("IndentWidth: 56", IndentWidth, 56u);<br>
+  EXPECT_EQ(FormatStyle::LK_JavaScript, Style.Language);<br>
+<br>
+  CHECK_PARSE("BasedOnStyle: LLVM\n"<br>
+              "IndentWidth: 67",<br>
+              IndentWidth, 67u);<br>
+<br>
+  CHECK_PARSE("---\n"<br>
+              "Language: JavaScript\n"<br>
+              "IndentWidth: 12\n"<br>
+              "---\n"<br>
+              "Language: Cpp\n"<br>
+              "IndentWidth: 34\n"<br>
+              "...\n",<br>
+              IndentWidth, 12u);<br>
+<br>
+  Style.Language = FormatStyle::LK_Cpp;<br>
+  CHECK_PARSE("---\n"<br>
+              "Language: JavaScript\n"<br>
+              "IndentWidth: 12\n"<br>
+              "---\n"<br>
+              "Language: Cpp\n"<br>
+              "IndentWidth: 34\n"<br>
+              "...\n",<br>
+              IndentWidth, 34u);<br>
+  CHECK_PARSE("---\n"<br>
+              "IndentWidth: 78\n"<br>
+              "---\n"<br>
+              "Language: JavaScript\n"<br>
+              "IndentWidth: 56\n"<br>
+              "...\n",<br>
+              IndentWidth, 78u);<br>
+<br>
+  Style.ColumnLimit = 123;<br>
+  Style.IndentWidth = 234;<br>
+  Style.BreakBeforeBraces = FormatStyle::BS_Linux;<br>
+  Style.TabWidth = 345;<br>
+  EXPECT_EQ(llvm::errc::success,<br>
+            parseConfiguration("---\n"<br>
+                               "IndentWidth: 456\n"<br>
+                               "BreakBeforeBraces: Allman\n"<br>
+                               "---\n"<br>
+                               "Language: JavaScript\n"<br>
+                               "IndentWidth: 111\n"<br>
+                               "TabWidth: 111\n"<br>
+                               "---\n"<br>
+                               "Language: Cpp\n"<br>
+                               "BreakBeforeBraces: Stroustrup\n"<br>
+                               "TabWidth: 789\n"<br>
+                               "...\n",<br>
+                               &Style));<br>
+  EXPECT_EQ(123u, Style.ColumnLimit);<br>
+  EXPECT_EQ(456u, Style.IndentWidth);<br>
+  EXPECT_EQ(FormatStyle::BS_Stroustrup, Style.BreakBeforeBraces);<br>
+  EXPECT_EQ(789u, Style.TabWidth);<br>
+<br>
+<br>
+  EXPECT_EQ(llvm::errc::invalid_argument,<br>
+            parseConfiguration("---\n"<br>
+                               "Language: JavaScript\n"<br>
+                               "IndentWidth: 56\n"<br>
+                               "---\n"<br>
+                               "IndentWidth: 78\n"<br>
+                               "...\n",<br>
+                               &Style));<br>
+  EXPECT_EQ(llvm::errc::invalid_argument,<br>
+            parseConfiguration("---\n"<br>
+                               "Language: JavaScript\n"<br>
+                               "IndentWidth: 56\n"<br>
+                               "---\n"<br>
+                               "Language: JavaScript\n"<br>
+                               "IndentWidth: 78\n"<br>
+                               "...\n",<br>
+                               &Style));<br>
+<br>
+  EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);<br>
+}<br>
<br>
 #undef CHECK_PARSE<br>
 #undef CHECK_PARSE_BOOL<br>
-}<br>
<br>
 TEST_F(FormatTest, ConfigurationRoundTripTest) {<br>
   FormatStyle Style = getLLVMStyle();<br>
   std::string YAML = configurationAsText(Style);<br>
   FormatStyle ParsedStyle = {};<br>
+  ParsedStyle.Language = FormatStyle::LK_Cpp;<br>
   EXPECT_EQ(0, parseConfiguration(YAML, &ParsedStyle).value());<br>
   EXPECT_EQ(Style, ParsedStyle);<br>
 }<br>
@@ -7457,18 +7560,36 @@ TEST_F(FormatTest, SpacesInAngles) {<br>
 }<br>
<br>
 TEST_F(FormatTest, UnderstandsJavaScript) {<br>
-  verifyFormat("a == = b;");<br>
-  verifyFormat("a != = b;");<br>
-<br>
-  verifyFormat("a === b;");<br>
-  verifyFormat("aaaaaaa ===\n    b;", getLLVMStyleWithColumns(10));<br>
-  verifyFormat("a !== b;");<br>
-  verifyFormat("aaaaaaa !==\n    b;", getLLVMStyleWithColumns(10));<br>
+  FormatStyle JS = getLLVMStyle();<br>
+  FormatStyle JS10Columns = getLLVMStyleWithColumns(10);<br>
+  FormatStyle JS20Columns = getLLVMStyleWithColumns(20);<br>
+  JS.Language = JS10Columns.Language = JS20Columns.Language =<br>
+      FormatStyle::LK_JavaScript;<br>
+<br>
+  verifyFormat("a == = b;", JS);<br>
+  verifyFormat("a != = b;", JS);<br>
+<br>
+  verifyFormat("a === b;", JS);<br>
+  verifyFormat("aaaaaaa ===\n    b;", JS10Columns);<br>
+  verifyFormat("a !== b;", JS);<br>
+  verifyFormat("aaaaaaa !==\n    b;", JS10Columns);<br>
   verifyFormat("if (a + b + c +\n"<br>
                "        d !==\n"<br>
                "    e + f + g)\n"<br>
                "  q();",<br>
-               getLLVMStyleWithColumns(20));<br>
+               JS20Columns);<br>
+<br>
+  verifyFormat("a >> >= b;", JS);<br>
+<br>
+  verifyFormat("a >>> b;", JS);<br>
+  verifyFormat("aaaaaaa >>>\n    b;", JS10Columns);<br>
+  verifyFormat("a >>>= b;", JS);<br>
+  verifyFormat("aaaaaaa >>>=\n    b;", JS10Columns);<br>
+  verifyFormat("if (a + b + c +\n"<br>
+               "        d >>>\n"<br>
+               "    e + f + g)\n"<br>
+               "  q();",<br>
+               JS20Columns);<br>
 }<br>
<br>
 } // end namespace tooling<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" target="_blank" class="cremed">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank" class="cremed">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" class="cremed">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank" class="cremed">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
<br></blockquote></div><br></div></div>