benhamilton created this revision. benhamilton added reviewers: jolesiak, stephanemoore, djasper. Herald added subscribers: cfe-commits, klimek.
Concatenating Objective-C string literals inside an array literal raises the warning -Wobjc-string-concatenation (which is enabled by default). clang-format currently splits and concatenates string literals like the following: NSArray *myArray = @[ @"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ]; into: NSArray *myArray = @[ @"aaaaaaaaaaaaaaaaaaaaaaaaaaaa" @"aaaaaaaaa" ]; which raises the warning. This is https://bugs.llvm.org/show_bug.cgi?id=36153 . The options I can think of to fix this are: 1. Have clang-format disable Wobjc-string-concatenation by emitting pragmas around the formatted code 2. Have clang-format wrap the string literals in a macro (which disables the warning) 3. Disable string splitting for Objective-C string literals inside array literals I think 1) has no precedent, and I couldn't find a good identity() macro for 2). So, this diff implements 3). Test Plan: make -j12 FormatTests && ./tools/clang/unittests/Format/FormatTests Repository: rC Clang https://reviews.llvm.org/D42704 Files: lib/Format/ContinuationIndenter.cpp lib/Format/ContinuationIndenter.h unittests/Format/FormatTestObjC.cpp Index: unittests/Format/FormatTestObjC.cpp =================================================================== --- unittests/Format/FormatTestObjC.cpp +++ unittests/Format/FormatTestObjC.cpp @@ -915,6 +915,12 @@ verifyFormat("[someFunction someLooooooooooooongParameter:@[\n" " NSBundle.mainBundle.infoDictionary[@\"a\"]\n" "]];"); + Style.ColumnLimit = 20; + // We can't break string literals inside NSArray literals + // (that raises -Wobjc-string-concatenation). + verifyFormat("NSArray *foo = @[\n" + " @\"aaaaaaaaaaaaaaaaaaaaaaaaaa\"\n" + "];\n"); } } // end namespace } // end namespace format Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -208,7 +208,8 @@ NoLineBreakInOperand(false), LastOperatorWrapped(true), ContainsLineBreak(false), ContainsUnwrappedBuilder(false), AlignColons(true), ObjCSelectorNameFound(false), - HasMultipleNestedBlocks(false), NestedBlockInlined(false) {} + HasMultipleNestedBlocks(false), NestedBlockInlined(false), + IsInsideObjCArrayLiteral(false) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -318,6 +319,10 @@ // "function" in JavaScript) is not wrapped to a new line. bool NestedBlockInlined : 1; + /// \brief \c true if the current \c ParenState represents an Objective-C + /// array literal. + bool IsInsideObjCArrayLiteral : 1; + bool operator<(const ParenState &Other) const { if (Indent != Other.Indent) return Indent < Other.Indent; Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1270,6 +1270,9 @@ State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1; + State.Stack.back().IsInsideObjCArrayLiteral = + Current.is(TT_ArrayInitializerLSquare) && Current.Previous && + Current.Previous->is(tok::at); } void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { @@ -1562,6 +1565,11 @@ // likely want to terminate the string before any line breaking is done. if (Current.IsUnterminatedLiteral) return nullptr; + // Don't break string literals inside Objective-C array literals (doing so + // raises the warning -Wobjc-string-concatenation). + if (State.Stack.back().IsInsideObjCArrayLiteral) { + return nullptr; + } StringRef Text = Current.TokenText; StringRef Prefix;
Index: unittests/Format/FormatTestObjC.cpp =================================================================== --- unittests/Format/FormatTestObjC.cpp +++ unittests/Format/FormatTestObjC.cpp @@ -915,6 +915,12 @@ verifyFormat("[someFunction someLooooooooooooongParameter:@[\n" " NSBundle.mainBundle.infoDictionary[@\"a\"]\n" "]];"); + Style.ColumnLimit = 20; + // We can't break string literals inside NSArray literals + // (that raises -Wobjc-string-concatenation). + verifyFormat("NSArray *foo = @[\n" + " @\"aaaaaaaaaaaaaaaaaaaaaaaaaa\"\n" + "];\n"); } } // end namespace } // end namespace format Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -208,7 +208,8 @@ NoLineBreakInOperand(false), LastOperatorWrapped(true), ContainsLineBreak(false), ContainsUnwrappedBuilder(false), AlignColons(true), ObjCSelectorNameFound(false), - HasMultipleNestedBlocks(false), NestedBlockInlined(false) {} + HasMultipleNestedBlocks(false), NestedBlockInlined(false), + IsInsideObjCArrayLiteral(false) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -318,6 +319,10 @@ // "function" in JavaScript) is not wrapped to a new line. bool NestedBlockInlined : 1; + /// \brief \c true if the current \c ParenState represents an Objective-C + /// array literal. + bool IsInsideObjCArrayLiteral : 1; + bool operator<(const ParenState &Other) const { if (Indent != Other.Indent) return Indent < Other.Indent; Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1270,6 +1270,9 @@ State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1; + State.Stack.back().IsInsideObjCArrayLiteral = + Current.is(TT_ArrayInitializerLSquare) && Current.Previous && + Current.Previous->is(tok::at); } void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { @@ -1562,6 +1565,11 @@ // likely want to terminate the string before any line breaking is done. if (Current.IsUnterminatedLiteral) return nullptr; + // Don't break string literals inside Objective-C array literals (doing so + // raises the warning -Wobjc-string-concatenation). + if (State.Stack.back().IsInsideObjCArrayLiteral) { + return nullptr; + } StringRef Text = Current.TokenText; StringRef Prefix;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits