diff options
Diffstat (limited to 'clang/lib/Format')
-rw-r--r-- | clang/lib/Format/BreakableToken.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Format/BreakableToken.h | 20 | ||||
-rw-r--r-- | clang/lib/Format/Format.cpp | 82 | ||||
-rw-r--r-- | clang/lib/Format/FormatToken.h | 4 | ||||
-rw-r--r-- | clang/lib/Format/FormatTokenLexer.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Format/NamespaceEndCommentsFixer.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Format/TokenAnnotator.cpp | 140 | ||||
-rw-r--r-- | clang/lib/Format/UnwrappedLineFormatter.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 9 |
9 files changed, 241 insertions, 86 deletions
diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 09ea5473c0c1..cd0eb0b4324a 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -88,11 +88,11 @@ getCommentSplit(StringRef Text, unsigned ContentStartColumn, StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes); - static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\."); + static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\."); while (SpaceOffset != StringRef::npos) { // Do not split before a number followed by a dot: this would be interpreted // as a numbered list, which would prevent re-flowing in subsequent passes. - if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks))) + if (kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks))) SpaceOffset = Text.find_last_of(Blanks, SpaceOffset); // In JavaScript, some @tags can be followed by {, and machinery that parses // these comments will fail to understand the comment if followed by a line @@ -245,7 +245,7 @@ BreakableStringLiteral::BreakableStringLiteral( BreakableToken::Split BreakableStringLiteral::getSplit( unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, - unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { + unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const { return getStringSplit(Line.substr(TailOffset), ContentStartColumn, ColumnLimit - Postfix.size(), Style.TabWidth, Encoding); } @@ -271,7 +271,7 @@ unsigned BreakableComment::getLineCount() const { return Lines.size(); } BreakableToken::Split BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const { + const llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. if (CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); @@ -316,9 +316,9 @@ static bool mayReflowContent(StringRef Content) { // Numbered lists may also start with a number followed by '.' // To avoid issues if a line starts with a number which is actually the end // of a previous line, we only consider numbers with up to 2 digits. - static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\. "); + static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. "); hasSpecialMeaningPrefix = - hasSpecialMeaningPrefix || kNumberedListRegexp->match(Content); + hasSpecialMeaningPrefix || kNumberedListRegexp.match(Content); // Simple heuristic for what to reflow: content should contain at least two // characters and either the first or second character must be @@ -458,7 +458,7 @@ BreakableBlockComment::BreakableBlockComment( BreakableToken::Split BreakableBlockComment::getSplit( unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, - unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { + unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. if (CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); @@ -597,9 +597,8 @@ void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset, PrefixWithTrailingIndent.size()); } -BreakableToken::Split -BreakableBlockComment::getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const { +BreakableToken::Split BreakableBlockComment::getReflowSplit( + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { if (!mayReflow(LineIndex, CommentPragmasRegex)) return Split(StringRef::npos, 0); @@ -706,8 +705,8 @@ BreakableBlockComment::getSplitAfterLastLine(unsigned TailOffset) const { return Split(StringRef::npos, 0); } -bool BreakableBlockComment::mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const { +bool BreakableBlockComment::mayReflow( + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { // Content[LineIndex] may exclude the indent after the '*' decoration. In that // case, we compute the start of the comment pragma manually. StringRef IndentContent = Content[LineIndex]; @@ -845,7 +844,7 @@ void BreakableLineCommentSection::insertBreak( } BreakableComment::Split BreakableLineCommentSection::getReflowSplit( - unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { if (!mayReflow(LineIndex, CommentPragmasRegex)) return Split(StringRef::npos, 0); @@ -955,7 +954,7 @@ void BreakableLineCommentSection::updateNextToken(LineState &State) const { } bool BreakableLineCommentSection::mayReflow( - unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { // Line comments have the indent as part of the prefix, so we need to // recompute the start of the line. StringRef IndentContent = Content[LineIndex]; diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h index 72852d59f9c4..a6691300de3b 100644 --- a/clang/lib/Format/BreakableToken.h +++ b/clang/lib/Format/BreakableToken.h @@ -155,7 +155,7 @@ public: /// file. virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const = 0; + const llvm::Regex &CommentPragmasRegex) const = 0; /// Emits the previously retrieved \p Split via \p Whitespaces. virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, @@ -190,7 +190,7 @@ public: /// If the split is not contained within one token, for example when reflowing /// line comments, returns (0, <length>). virtual Split getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const { + const llvm::Regex &CommentPragmasRegex) const { return Split(StringRef::npos, 0); } @@ -255,7 +255,7 @@ public: Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, unsigned ContentIndent, WhitespaceManager &Whitespaces) const override; @@ -298,7 +298,7 @@ public: unsigned getLineCount() const override; Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) const override; @@ -309,7 +309,7 @@ protected: // Checks if the content of line LineIndex may be reflown with the previous // line. virtual bool mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const = 0; + const llvm::Regex &CommentPragmasRegex) const = 0; // Contains the original text of the lines of the block comment. // @@ -363,7 +363,7 @@ public: Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; unsigned getRangeLength(unsigned LineIndex, unsigned Offset, StringRef::size_type Length, unsigned StartColumn) const override; @@ -375,7 +375,7 @@ public: unsigned ContentIndent, WhitespaceManager &Whitespaces) const override; Split getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void reflow(unsigned LineIndex, WhitespaceManager &Whitespaces) const override; bool introducesBreakBeforeToken() const override; @@ -384,7 +384,7 @@ public: Split getSplitAfterLastLine(unsigned TailOffset) const override; bool mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; // Contains Javadoc annotations that require additional indent when continued // on multiple lines. @@ -448,14 +448,14 @@ public: unsigned ContentIndent, WhitespaceManager &Whitespaces) const override; Split getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void reflow(unsigned LineIndex, WhitespaceManager &Whitespaces) const override; void adaptStartOfLine(unsigned LineIndex, WhitespaceManager &Whitespaces) const override; void updateNextToken(LineState &State) const override; bool mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; private: // OriginalPrefix[i] contains the original prefix of line i, including diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index cd44c0be85f0..f12bca48c630 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -467,6 +467,7 @@ template <> struct MappingTraits<FormatStyle> { Style.ConstructorInitializerIndentWidth); IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle); + IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding); IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment); IO.mapOptional("DisableFormat", Style.DisableFormat); IO.mapOptional("ExperimentalAutoDetectBinPacking", @@ -476,6 +477,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks); IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); + IO.mapOptional("IncludeIsMainSourceRegex", + Style.IncludeStyle.IncludeIsMainSourceRegex); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); @@ -534,16 +537,21 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); IO.mapOptional("SpacesInAngles", Style.SpacesInAngles); + IO.mapOptional("SpacesInConditionalStatement", + Style.SpacesInConditionalStatement); IO.mapOptional("SpacesInContainerLiterals", Style.SpacesInContainerLiterals); IO.mapOptional("SpacesInCStyleCastParentheses", Style.SpacesInCStyleCastParentheses); IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses); IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); + IO.mapOptional("SpaceBeforeSquareBrackets", + Style.SpaceBeforeSquareBrackets); IO.mapOptional("Standard", Style.Standard); IO.mapOptional("StatementMacros", Style.StatementMacros); IO.mapOptional("TabWidth", Style.TabWidth); IO.mapOptional("TypenameMacros", Style.TypenameMacros); + IO.mapOptional("UseCRLF", Style.UseCRLF); IO.mapOptional("UseTab", Style.UseTab); } }; @@ -760,6 +768,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ConstructorInitializerIndentWidth = 4; LLVMStyle.ContinuationIndentWidth = 4; LLVMStyle.Cpp11BracedListStyle = true; + LLVMStyle.DeriveLineEnding = true; LLVMStyle.DerivePointerAlignment = false; LLVMStyle.ExperimentalAutoDetectBinPacking = false; LLVMStyle.FixNamespaceComments = true; @@ -790,6 +799,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Latest; + LLVMStyle.UseCRLF = false; LLVMStyle.UseTab = FormatStyle::UT_Never; LLVMStyle.ReflowComments = true; LLVMStyle.SpacesInParentheses = false; @@ -807,7 +817,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true; LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; + LLVMStyle.SpaceBeforeSquareBrackets = false; LLVMStyle.SpacesInAngles = false; + LLVMStyle.SpacesInConditionalStatement = false; LLVMStyle.PenaltyBreakAssignment = prec::Assignment; LLVMStyle.PenaltyBreakComment = 300; @@ -1348,7 +1360,11 @@ public: WhitespaceManager Whitespaces( Env.getSourceManager(), Style, - inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID()))); + Style.DeriveLineEnding + ? inputUsesCRLF( + Env.getSourceManager().getBufferData(Env.getFileID()), + Style.UseCRLF) + : Style.UseCRLF); ContinuationIndenter Indenter(Style, Tokens.getKeywords(), Env.getSourceManager(), Whitespaces, Encoding, BinPackInconclusiveFunctions); @@ -1369,8 +1385,10 @@ public: } private: - static bool inputUsesCRLF(StringRef Text) { - return Text.count('\r') * 2 > Text.count('\n'); + static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF) { + size_t LF = Text.count('\n'); + size_t CR = Text.count('\r') * 2; + return LF == CR ? DefaultToCRLF : CR > LF; } bool @@ -2600,6 +2618,10 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, if (std::error_code EC = FS->makeAbsolute(Path)) return make_string_error(EC.message()); + llvm::SmallVector<std::string, 2> FilesToLookFor; + FilesToLookFor.push_back(".clang-format"); + FilesToLookFor.push_back("_clang-format"); + for (StringRef Directory = Path; !Directory.empty(); Directory = llvm::sys::path::parent_path(Directory)) { @@ -2609,43 +2631,35 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, continue; } - SmallString<128> ConfigFile(Directory); - - llvm::sys::path::append(ConfigFile, ".clang-format"); - LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n"); + for (const auto &F : FilesToLookFor) { + SmallString<128> ConfigFile(Directory); - Status = FS->status(ConfigFile.str()); - bool FoundConfigFile = - Status && (Status->getType() == llvm::sys::fs::file_type::regular_file); - if (!FoundConfigFile) { - // Try _clang-format too, since dotfiles are not commonly used on Windows. - ConfigFile = Directory; - llvm::sys::path::append(ConfigFile, "_clang-format"); + llvm::sys::path::append(ConfigFile, F); LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n"); + Status = FS->status(ConfigFile.str()); - FoundConfigFile = Status && (Status->getType() == - llvm::sys::fs::file_type::regular_file); - } - if (FoundConfigFile) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = - 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 (ec == ParseError::Unsuitable) { - if (!UnsuitableConfigFiles.empty()) - UnsuitableConfigFiles.append(", "); - UnsuitableConfigFiles.append(ConfigFile); - continue; + if (Status && + (Status->getType() == llvm::sys::fs::file_type::regular_file)) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + 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 (ec == ParseError::Unsuitable) { + if (!UnsuitableConfigFiles.empty()) + UnsuitableConfigFiles.append(", "); + UnsuitableConfigFiles.append(ConfigFile); + continue; + } + return make_string_error("Error reading " + ConfigFile + ": " + + ec.message()); } - return make_string_error("Error reading " + ConfigFile + ": " + - ec.message()); + LLVM_DEBUG(llvm::dbgs() + << "Using configuration file " << ConfigFile << "\n"); + return Style; } - LLVM_DEBUG(llvm::dbgs() - << "Using configuration file " << ConfigFile << "\n"); - return Style; } } if (!UnsuitableConfigFiles.empty()) diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index b11f36559a8b..e9cd327754ef 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -60,6 +60,8 @@ namespace format { TYPE(JsExponentiationEqual) \ TYPE(JsFatArrow) \ TYPE(JsNonNullAssertion) \ + TYPE(JsNullishCoalescingOperator) \ + TYPE(JsNullPropagatingOperator) \ TYPE(JsPrivateIdentifier) \ TYPE(JsTypeColon) \ TYPE(JsTypeOperator) \ @@ -405,7 +407,7 @@ struct FormatToken { bool isMemberAccess() const { return isOneOf(tok::arrow, tok::period, tok::arrowstar) && !isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow, - TT_LambdaArrow); + TT_LambdaArrow, TT_LeadingJavaAnnotation); } bool isUnaryOperator() const { diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 5d8a77577c0b..ef20ba884fb3 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -100,6 +100,10 @@ void FormatTokenLexer::tryMergePreviousTokens() { static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star}; static const tok::TokenKind JSExponentiationEqual[] = {tok::star, tok::starequal}; + static const tok::TokenKind JSNullPropagatingOperator[] = {tok::question, + tok::period}; + static const tok::TokenKind JSNullishOperator[] = {tok::question, + tok::question}; // FIXME: Investigate what token type gives the correct operator priority. if (tryMergeTokens(JSIdentity, TT_BinaryOperator)) @@ -116,6 +120,14 @@ void FormatTokenLexer::tryMergePreviousTokens() { Tokens.back()->Tok.setKind(tok::starequal); return; } + if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator)) + return; + if (tryMergeTokens(JSNullPropagatingOperator, + TT_JsNullPropagatingOperator)) { + // Treat like a regular "." access. + Tokens.back()->Tok.setKind(tok::period); + return; + } if (tryMergeJSPrivateIdentifier()) return; } diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp index 98901cff2681..20b424f86077 100644 --- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp @@ -92,24 +92,24 @@ bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName, // Matches a valid namespace end comment. // Valid namespace end comments don't need to be edited. - static llvm::Regex *const NamespaceCommentPattern = - new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" - "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", - llvm::Regex::IgnoreCase); - static llvm::Regex *const NamespaceMacroCommentPattern = - new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" - "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$", - llvm::Regex::IgnoreCase); + static const llvm::Regex NamespaceCommentPattern = + llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", + llvm::Regex::IgnoreCase); + static const llvm::Regex NamespaceMacroCommentPattern = + llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$", + llvm::Regex::IgnoreCase); SmallVector<StringRef, 8> Groups; if (NamespaceTok->is(TT_NamespaceMacro) && - NamespaceMacroCommentPattern->match(Comment->TokenText, &Groups)) { + NamespaceMacroCommentPattern.match(Comment->TokenText, &Groups)) { StringRef NamespaceTokenText = Groups.size() > 4 ? Groups[4] : ""; // The name of the macro must be used. if (NamespaceTokenText != NamespaceTok->TokenText) return false; } else if (NamespaceTok->isNot(tok::kw_namespace) || - !NamespaceCommentPattern->match(Comment->TokenText, &Groups)) { + !NamespaceCommentPattern.match(Comment->TokenText, &Groups)) { // Comment does not match regex. return false; } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 1ed35597d075..d5d394e61926 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -950,9 +950,9 @@ private: if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->Type = TT_PointerOrReference; consumeToken(); - if (CurrentToken && - CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, - tok::comma)) + if (CurrentToken && CurrentToken->Previous->isOneOf( + TT_BinaryOperator, TT_UnaryOperator, tok::comma, + tok::star, tok::arrow, tok::amp, tok::ampamp)) CurrentToken->Previous->Type = TT_OverloadedOperator; } if (CurrentToken) { @@ -1344,12 +1344,80 @@ private: Contexts.back().IsExpression = false; } else if (Current.is(tok::kw_new)) { Contexts.back().CanBeExpression = false; - } else if (Current.isOneOf(tok::semi, tok::exclaim)) { + } else if (Current.is(tok::semi) || + (Current.is(tok::exclaim) && Current.Previous && + !Current.Previous->is(tok::kw_operator))) { // This should be the condition or increment in a for-loop. + // But not operator !() (can't use TT_OverloadedOperator here as its not + // been annotated yet). Contexts.back().IsExpression = true; } } + static FormatToken *untilMatchingParen(FormatToken *Current) { + // Used when `MatchingParen` is not yet established. + int ParenLevel = 0; + while (Current) { + if (Current->is(tok::l_paren)) + ParenLevel++; + if (Current->is(tok::r_paren)) + ParenLevel--; + if (ParenLevel < 1) + break; + Current = Current->Next; + } + return Current; + } + + static bool isDeductionGuide(FormatToken &Current) { + // Look for a deduction guide template<T> A(...) -> A<...>; + if (Current.Previous && Current.Previous->is(tok::r_paren) && + Current.startsSequence(tok::arrow, tok::identifier, tok::less)) { + // Find the TemplateCloser. + FormatToken *TemplateCloser = Current.Next->Next; + int NestingLevel = 0; + while (TemplateCloser) { + // Skip over an expressions in parens A<(3 < 2)>; + if (TemplateCloser->is(tok::l_paren)) { + // No Matching Paren yet so skip to matching paren + TemplateCloser = untilMatchingParen(TemplateCloser); + } + if (TemplateCloser->is(tok::less)) + NestingLevel++; + if (TemplateCloser->is(tok::greater)) + NestingLevel--; + if (NestingLevel < 1) + break; + TemplateCloser = TemplateCloser->Next; + } + // Assuming we have found the end of the template ensure its followed + // with a semi-colon. + if (TemplateCloser && TemplateCloser->Next && + TemplateCloser->Next->is(tok::semi) && + Current.Previous->MatchingParen) { + // Determine if the identifier `A` prior to the A<..>; is the same as + // prior to the A(..) + FormatToken *LeadingIdentifier = + Current.Previous->MatchingParen->Previous; + + // Differentiate a deduction guide by seeing the + // > of the template prior to the leading identifier. + if (LeadingIdentifier) { + FormatToken *PriorLeadingIdentifier = LeadingIdentifier->Previous; + // Skip back past explicit decoration + if (PriorLeadingIdentifier && + PriorLeadingIdentifier->is(tok::kw_explicit)) + PriorLeadingIdentifier = PriorLeadingIdentifier->Previous; + + return (PriorLeadingIdentifier && + PriorLeadingIdentifier->is(TT_TemplateCloser) && + LeadingIdentifier->TokenText == Current.Next->TokenText); + } + } + } + return false; + } + void determineTokenType(FormatToken &Current) { if (!Current.is(TT_Unknown)) // The token type is already known. @@ -1397,6 +1465,10 @@ private: !Current.Previous->is(tok::kw_operator)) { // not auto operator->() -> xxx; Current.Type = TT_TrailingReturnArrow; + + } else if (isDeductionGuide(Current)) { + // Deduction guides trailing arrow " A(...) -> A<T>;". + Current.Type = TT_TrailingReturnArrow; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, Contexts.back().CanBeExpression && @@ -1757,7 +1829,8 @@ private: // Use heuristics to recognize unary operators. if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square, tok::question, tok::colon, tok::kw_return, - tok::kw_case, tok::at, tok::l_brace, tok::kw_throw)) + tok::kw_case, tok::at, tok::l_brace, tok::kw_throw, + tok::kw_co_return, tok::kw_co_yield)) return TT_UnaryOperator; // There can't be two consecutive binary operators. @@ -2087,11 +2160,22 @@ static bool isFunctionDeclarationName(const FormatToken &Current, continue; if (Next->isOneOf(tok::kw_new, tok::kw_delete)) { // For 'new[]' and 'delete[]'. - if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next && - Next->Next->Next->is(tok::r_square)) + if (Next->Next && + Next->Next->startsSequence(tok::l_square, tok::r_square)) Next = Next->Next->Next; continue; } + if (Next->startsSequence(tok::l_square, tok::r_square)) { + // For operator[](). + Next = Next->Next; + continue; + } + if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) && + Next->Next && Next->Next->isOneOf(tok::star, tok::amp, tok::ampamp)) { + // For operator void*(), operator char*(), operator Foo*(). + Next = Next->Next; + continue; + } break; } @@ -2508,6 +2592,13 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { Right.ParameterCount > 0); } +/// Returns \c true if the token is followed by a boolean condition, \c false +/// otherwise. +static bool isKeywordWithCondition(const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, + tok::kw_constexpr); +} + bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, const FormatToken &Right) { @@ -2526,6 +2617,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && Right.is(tok::r_brace) && Right.BlockKind != BK_Block)) return Style.SpaceInEmptyParentheses; + if (Style.SpacesInConditionalStatement) { + if (Left.is(tok::l_paren) && Left.Previous && + isKeywordWithCondition(*Left.Previous)) + return true; + if (Right.is(tok::r_paren) && Right.MatchingParen && + Right.MatchingParen->Previous && + isKeywordWithCondition(*Right.MatchingParen->Previous)) + return true; + } if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) return (Right.is(TT_CastRParen) || (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen))) @@ -2567,7 +2667,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous && Left.Previous->is(tok::kw_case)); if (Left.is(tok::l_square) && Right.is(tok::amp)) - return false; + return Style.SpacesInSquareBrackets; if (Right.is(TT_PointerOrReference)) { if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) { if (!Left.MatchingParen) @@ -2605,6 +2705,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, tok::l_square)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; + if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) && + (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) && + Left.Previous && Left.Previous->is(tok::kw_operator)) + // Space between the type and the * + // operator void*(), operator char*(), operator Foo*() dependant + // on PointerAlignment style. + return (Style.PointerAlignment != FormatStyle::PAS_Left); const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { return Style.SpacesInContainerLiterals || @@ -2634,7 +2741,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, TT_DesignatedInitializerLSquare, TT_StructuredBindingLSquare, TT_AttributeSquare) && - !Left.isOneOf(tok::numeric_constant, TT_DictLiteral)) + !Left.isOneOf(tok::numeric_constant, TT_DictLiteral) && + !(!Left.is(tok::r_square) && Style.SpaceBeforeSquareBrackets && + Right.is(TT_ArraySubscriptLSquare))) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) return !Left.Children.empty(); // No spaces in "{}". @@ -2906,14 +3015,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } if (Left.is(TT_UnaryOperator)) { - // The alternative operators for ~ and ! are "compl" and "not". - // If they are used instead, we do not want to combine them with - // the token to the right, unless that is a left paren. if (!Right.is(tok::l_paren)) { + // The alternative operators for ~ and ! are "compl" and "not". + // If they are used instead, we do not want to combine them with + // the token to the right, unless that is a left paren. if (Left.is(tok::exclaim) && Left.TokenText == "not") return true; if (Left.is(tok::tilde) && Left.TokenText == "compl") return true; + // Lambda captures allow for a lone &, so "&]" needs to be properly + // handled. + if (Left.is(tok::amp) && Right.is(tok::r_square)) + return Style.SpacesInSquareBrackets; } return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || Right.is(TT_BinaryOperator); @@ -2947,7 +3060,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // The identifier might actually be a macro name such as ALWAYS_INLINE. If // this turns out to be too lenient, add analysis of the identifier itself. return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); - if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment)) + if (Right.is(tok::coloncolon) && + !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren)) return (Left.is(TT_TemplateOpener) && Style.Standard < FormatStyle::LS_Cpp11) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 8b8d357d9cbe..fec85f1174da 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -326,6 +326,19 @@ private: FormatStyle::BWACS_Always) ? tryMergeSimpleBlock(I, E, Limit) : 0; + } else if (I[1]->First->is(tok::l_brace) && + TheLine->First->isOneOf(tok::kw_else, tok::kw_catch) && + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_MultiLine) { + // This case if different from the upper BWACS_MultiLine processing + // in that a preceding r_brace is not on the same line as else/catch + // most likely because of BeforeElse/BeforeCatch set to true. + // If the line length doesn't fit ColumnLimit, leave l_brace on the + // next line to respect the BWACS_MultiLine. + return (Style.ColumnLimit == 0 || + TheLine->Last->TotalLength <= Style.ColumnLimit) + ? 1 + : 0; } // Try to merge either empty or one-line block if is precedeed by control // statement token diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index bbe05602f6da..ead6b4743207 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -466,7 +466,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { (NextTok->is(tok::semi) && (!ExpectClassBody || LBraceStack.size() != 1)) || (NextTok->isBinaryOperator() && !NextIsObjCMethod); - if (NextTok->is(tok::l_square)) { + if (!Style.isCSharp() && NextTok->is(tok::l_square)) { // We can have an array subscript after a braced init // list, but C++11 attributes are expected after blocks. NextTok = Tokens->getNextToken(); @@ -2498,9 +2498,10 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) { // Checks if \p FormatTok is a line comment that continues the line comment // section on \p Line. -static bool continuesLineCommentSection(const FormatToken &FormatTok, - const UnwrappedLine &Line, - llvm::Regex &CommentPragmasRegex) { +static bool +continuesLineCommentSection(const FormatToken &FormatTok, + const UnwrappedLine &Line, + const llvm::Regex &CommentPragmasRegex) { if (Line.Tokens.empty()) return false; |