On Tue, May 7, 2013 at 11:32 AM, Alexander Kornienko <[email protected]> wrote: > Author: alexfh > Date: Tue May 7 10:32:14 2013 > New Revision: 181326 > > URL: http://llvm.org/viewvc/llvm-project?rev=181326&view=rev > Log: > Config file support for clang-format, part 1. > > Summary: > Added parseConfiguration method, which reads FormatStyle from YAML > string. This supports all FormatStyle fields and an additional BasedOnStyle > field, which can be used to specify base style. > > Reviewers: djasper, klimek > > Reviewed By: djasper > > CC: cfe-commits > > Differential Revision: http://llvm-reviews.chandlerc.com/D754 > > Modified: > cfe/trunk/include/clang/Format/Format.h > cfe/trunk/lib/Format/Format.cpp > cfe/trunk/unittests/Format/FormatTest.cpp > > Modified: cfe/trunk/include/clang/Format/Format.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=181326&r1=181325&r2=181326&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Format/Format.h (original) > +++ cfe/trunk/include/clang/Format/Format.h Tue May 7 10:32:14 2013 > @@ -17,6 +17,7 @@ > > #include "clang/Frontend/FrontendAction.h" > #include "clang/Tooling/Refactoring.h" > +#include "llvm/Support/system_error.h" > > namespace clang { > > @@ -110,6 +111,18 @@ FormatStyle getChromiumStyle(); > /// https://developer.mozilla.org/en-US/docs/Developer_Guide/Coding_Style. > FormatStyle getMozillaStyle(); > > +/// \brief Returns a predefined style by name. > +/// > +/// Currently supported names: LLVM, Google, Chromium, Mozilla. Names are > +/// compared case-insensitively. > +FormatStyle getPredefinedStyle(StringRef Name); > + > +/// \brief Parse configuration from YAML-formatted text. > +llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style); > + > +/// \brief Gets configuration in a YAML string. > +std::string configurationAsText(const FormatStyle &Style); > + > /// \brief Reformats the given \p Ranges in the token stream coming out of > /// \c Lex. > /// > > Modified: cfe/trunk/lib/Format/Format.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=181326&r1=181325&r2=181326&view=diff > ============================================================================== > --- cfe/trunk/lib/Format/Format.cpp (original) > +++ cfe/trunk/lib/Format/Format.cpp Tue May 7 10:32:14 2013 > @@ -28,9 +28,59 @@ > #include "llvm/ADT/STLExtras.h" > #include "llvm/Support/Allocator.h" > #include "llvm/Support/Debug.h" > +#include "llvm/Support/YAMLTraits.h" > #include <queue> > #include <string> > > +namespace llvm { > +namespace yaml { > +template <> > +struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> > { > + static void enumeration(IO &io, > + clang::format::FormatStyle::LanguageStandard > &value) { > + io.enumCase(value, "C++03", clang::format::FormatStyle::LS_Cpp03); > + io.enumCase(value, "C++11", clang::format::FormatStyle::LS_Cpp11); > + io.enumCase(value, "Auto", clang::format::FormatStyle::LS_Auto); > + } > +}; > + > +template <> struct MappingTraits<clang::format::FormatStyle> { > + static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) > { > + if (!IO.outputting()) { > + StringRef BasedOnStyle; > + IO.mapOptional("BasedOnStyle", BasedOnStyle); > + > + if (!BasedOnStyle.empty()) > + Style = clang::format::getPredefinedStyle(BasedOnStyle); > + } > + > + IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset); > + IO.mapOptional("AlignEscapedNewlinesLeft", > Style.AlignEscapedNewlinesLeft); > + IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine", > + Style.AllowAllParametersOfDeclarationOnNextLine); > + IO.mapOptional("AllowShortIfStatementsOnASingleLine", > + Style.AllowShortIfStatementsOnASingleLine); > + IO.mapOptional("BinPackParameters", Style.BinPackParameters); > + IO.mapOptional("ColumnLimit", Style.ColumnLimit); > + IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", > + Style.ConstructorInitializerAllOnOneLineOrOnePerLine); > + IO.mapOptional("DerivePointerBinding", Style.DerivePointerBinding); > + IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); > + IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); > + IO.mapOptional("ObjCSpaceBeforeProtocolList", > + Style.ObjCSpaceBeforeProtocolList); > + IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter); > + IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", > + Style.PenaltyReturnTypeOnItsOwnLine); > + IO.mapOptional("PointerBindsToType", Style.PointerBindsToType); > + IO.mapOptional("SpacesBeforeTrailingComments", > + Style.SpacesBeforeTrailingComments); > + IO.mapOptional("Standard", Style.Standard); > + } > +}; > +} > +} > + > namespace clang { > namespace format { > > @@ -98,6 +148,37 @@ FormatStyle getMozillaStyle() { > return MozillaStyle; > } > > +FormatStyle getPredefinedStyle(StringRef Name) { > + 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(); > + > + llvm::errs() << "Unknown style " << Name << ", using Google style.\n"; > + return getGoogleStyle(); > +} > + > +llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) { > + llvm::yaml::Input Input(Text); > + Input >> *Style; > + return Input.error(); > +} > + > +std::string configurationAsText(const FormatStyle &Style) { > + std::string Text; > + llvm::raw_string_ostream Stream(Text); > + llvm::yaml::Output Output(Stream); > + // We use the same mapping method for input and output, so we need a > non-const > + // reference here. > + FormatStyle NonConstStyle = Style; > + Output << NonConstStyle; > + return Text; > +} > + > // Returns the length of everything up to the first possible line break after > // the ), ], } or > matching \c Tok. > static unsigned getLengthToMatchingParen(const AnnotatedToken &Tok) { > > Modified: cfe/trunk/unittests/Format/FormatTest.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=181326&r1=181325&r2=181326&view=diff > ============================================================================== > --- cfe/trunk/unittests/Format/FormatTest.cpp (original) > +++ cfe/trunk/unittests/Format/FormatTest.cpp Tue May 7 10:32:14 2013 > @@ -3909,5 +3909,113 @@ TEST_F(FormatTest, DoNotCreateUnreasonab > "}"); > } > > +bool operator==(const FormatStyle &L, const FormatStyle &R) { > + return L.AccessModifierOffset == R.AccessModifierOffset && > + L.AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft && > + L.AllowAllParametersOfDeclarationOnNextLine == > + R.AllowAllParametersOfDeclarationOnNextLine && > + L.AllowShortIfStatementsOnASingleLine == > + R.AllowShortIfStatementsOnASingleLine && > + L.BinPackParameters == R.BinPackParameters && > + L.ColumnLimit == R.ColumnLimit && > + L.ConstructorInitializerAllOnOneLineOrOnePerLine == > + R.ConstructorInitializerAllOnOneLineOrOnePerLine && > + L.DerivePointerBinding == R.DerivePointerBinding && > + L.IndentCaseLabels == R.IndentCaseLabels && > + L.MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && > + L.ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList && > + L.PenaltyExcessCharacter == R.PenaltyExcessCharacter && > + L.PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine > && > + L.PointerBindsToType == R.PointerBindsToType && > + L.SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && > + L.Standard == R.Standard; > +} > + > +bool allStylesEqual(ArrayRef<FormatStyle> Styles) { > + for (size_t i = 1; i < Styles.size(); ++i) > + if (!(Styles[0] == Styles[i])) > + return false; > + return true; > +} > + > +TEST_F(FormatTest, GetsPredefinedStyleByName) { > + FormatStyle LLVMStyles[] = { getLLVMStyle(), getPredefinedStyle("LLVM"), > + getPredefinedStyle("llvm"), > + getPredefinedStyle("lLvM") }; > + EXPECT_TRUE(allStylesEqual(LLVMStyles)); > + > + FormatStyle GoogleStyles[] = { getGoogleStyle(), > getPredefinedStyle("Google"), > + getPredefinedStyle("google"), > + getPredefinedStyle("gOOgle") }; > + EXPECT_TRUE(allStylesEqual(GoogleStyles)); > + > + FormatStyle ChromiumStyles[] = { getChromiumStyle(), > + getPredefinedStyle("Chromium"), > + getPredefinedStyle("chromium"), > + getPredefinedStyle("chROmiUM") }; > + EXPECT_TRUE(allStylesEqual(ChromiumStyles)); > + > + FormatStyle MozillaStyles[] = { getMozillaStyle(), > + getPredefinedStyle("Mozilla"), > + getPredefinedStyle("mozilla"), > + getPredefinedStyle("moZilla") }; > + EXPECT_TRUE(allStylesEqual(MozillaStyles)); > +} > + > +TEST_F(FormatTest, ParsesConfiguration) { > + FormatStyle Style = {}; > +#define CHECK_PARSE(TEXT, FIELD, VALUE) > \ > + EXPECT_NE(VALUE, Style.FIELD); > \ > + EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); > \ > + EXPECT_EQ(VALUE, Style.FIELD) > + > +#define CHECK_PARSE_BOOL(FIELD) > \ > + Style.FIELD = false; > \ > + EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); > \ > + EXPECT_EQ(true, Style.FIELD); > \ > + EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); > \ > + EXPECT_EQ(false, Style.FIELD); > + > + CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft); > + CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); > + CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine); > + CHECK_PARSE_BOOL(BinPackParameters); > + CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine); > + CHECK_PARSE_BOOL(DerivePointerBinding); > + CHECK_PARSE_BOOL(IndentCaseLabels); > + CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); > + CHECK_PARSE_BOOL(PointerBindsToType); > + > + CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234); > + CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u); > + CHECK_PARSE("MaxEmptyLinesToKeep: 1234", MaxEmptyLinesToKeep, 1234u); > + CHECK_PARSE("PenaltyExcessCharacter: 1234", PenaltyExcessCharacter, 1234u); > + CHECK_PARSE("PenaltyReturnTypeOnItsOwnLine: 1234", > + PenaltyReturnTypeOnItsOwnLine, 1234u); > + CHECK_PARSE("SpacesBeforeTrailingComments: 1234", > + SpacesBeforeTrailingComments, 1234u); > + > + Style.Standard = FormatStyle::LS_Auto; > + CHECK_PARSE("Standard: C++03", Standard, FormatStyle::LS_Cpp03); > + CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11); > + CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto); > + > + Style.ColumnLimit = 123; > + FormatStyle BaseStyle = getLLVMStyle(); > + CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit); > + CHECK_PARSE("BasedOnStyle: LLVM\nColumnLimit: 1234", ColumnLimit, 1234u); > + > +#undef CHECK_PARSE > +#undef CHECK_PARSE_BOOL > +} > + > +TEST_F(FormatTest, ConfigurationRoundTripTest) { > + FormatStyle Style = getLLVMStyle(); > + std::string YAML = configurationAsText(Style); > + FormatStyle ParsedStyle = {}; > + EXPECT_EQ(0, parseConfiguration(YAML, &ParsedStyle).value());
This unit test is failing because of Input::beginMapping in YAMLTraits.cpp. It uses dyn_cast, but CurrentNode is null (and so it asserts). I don't know enough about YAML to know whether CurrentNode being null is sensible or not. ~Aaron _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
