[clang] f64903f - Add -Wno-error=unknown flag to clang-format.
Joachim Meyer via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 19 01:18:26 PDT 2020
Author: Joachim Meyer
Date: 2020-09-19T10:17:57+02:00
New Revision: f64903fd81764f1fde7aeb00eea5e1d488458f63
URL: https://github.com/llvm/llvm-project/commit/f64903fd81764f1fde7aeb00eea5e1d488458f63
DIFF: https://github.com/llvm/llvm-project/commit/f64903fd81764f1fde7aeb00eea5e1d488458f63.diff
LOG: Add -Wno-error=unknown flag to clang-format.
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.
Differential Revision: https://reviews.llvm.org/D86137
Added:
Modified:
clang/docs/ClangFormat.rst
clang/include/clang/Format/Format.h
clang/lib/Format/Format.cpp
clang/tools/clang-format/ClangFormat.cpp
clang/unittests/Format/FormatTest.cpp
llvm/include/llvm/Support/YAMLParser.h
llvm/include/llvm/Support/YAMLTraits.h
llvm/lib/Support/YAMLParser.cpp
llvm/lib/Support/YAMLTraits.cpp
llvm/unittests/ObjectYAML/YAMLTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst
index b09f48b0027b..d396667ce10c 100644
--- a/clang/docs/ClangFormat.rst
+++ b/clang/docs/ClangFormat.rst
@@ -31,6 +31,12 @@ to format C/C++/Java/JavaScript/Objective-C/Protobuf/C# code.
Clang-format options:
--Werror - If set, changes formatting warnings to errors
+ --Wno-error=unknown - If set, unknown format options are only warned about.
+ This can be used to enable formatting, even if the
+ configuration contains unknown (newer) options.
+ Use with caution, as this might lead to dramatically
+
diff ering format depending on an option being
+ supported or not.
--assume-filename=<string> - Override filename used to determine the language.
When reading from stdin, clang-format assumes this
filename to determine the language.
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 2840a6846018..40d5184f4d0d 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2523,7 +2523,8 @@ struct FormatStyle {
private:
FormatStyleSet StyleSet;
- friend std::error_code parseConfiguration(StringRef Text, FormatStyle *Style);
+ friend std::error_code parseConfiguration(StringRef Text, FormatStyle *Style,
+ bool AllowUnknownOptions);
};
/// Returns a format style complying with the LLVM coding standards:
@@ -2578,7 +2579,11 @@ bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
///
/// 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 AllowUnknownOptions is true, no errors are emitted if unknown
+/// format options are occured.
+std::error_code parseConfiguration(StringRef Text, FormatStyle *Style,
+ bool AllowUnknownOptions = false);
/// Gets configuration in a YAML string.
std::string configurationAsText(const FormatStyle &Style);
@@ -2715,6 +2720,9 @@ extern const char *DefaultFallbackStyle;
/// 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] AllowUnknownOptions If true, unknown format options only
+/// emit a warning. 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
@@ -2722,7 +2730,8 @@ extern const char *DefaultFallbackStyle;
llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
StringRef FallbackStyle,
StringRef Code = "",
- llvm::vfs::FileSystem *FS = nullptr);
+ llvm::vfs::FileSystem *FS = nullptr,
+ bool AllowUnknownOptions = false);
// Guesses the language from the ``FileName`` and ``Code`` to be formatted.
// Defaults to FormatStyle::LK_Cpp.
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 03188b46099d..8e4f65ace3f0 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1301,7 +1301,8 @@ bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
return true;
}
-std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
+std::error_code parseConfiguration(StringRef Text, FormatStyle *Style,
+ bool AllowUnknownOptions) {
assert(Style);
FormatStyle::LanguageKind Language = Style->Language;
assert(Language != FormatStyle::LK_None);
@@ -1315,6 +1316,7 @@ std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
// Mapping also uses the context to get the language to find the correct
// base style.
Input.setContext(Style);
+ Input.setAllowUnknownKeys(AllowUnknownOptions);
Input >> Styles;
if (Input.error())
return Input.error();
@@ -2818,8 +2820,8 @@ const char *DefaultFallbackStyle = "LLVM";
llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
StringRef FallbackStyleName,
- StringRef Code,
- llvm::vfs::FileSystem *FS) {
+ StringRef Code, llvm::vfs::FileSystem *FS,
+ bool AllowUnknownOptions) {
if (!FS) {
FS = llvm::vfs::getRealFileSystem().get();
}
@@ -2831,7 +2833,8 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
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, AllowUnknownOptions))
return make_string_error("Error parsing -style: " + ec.message());
return Style;
}
@@ -2875,8 +2878,8 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
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, AllowUnknownOptions)) {
if (ec == ParseError::Unsuitable) {
if (!UnsuitableConfigFiles.empty())
UnsuitableConfigFiles.append(", ");
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index aa40bab52df5..8dd55d99e2a0 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -104,6 +104,18 @@ static cl::opt<bool> SortIncludes(
"SortIncludes style flag"),
cl::cat(ClangFormatCategory));
+// using the full param name as Wno-error probably won't be a common use case in
+// clang-format
+static cl::opt<bool> AllowUnknownOptions(
+ "Wno-error=unknown",
+ cl::desc("If set, unknown format options are only warned about.\n"
+ "This can be used to enable formatting, even if the\n"
+ "configuration contains unknown (newer) options.\n"
+ "Use with caution, as this might lead to dramatically\n"
+ "
diff ering format depending on an option being\n"
+ "supported or not."),
+ 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 +390,8 @@ static bool format(StringRef FileName) {
}
llvm::Expected<FormatStyle> FormatStyle =
- getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer());
+ getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
+ nullptr, AllowUnknownOptions.getValue());
if (!FormatStyle) {
llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
return true;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index eb72a01d3d27..27e76d40d125 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -16315,9 +16315,12 @@ TEST(FormatStyle, GetStyleOfFile) {
"InvalidKey: InvalidValue")));
ASSERT_TRUE(
FS.addFile("/d/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
- auto Style7 = getStyle("file", "/d/.clang-format", "LLVM", "", &FS);
- ASSERT_FALSE((bool)Style7);
- llvm::consumeError(Style7.takeError());
+ auto Style7a = getStyle("file", "/d/.clang-format", "LLVM", "", &FS);
+ ASSERT_FALSE((bool)Style7a);
+ llvm::consumeError(Style7a.takeError());
+
+ auto Style7b = getStyle("file", "/d/.clang-format", "LLVM", "", &FS, true);
+ ASSERT_TRUE((bool)Style7b);
// Test 8: inferred per-language defaults apply.
auto StyleTd = getStyle("file", "x.td", "llvm", "", &FS);
diff --git a/llvm/include/llvm/Support/YAMLParser.h b/llvm/include/llvm/Support/YAMLParser.h
index 44daf7850904..7baf69eebac9 100644
--- a/llvm/include/llvm/Support/YAMLParser.h
+++ b/llvm/include/llvm/Support/YAMLParser.h
@@ -40,6 +40,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
#include <cassert>
#include <cstddef>
#include <iterator>
@@ -51,7 +52,6 @@
namespace llvm {
class MemoryBufferRef;
-class SourceMgr;
class raw_ostream;
class Twine;
@@ -100,7 +100,8 @@ class Stream {
return !failed();
}
- void printError(Node *N, const Twine &Msg);
+ void printError(Node *N, const Twine &Msg,
+ SourceMgr::DiagKind Kind = SourceMgr::DK_Error);
private:
friend class Document;
diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h
index acb1d61cf569..f32a6ca92d29 100644
--- a/llvm/include/llvm/Support/YAMLTraits.h
+++ b/llvm/include/llvm/Support/YAMLTraits.h
@@ -789,6 +789,7 @@ class IO {
virtual NodeKind getNodeKind() = 0;
virtual void setError(const Twine &) = 0;
+ virtual void setAllowUnknownKeys(bool Allow);
template <typename T>
void enumCase(T &Val, const char* Str, const T ConstVal) {
@@ -1495,6 +1496,9 @@ class Input : public IO {
void setError(HNode *hnode, const Twine &message);
void setError(Node *node, const Twine &message);
+ void reportWarning(HNode *hnode, const Twine &message);
+ void reportWarning(Node *hnode, const Twine &message);
+
public:
// These are only used by operator>>. They could be private
// if those templated things could be made friends.
@@ -1504,6 +1508,8 @@ class Input : public IO {
/// Returns the current node that's being parsed by the YAML Parser.
const Node *getCurrentNode() const;
+ void setAllowUnknownKeys(bool Allow) override;
+
private:
SourceMgr SrcMgr; // must be before Strm
std::unique_ptr<llvm::yaml::Stream> Strm;
@@ -1514,6 +1520,7 @@ class Input : public IO {
std::vector<bool> BitValuesUsed;
HNode *CurrentNode = nullptr;
bool ScalarMatchFound = false;
+ bool AllowUnknownKeys = false;
};
///
diff --git a/llvm/lib/Support/YAMLParser.cpp b/llvm/lib/Support/YAMLParser.cpp
index ca8ffdc47afa..b9bbdc33a433 100644
--- a/llvm/lib/Support/YAMLParser.cpp
+++ b/llvm/lib/Support/YAMLParser.cpp
@@ -1775,12 +1775,9 @@ Stream::~Stream() = default;
bool Stream::failed() { return scanner->failed(); }
-void Stream::printError(Node *N, const Twine &Msg) {
+void Stream::printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind) {
SMRange Range = N ? N->getSourceRange() : SMRange();
- scanner->printError( Range.Start
- , SourceMgr::DK_Error
- , Msg
- , Range);
+ scanner->printError(Range.Start, Kind, Msg, Range);
}
document_iterator Stream::begin() {
diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp
index 9ac7c65e19f7..8a5bb653d7ac 100644
--- a/llvm/lib/Support/YAMLTraits.cpp
+++ b/llvm/lib/Support/YAMLTraits.cpp
@@ -48,6 +48,10 @@ void IO::setContext(void *Context) {
Ctxt = Context;
}
+void IO::setAllowUnknownKeys(bool Allow) {
+ llvm_unreachable("Only supported for Input");
+}
+
//===----------------------------------------------------------------------===//
// Input
//===----------------------------------------------------------------------===//
@@ -197,8 +201,12 @@ void Input::endMapping() {
return;
for (const auto &NN : MN->Mapping) {
if (!is_contained(MN->ValidKeys, NN.first())) {
- setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'");
- break;
+ HNode *ReportNode = NN.second.get();
+ if (!AllowUnknownKeys) {
+ setError(ReportNode, Twine("unknown key '") + NN.first() + "'");
+ break;
+ } else
+ reportWarning(ReportNode, Twine("unknown key '") + NN.first() + "'");
}
}
}
@@ -370,6 +378,11 @@ void Input::setError(Node *node, const Twine &message) {
EC = make_error_code(errc::invalid_argument);
}
+void Input::reportWarning(HNode *hnode, const Twine &message) {
+ assert(hnode && "HNode must not be NULL");
+ Strm->printError(hnode->_node, message, SourceMgr::DK_Warning);
+}
+
std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) {
SmallString<128> StringStorage;
if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) {
@@ -428,6 +441,8 @@ void Input::setError(const Twine &Message) {
setError(CurrentNode, Message);
}
+void Input::setAllowUnknownKeys(bool Allow) { AllowUnknownKeys = Allow; }
+
bool Input::canElideEmptySequence() {
return false;
}
diff --git a/llvm/unittests/ObjectYAML/YAMLTest.cpp b/llvm/unittests/ObjectYAML/YAMLTest.cpp
index 3d283a03b225..53582a987215 100644
--- a/llvm/unittests/ObjectYAML/YAMLTest.cpp
+++ b/llvm/unittests/ObjectYAML/YAMLTest.cpp
@@ -35,3 +35,21 @@ TEST(ObjectYAML, BinaryRef) {
YOut << BH;
EXPECT_NE(OS.str().find("''"), StringRef::npos);
}
+
+TEST(ObjectYAML, UnknownOption) {
+ StringRef InputYAML = "InvalidKey: InvalidValue\n"
+ "Binary: AAAA\n";
+ BinaryHolder BH;
+ yaml::Input Input(InputYAML);
+ // test 1: default in trying to parse invalid key is an error case.
+ Input >> BH;
+ EXPECT_EQ(Input.error().value(), 22);
+
+ // test 2: only warn about invalid key if actively set.
+ yaml::Input Input2(InputYAML);
+ BinaryHolder BH2;
+ Input2.setAllowUnknownKeys(true);
+ Input2 >> BH2;
+ EXPECT_EQ(BH2.Binary, yaml::BinaryRef("AAAA"));
+ EXPECT_EQ(Input2.error().value(), 0);
+}
More information about the cfe-commits
mailing list