aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/RawCommentList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/RawCommentList.cpp')
-rw-r--r--lib/AST/RawCommentList.cpp86
1 files changed, 79 insertions, 7 deletions
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 24b129a5c532..8317f76b8569 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentSema.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
@@ -62,12 +63,53 @@ std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment,
bool mergedCommentIsTrailingComment(StringRef Comment) {
return (Comment.size() > 3) && (Comment[3] == '<');
}
+
+/// Returns true if R1 and R2 both have valid locations that start on the same
+/// column.
+bool commentsStartOnSameColumn(const SourceManager &SM, const RawComment &R1,
+ const RawComment &R2) {
+ SourceLocation L1 = R1.getLocStart();
+ SourceLocation L2 = R2.getLocStart();
+ bool Invalid = false;
+ unsigned C1 = SM.getPresumedColumnNumber(L1, &Invalid);
+ if (!Invalid) {
+ unsigned C2 = SM.getPresumedColumnNumber(L2, &Invalid);
+ return !Invalid && (C1 == C2);
+ }
+ return false;
+}
} // unnamed namespace
+/// \brief Determines whether there is only whitespace in `Buffer` between `P`
+/// and the previous line.
+/// \param Buffer The buffer to search in.
+/// \param P The offset from the beginning of `Buffer` to start from.
+/// \return true if all of the characters in `Buffer` ranging from the closest
+/// line-ending character before `P` (or the beginning of `Buffer`) to `P - 1`
+/// are whitespace.
+static bool onlyWhitespaceOnLineBefore(const char *Buffer, unsigned P) {
+ // Search backwards until we see linefeed or carriage return.
+ for (unsigned I = P; I != 0; --I) {
+ char C = Buffer[I - 1];
+ if (isVerticalWhitespace(C))
+ return true;
+ if (!isHorizontalWhitespace(C))
+ return false;
+ }
+ // We hit the beginning of the buffer.
+ return true;
+}
+
+/// Returns whether `K` is an ordinary comment kind.
+static bool isOrdinaryKind(RawComment::CommentKind K) {
+ return (K == RawComment::RCK_OrdinaryBCPL) ||
+ (K == RawComment::RCK_OrdinaryC);
+}
+
RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
bool Merged, bool ParseAllComments) :
Range(SR), RawTextValid(false), BriefTextValid(false),
- IsAttached(false), IsAlmostTrailingComment(false),
+ IsAttached(false), IsTrailingComment(false), IsAlmostTrailingComment(false),
ParseAllComments(ParseAllComments) {
// Extract raw comment text, if possible.
if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) {
@@ -75,17 +117,34 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
return;
}
+ // Guess comment kind.
+ std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments);
+
+ // Guess whether an ordinary comment is trailing.
+ if (ParseAllComments && isOrdinaryKind(K.first)) {
+ FileID BeginFileID;
+ unsigned BeginOffset;
+ std::tie(BeginFileID, BeginOffset) =
+ SourceMgr.getDecomposedLoc(Range.getBegin());
+ if (BeginOffset != 0) {
+ bool Invalid = false;
+ const char *Buffer =
+ SourceMgr.getBufferData(BeginFileID, &Invalid).data();
+ IsTrailingComment |=
+ (!Invalid && !onlyWhitespaceOnLineBefore(Buffer, BeginOffset));
+ }
+ }
+
if (!Merged) {
- // Guess comment kind.
- std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments);
Kind = K.first;
- IsTrailingComment = K.second;
+ IsTrailingComment |= K.second;
IsAlmostTrailingComment = RawText.startswith("//<") ||
RawText.startswith("/*<");
} else {
Kind = RCK_Merged;
- IsTrailingComment = mergedCommentIsTrailingComment(RawText);
+ IsTrailingComment =
+ IsTrailingComment || mergedCommentIsTrailingComment(RawText);
}
}
@@ -239,9 +298,22 @@ void RawCommentList::addComment(const RawComment &RC,
const RawComment &C2 = RC;
// Merge comments only if there is only whitespace between them.
- // Can't merge trailing and non-trailing comments.
+ // Can't merge trailing and non-trailing comments unless the second is
+ // non-trailing ordinary in the same column, as in the case:
+ // int x; // documents x
+ // // more text
+ // versus:
+ // int x; // documents x
+ // int y; // documents y
+ // or:
+ // int x; // documents x
+ // // documents y
+ // int y;
// Merge comments if they are on same or consecutive lines.
- if (C1.isTrailingComment() == C2.isTrailingComment() &&
+ if ((C1.isTrailingComment() == C2.isTrailingComment() ||
+ (C1.isTrailingComment() && !C2.isTrailingComment() &&
+ isOrdinaryKind(C2.getKind()) &&
+ commentsStartOnSameColumn(SourceMgr, C1, C2))) &&
onlyWhitespaceBetween(SourceMgr, C1.getLocEnd(), C2.getLocStart(),
/*MaxNewlinesAllowed=*/1)) {
SourceRange MergedRange(C1.getLocStart(), C2.getLocEnd());