summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Format/WhitespaceManager.cpp54
-rw-r--r--clang/unittests/Format/FormatTestComments.cpp24
2 files changed, 70 insertions, 8 deletions
diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp
index c48883351c7..4b4fd13145f 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -100,14 +100,52 @@ void WhitespaceManager::calculateLineBreakInformation() {
Changes[0].PreviousEndOfTokenColumn = 0;
Change *LastOutsideTokenChange = &Changes[0];
for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
- unsigned OriginalWhitespaceStart =
- SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
- unsigned PreviousOriginalWhitespaceEnd = SourceMgr.getFileOffset(
- Changes[i - 1].OriginalWhitespaceRange.getEnd());
- Changes[i - 1].TokenLength = OriginalWhitespaceStart -
- PreviousOriginalWhitespaceEnd +
- Changes[i].PreviousLinePostfix.size() +
- Changes[i - 1].CurrentLinePrefix.size();
+ SourceLocation OriginalWhitespaceStart =
+ Changes[i].OriginalWhitespaceRange.getBegin();
+ SourceLocation PreviousOriginalWhitespaceEnd =
+ Changes[i - 1].OriginalWhitespaceRange.getEnd();
+ unsigned OriginalWhitespaceStartOffset =
+ SourceMgr.getFileOffset(OriginalWhitespaceStart);
+ unsigned PreviousOriginalWhitespaceEndOffset =
+ SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
+ assert(PreviousOriginalWhitespaceEndOffset <=
+ OriginalWhitespaceStartOffset);
+ const char *const PreviousOriginalWhitespaceEndData =
+ SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
+ StringRef Text(PreviousOriginalWhitespaceEndData,
+ SourceMgr.getCharacterData(OriginalWhitespaceStart) -
+ PreviousOriginalWhitespaceEndData);
+ // Usually consecutive changes would occur in consecutive tokens. This is
+ // not the case however when analyzing some preprocessor runs of the
+ // annotated lines. For example, in this code:
+ //
+ // #if A // line 1
+ // int i = 1;
+ // #else B // line 2
+ // int i = 2;
+ // #endif // line 3
+ //
+ // one of the runs will produce the sequence of lines marked with line 1, 2
+ // and 3. So the two consecutive whitespace changes just before '// line 2'
+ // and before '#endif // line 3' span multiple lines and tokens:
+ //
+ // #else B{change X}[// line 2
+ // int i = 2;
+ // ]{change Y}#endif // line 3
+ //
+ // For this reason, if the text between consecutive changes spans multiple
+ // newlines, the token length must be adjusted to the end of the original
+ // line of the token.
+ auto NewlinePos = Text.find_first_of('\n');
+ if (NewlinePos == StringRef::npos) {
+ Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
+ PreviousOriginalWhitespaceEndOffset +
+ Changes[i].PreviousLinePostfix.size() +
+ Changes[i - 1].CurrentLinePrefix.size();
+ } else {
+ Changes[i - 1].TokenLength =
+ NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
+ }
// If there are multiple changes in this token, sum up all the changes until
// the end of the line.
diff --git a/clang/unittests/Format/FormatTestComments.cpp b/clang/unittests/Format/FormatTestComments.cpp
index 09ee4645f59..fdb5a08e7a2 100644
--- a/clang/unittests/Format/FormatTestComments.cpp
+++ b/clang/unittests/Format/FormatTestComments.cpp
@@ -1052,6 +1052,30 @@ TEST_F(FormatTestComments, KeepsTrailingPPCommentsAndSectionCommentsSeparate) {
"}", getLLVMStyleWithColumns(80));
}
+TEST_F(FormatTestComments, AlignsPPElseEndifComments) {
+ verifyFormat("#if A\n"
+ "#else // A\n"
+ "int iiii;\n"
+ "#endif // B",
+ getLLVMStyleWithColumns(20));
+ verifyFormat("#if A\n"
+ "#else // A\n"
+ "int iiii; // CC\n"
+ "#endif // B",
+ getLLVMStyleWithColumns(20));
+ EXPECT_EQ("#if A\n"
+ "#else // A1\n"
+ " // A2\n"
+ "int ii;\n"
+ "#endif // B",
+ format("#if A\n"
+ "#else // A1\n"
+ " // A2\n"
+ "int ii;\n"
+ "#endif // B",
+ getLLVMStyleWithColumns(20)));
+}
+
TEST_F(FormatTestComments, CommentsInStaticInitializers) {
EXPECT_EQ(
"static SomeType type = {aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
OpenPOWER on IntegriCloud