fodinabor created this revision.
fodinabor added reviewers: bkramer, djasper, klimek.
Herald added subscribers: llvm-commits, cfe-commits, hiraditya.
Herald added projects: clang, LLVM.
fodinabor requested review of this revision.

Currently newer clang-format options cannot be included in .clang-format files, 
if not all users can be forced to use an updated version.
This patch tries to solve this by adding an option to clang-format, enabling to 
ignore unknown (newer) options.

As this is my first LLVM patch, I'm expecting to get some things wrong and are 
happy to receive any feedback!
E.g.: I haven't found how to update the clang-format help page yet. Is it auto 
generated?
Also if you have any suggestions on whom to ask wrt review, please add them.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D86137

Files:
  clang/include/clang/Format/Format.h
  clang/lib/Format/Format.cpp
  clang/tools/clang-format/ClangFormat.cpp
  llvm/include/llvm/Support/YAMLTraits.h
  llvm/lib/Support/YAMLTraits.cpp

Index: llvm/lib/Support/YAMLTraits.cpp
===================================================================
--- llvm/lib/Support/YAMLTraits.cpp
+++ llvm/lib/Support/YAMLTraits.cpp
@@ -195,6 +195,8 @@
   MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
   if (!MN)
     return;
+  if (IgnoreUnkown)
+    return;
   for (const auto &NN : MN->Mapping) {
     if (!is_contained(MN->ValidKeys, NN.first())) {
       setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'");
@@ -428,6 +430,8 @@
   setError(CurrentNode, Message);
 }
 
+void Input::setIgnoreUnknown(bool Value) { IgnoreUnkown = Value; }
+
 bool Input::canElideEmptySequence() {
   return false;
 }
@@ -735,6 +739,8 @@
 void Output::setError(const Twine &message) {
 }
 
+void Output::setIgnoreUnknown(bool Value) {}
+
 bool Output::canElideEmptySequence() {
   // Normally, with an optional key/value where the value is an empty sequence,
   // the whole key/value can be not written.  But, that produces wrong yaml
Index: llvm/include/llvm/Support/YAMLTraits.h
===================================================================
--- llvm/include/llvm/Support/YAMLTraits.h
+++ llvm/include/llvm/Support/YAMLTraits.h
@@ -789,6 +789,7 @@
   virtual NodeKind getNodeKind() = 0;
 
   virtual void setError(const Twine &) = 0;
+  virtual void setIgnoreUnknown(bool) = 0;
 
   template <typename T>
   void enumCase(T &Val, const char* Str, const T ConstVal) {
@@ -1504,6 +1505,8 @@
   /// Returns the current node that's being parsed by the YAML Parser.
   const Node *getCurrentNode() const;
 
+  void setIgnoreUnknown(bool) override;
+
 private:
   SourceMgr                           SrcMgr; // must be before Strm
   std::unique_ptr<llvm::yaml::Stream> Strm;
@@ -1514,6 +1517,7 @@
   std::vector<bool>                   BitValuesUsed;
   HNode *CurrentNode = nullptr;
   bool                                ScalarMatchFound = false;
+  bool IgnoreUnkown = false;
 };
 
 ///
@@ -1561,6 +1565,7 @@
   void scalarTag(std::string &) override;
   NodeKind getNodeKind() override;
   void setError(const Twine &message) override;
+  void setIgnoreUnknown(bool) override;
   bool canElideEmptySequence() override;
 
   // These are only used by operator<<. They could be private
Index: clang/tools/clang-format/ClangFormat.cpp
===================================================================
--- clang/tools/clang-format/ClangFormat.cpp
+++ clang/tools/clang-format/ClangFormat.cpp
@@ -104,6 +104,11 @@
              "SortIncludes style flag"),
     cl::cat(ClangFormatCategory));
 
+static cl::opt<bool>
+    IgnoreUnkownOptions("ignore-unknown-options",
+                        cl::desc("If set, unknown format options are ignored."),
+                        cl::init(false), cl::cat(ClangFormatCategory));
+
 static cl::opt<bool>
     Verbose("verbose", cl::desc("If set, shows the list of processed files"),
             cl::cat(ClangFormatCategory));
@@ -378,7 +383,8 @@
   }
 
   llvm::Expected<FormatStyle> FormatStyle =
-      getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer());
+      getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
+               nullptr, IgnoreUnkownOptions.getValue());
   if (!FormatStyle) {
     llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
     return true;
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -1288,7 +1288,8 @@
   return true;
 }
 
-std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
+std::error_code parseConfiguration(StringRef Text, FormatStyle *Style,
+                                   bool IgnoreUnknownOptions) {
   assert(Style);
   FormatStyle::LanguageKind Language = Style->Language;
   assert(Language != FormatStyle::LK_None);
@@ -1302,6 +1303,7 @@
   // Mapping also uses the context to get the language to find the correct
   // base style.
   Input.setContext(Style);
+  Input.setIgnoreUnknown(IgnoreUnknownOptions);
   Input >> Styles;
   if (Input.error())
     return Input.error();
@@ -2800,8 +2802,8 @@
 
 llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
                                      StringRef FallbackStyleName,
-                                     StringRef Code,
-                                     llvm::vfs::FileSystem *FS) {
+                                     StringRef Code, llvm::vfs::FileSystem *FS,
+                                     bool IgnoreUnknownOptions) {
   if (!FS) {
     FS = llvm::vfs::getRealFileSystem().get();
   }
@@ -2813,7 +2815,8 @@
 
   if (StyleName.startswith("{")) {
     // Parse YAML/JSON style from the command line.
-    if (std::error_code ec = parseConfiguration(StyleName, &Style))
+    if (std::error_code ec =
+            parseConfiguration(StyleName, &Style, IgnoreUnknownOptions))
       return make_string_error("Error parsing -style: " + ec.message());
     return Style;
   }
@@ -2857,8 +2860,8 @@
             FS->getBufferForFile(ConfigFile.str());
         if (std::error_code EC = Text.getError())
           return make_string_error(EC.message());
-        if (std::error_code ec =
-                parseConfiguration(Text.get()->getBuffer(), &Style)) {
+        if (std::error_code ec = parseConfiguration(
+                Text.get()->getBuffer(), &Style, IgnoreUnknownOptions)) {
           if (ec == ParseError::Unsuitable) {
             if (!UnsuitableConfigFiles.empty())
               UnsuitableConfigFiles.append(", ");
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -2478,7 +2478,8 @@
 private:
   FormatStyleSet StyleSet;
 
-  friend std::error_code parseConfiguration(StringRef Text, FormatStyle *Style);
+  friend std::error_code parseConfiguration(StringRef Text, FormatStyle *Style,
+                                            bool IgnoreUnknownOptions);
 };
 
 /// Returns a format style complying with the LLVM coding standards:
@@ -2533,7 +2534,11 @@
 ///
 /// When ``BasedOnStyle`` is not present, options not present in the YAML
 /// document, are retained in \p Style.
-std::error_code parseConfiguration(StringRef Text, FormatStyle *Style);
+///
+/// If IgnoreUnknownOptions is true, no errors are emitted if unknown
+/// format options are occured.
+std::error_code parseConfiguration(StringRef Text, FormatStyle *Style,
+                                   bool IgnoreUnknownOptions = false);
 
 /// Gets configuration in a YAML string.
 std::string configurationAsText(const FormatStyle &Style);
@@ -2670,6 +2675,8 @@
 /// language if the filename isn't sufficient.
 /// \param[in] FS The underlying file system, in which the file resides. By
 /// default, the file system is the real file system.
+/// \param[in] IgnoreUnknownOptions If true, unknown format options are ignored.
+///             If false, errors are emitted on unknown format options.
 ///
 /// \returns FormatStyle as specified by ``StyleName``. If ``StyleName`` is
 /// "file" and no file is found, returns ``FallbackStyle``. If no style could be
@@ -2677,7 +2684,8 @@
 llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
                                      StringRef FallbackStyle,
                                      StringRef Code = "",
-                                     llvm::vfs::FileSystem *FS = nullptr);
+                                     llvm::vfs::FileSystem *FS = nullptr,
+                                     bool IgnoreUnknownOptions = false);
 
 // Guesses the language from the ``FileName`` and ``Code`` to be formatted.
 // Defaults to FormatStyle::LK_Cpp.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to