diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2012-06-20 09:53:52 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2012-06-20 09:53:52 +0000 |
commit | f95d4125c01fa7b98722ae8cfbceac4a87d037b4 (patch) | |
tree | 5d3f7163adeadbff7ac65afff4414f6757b06792 /lib/AST/RawCommentList.cpp | |
parent | 10663399b1d4663e8b140eb12d9aa351be147c55 (diff) |
Fix a big layering violation introduced by r158771.
That commit added a new library just to hold the RawCommentList. I've
started a discussion on the commit thread about whether that is really
meritted -- it certainly doesn't seem necessary at this stage.
However, the immediate problem is that the AST library has a hard
dependency on the Comment library, but the dependencies were set up
completely backward. In addition to the layering violation, this had an
unfortunate effect if scattering the Comments library dependency
throughout the build system, but inconsistently so -- several parts of
the CMake dependencies were missing and only showed up due to transitive
deps or the fact that the target wasn't being built by tho bots.
It turns out that the Comments library can't (currently) be a well
formed layer *below* the AST library either, as it has an API that
accepts an ASTContext. That parameter is currently unused, so maybe that
was a mistake?
Anyways, it really seems like this is logically part of the AST --
that's the whole point of the ASTContext providing access to it as far
as I can tell -- so I've merged it into the AST library to solve the
immediate layering violation problems and remove some of the churn from
our library dependencies.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158807 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/RawCommentList.cpp')
-rw-r--r-- | lib/AST/RawCommentList.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp new file mode 100644 index 0000000000..07776779e8 --- /dev/null +++ b/lib/AST/RawCommentList.cpp @@ -0,0 +1,207 @@ +//===--- RawCommentList.cpp - Processing raw comments -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/RawCommentList.h" +#include "clang/AST/ASTContext.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang; + +namespace { +/// Get comment kind and bool describing if it is a trailing comment. +std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment) { + if (Comment.size() < 3 || Comment[0] != '/') + return std::make_pair(RawComment::CK_Invalid, false); + + RawComment::CommentKind K; + if (Comment[1] == '/') { + if (Comment.size() < 3) + return std::make_pair(RawComment::CK_OrdinaryBCPL, false); + + if (Comment[2] == '/') + K = RawComment::CK_BCPLSlash; + else if (Comment[2] == '!') + K = RawComment::CK_BCPLExcl; + else + return std::make_pair(RawComment::CK_OrdinaryBCPL, false); + } else { + assert(Comment.size() >= 4); + + // Comment lexer does not understand escapes in comment markers, so pretend + // that this is not a comment. + if (Comment[1] != '*' || + Comment[Comment.size() - 2] != '*' || + Comment[Comment.size() - 1] != '/') + return std::make_pair(RawComment::CK_Invalid, false); + + if (Comment[2] == '*') + K = RawComment::CK_JavaDoc; + else if (Comment[2] == '!') + K = RawComment::CK_Qt; + else + return std::make_pair(RawComment::CK_OrdinaryC, false); + } + const bool TrailingComment = (Comment.size() > 3) && (Comment[3] == '<'); + return std::make_pair(K, TrailingComment); +} + +bool mergedCommentIsTrailingComment(StringRef Comment) { + return (Comment.size() > 3) && (Comment[3] == '<'); +} +} // unnamed namespace + +RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, + bool Merged) : + Range(SR), RawTextValid(false), IsAlmostTrailingComment(false), + BeginLineValid(false), EndLineValid(false) { + // Extract raw comment text, if possible. + if (getRawText(SourceMgr).empty()) { + Kind = CK_Invalid; + return; + } + + if (!Merged) { + // Guess comment kind. + std::pair<CommentKind, bool> K = getCommentKind(RawText); + Kind = K.first; + IsTrailingComment = K.second; + + IsAlmostTrailingComment = RawText.startswith("//<") || + RawText.startswith("/*<"); + } else { + Kind = CK_Merged; + IsTrailingComment = mergedCommentIsTrailingComment(RawText); + } +} + +unsigned RawComment::getBeginLine(const SourceManager &SM) const { + if (BeginLineValid) + return BeginLine; + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin()); + BeginLine = SM.getLineNumber(LocInfo.first, LocInfo.second); + BeginLineValid = true; + return BeginLine; +} + +unsigned RawComment::getEndLine(const SourceManager &SM) const { + if (EndLineValid) + return EndLine; + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getEnd()); + EndLine = SM.getLineNumber(LocInfo.first, LocInfo.second); + EndLineValid = true; + return EndLine; +} + +StringRef RawComment::getRawTextSlow(const SourceManager &SourceMgr) const { + FileID BeginFileID; + FileID EndFileID; + unsigned BeginOffset; + unsigned EndOffset; + + llvm::tie(BeginFileID, BeginOffset) = + SourceMgr.getDecomposedLoc(Range.getBegin()); + llvm::tie(EndFileID, EndOffset) = + SourceMgr.getDecomposedLoc(Range.getEnd()); + + const unsigned Length = EndOffset - BeginOffset; + if (Length < 2) + return StringRef(); + + // The comment can't begin in one file and end in another. + assert(BeginFileID == EndFileID); + + bool Invalid = false; + const char *BufferStart = SourceMgr.getBufferData(BeginFileID, + &Invalid).data(); + if (Invalid) + return StringRef(); + + return StringRef(BufferStart + BeginOffset, Length); +} + +namespace { +bool containsOnlyWhitespace(StringRef Str) { + return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos; +} + +bool onlyWhitespaceBetweenComments(SourceManager &SM, + const RawComment &C1, const RawComment &C2) { + std::pair<FileID, unsigned> C1EndLocInfo = SM.getDecomposedLoc( + C1.getSourceRange().getEnd()); + std::pair<FileID, unsigned> C2BeginLocInfo = SM.getDecomposedLoc( + C2.getSourceRange().getBegin()); + + // Question does not make sense if comments are located in different files. + if (C1EndLocInfo.first != C2BeginLocInfo.first) + return false; + + bool Invalid = false; + const char *Buffer = SM.getBufferData(C1EndLocInfo.first, &Invalid).data(); + if (Invalid) + return false; + + StringRef TextBetweenComments(Buffer + C1EndLocInfo.second, + C2BeginLocInfo.second - C1EndLocInfo.second); + + return containsOnlyWhitespace(TextBetweenComments); +} +} // unnamed namespace + +void RawCommentList::addComment(const RawComment &RC, ASTContext &Context) { + if (RC.isInvalid()) + return; + + assert((Comments.empty() || + SourceMgr.isBeforeInTranslationUnit( + Comments[0].getSourceRange().getEnd(), + RC.getSourceRange().getBegin())) && + "comments are not coming in source order"); + + if (OnlyWhitespaceSeen) { + if (!onlyWhitespaceBetweenComments(SourceMgr, LastComment, RC)) + OnlyWhitespaceSeen = false; + } + + LastComment = RC; + + // Ordinary comments are not interesting for us. + if (RC.isOrdinary()) + return; + + // If this is the first Doxygen comment, save it (because there isn't + // anything to merge it with). + if (Comments.empty()) { + Comments.push_back(RC); + OnlyWhitespaceSeen = true; + return; + } + + const RawComment &C1 = Comments.back(); + const RawComment &C2 = RC; + + // Merge comments only if there is only whitespace between them. + // Can't merge trailing and non-trailing comments. + // Merge trailing comments if they are on same or consecutive lines. + if (OnlyWhitespaceSeen && + (C1.isTrailingComment() == C2.isTrailingComment()) && + (!C1.isTrailingComment() || + C1.getEndLine(SourceMgr) + 1 >= C2.getBeginLine(SourceMgr))) { + SourceRange MergedRange(C1.getSourceRange().getBegin(), + C2.getSourceRange().getEnd()); + RawComment Merged(SourceMgr, MergedRange, true); + Comments.pop_back(); + Comments.push_back(Merged); + } else + Comments.push_back(RC); + + OnlyWhitespaceSeen = true; +} + |