Index: ; =================================================================== --- ; +++ ; @@ -853,6 +853,20 @@ return true; } +FormatStyle::FormatStyleSet FormatStyle::BuildStyleSetFromConfiguration( + const FormatStyle &MainStyle, + const std::vector &ConfigurationStyles) { + FormatStyleSet Styles; + Styles.Add(MainStyle); + for (int i = 0; i < ConfigurationStyles.size(); ++i) { + if (Styles[i].Language != FormatStyle::LK_None && + Styles[i].Language != MainStyle.Language) { + Styles.Add(Styles[i]); + } + } + return Styles; +} + std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) { assert(Style); FormatStyle::LanguageKind Language = Style->Language; @@ -888,15 +902,21 @@ // 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 0) after it. + bool LanguageFound = false; 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 = Language; - return make_error_code(ParseError::Success); + LanguageFound = true; + break; } } - return make_error_code(ParseError::Unsuitable); + if (!LanguageFound) + return make_error_code(ParseError::Unsuitable); + Style->StyleSet = + FormatStyle::BuildFormatStyleSetFromConfiguration(*Style, Styles); + return make_error_code(ParseError::Success); } std::string configurationAsText(const FormatStyle &Style) { @@ -910,6 +930,34 @@ return Stream.str(); } +llvm::Optional +FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const { + if (!Styles) + return None; + auto It = Styles->find(Language); + if (It == Styles->end()) + return None; + FormatStyle Style = *It->second; + Style.StyleSet = *this; + return Style; +} + +void FormatStyle::FormatStyleSet::Add(FormatStyle Style) { + Style.StyleSet.Styles.reset(); + if (!Styles) + Styles = std::make_shared(); + (*Styles)[Style.Language].reset(new FormatStyle(Style)); +} + +llvm::Optional +FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const { + return StyleSet.Get(Language); +} + +void FormatStyle::AddLanguageStyle(const FormatStyle& Style) { + StyleSet.Add(Style); +} + namespace { class JavaScriptRequoter : public TokenAnalyzer { Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1685,6 +1685,36 @@ Standard == R.Standard && TabWidth == R.TabWidth && UseTab == R.UseTab; } + + llvm::Optional GetLanguageStyle(LanguageKind Language) const; + + // Stores per-language styles. A FormatStyle instance inside has an empty + // StyleSet. A FormatStyle instance returned by the Get method has its + // StyleSet set to a copy of the originating StyleSet, effectively keeping the + // internal representation of that StyleSet alive. + // + // The memory management and ownership reminds of a birds nest: chicks + // leaving the nest take photos of the nest with them. + struct FormatStyleSet { + typedef std::map> + MapType; + + llvm::Optional Get(FormatStyle::LanguageKind Language) const; + void Add(FormatStyle Style); + + private: + std::shared_ptr Styles; + }; + + static FormatStyleSet BuildStyleSetFromConfiguration( + const FormatStyle &MainStyle, + const std::vector &ConfigurationStyles); + +private: + FormatStyleSet StyleSet; + + friend std::error_code parseConfiguration(StringRef Text, FormatStyle *Style); }; /// \brief Returns a format style complying with the LLVM coding standards: Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -853,6 +853,20 @@ return true; } +FormatStyle::FormatStyleSet FormatStyle::BuildStyleSetFromConfiguration( + const FormatStyle &MainStyle, + const std::vector &ConfigurationStyles) { + FormatStyleSet StyleSet; + StyleSet.Add(MainStyle); + for (size_t i = 0; i < ConfigurationStyles.size(); ++i) { + if (ConfigurationStyles[i].Language != FormatStyle::LK_None && + ConfigurationStyles[i].Language != MainStyle.Language) { + StyleSet.Add(ConfigurationStyles[i]); + } + } + return StyleSet; +} + std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) { assert(Style); FormatStyle::LanguageKind Language = Style->Language; @@ -888,15 +902,20 @@ // 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 0) after it. + bool LanguageFound = false; 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 = Language; - return make_error_code(ParseError::Success); + LanguageFound = true; + break; } } - return make_error_code(ParseError::Unsuitable); + if (!LanguageFound) + return make_error_code(ParseError::Unsuitable); + Style->StyleSet = FormatStyle::BuildStyleSetFromConfiguration(*Style, Styles); + return make_error_code(ParseError::Success); } std::string configurationAsText(const FormatStyle &Style) { @@ -910,6 +929,30 @@ return Stream.str(); } +llvm::Optional +FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const { + if (!Styles) + return None; + auto It = Styles->find(Language); + if (It == Styles->end()) + return None; + FormatStyle Style = *It->second; + Style.StyleSet = *this; + return Style; +} + +void FormatStyle::FormatStyleSet::Add(FormatStyle Style) { + Style.StyleSet.Styles.reset(); + if (!Styles) + Styles = std::make_shared(); + (*Styles)[Style.Language].reset(new FormatStyle(Style)); +} + +llvm::Optional +FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const { + return StyleSet.Get(Language); +} + namespace { class JavaScriptRequoter : public TokenAnalyzer {