aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitri Gribenko <gribozavr@gmail.com>2012-06-20 00:34:58 +0000
committerDmitri Gribenko <gribozavr@gmail.com>2012-06-20 00:34:58 +0000
commitaa0cd85838f2a024e589ea4e8c2094130065af21 (patch)
treeb4e013c1268210fa0769c263d702c637395b59ae
parented36b2a80878c29603bdc89a7969253fb6446174 (diff)
Structured comment parsing, first step.
* Retain comments in the AST * Serialize/deserialize comments * Find comments attached to a certain Decl * Expose raw comment text and SourceRange via libclang git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158771 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang-c/Index.h13
-rw-r--r--include/clang/AST/ASTContext.h26
-rw-r--r--include/clang/AST/ExternalASTSource.h3
-rw-r--r--include/clang/Basic/SourceManager.h42
-rw-r--r--include/clang/Comments/RawCommentList.h172
-rw-r--r--include/clang/Lex/Preprocessor.h4
-rw-r--r--include/clang/Parse/Parser.h1
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--include/clang/Serialization/ASTBitCodes.h12
-rw-r--r--include/clang/Serialization/ASTReader.h7
-rw-r--r--include/clang/Serialization/ASTWriter.h1
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp2
-rw-r--r--lib/AST/ASTContext.cpp102
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/Comments/CMakeLists.txt7
-rw-r--r--lib/Comments/Makefile14
-rw-r--r--lib/Comments/RawCommentList.cpp207
-rw-r--r--lib/Lex/Preprocessor.cpp4
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Parse/Parser.cpp22
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/SemaType.cpp2
-rw-r--r--lib/Serialization/ASTReader.cpp66
-rw-r--r--lib/Serialization/ASTWriter.cpp18
-rw-r--r--test/Index/annotate-comments.cpp229
-rw-r--r--tools/arcmt-test/CMakeLists.txt1
-rw-r--r--tools/arcmt-test/Makefile3
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c20
-rw-r--r--tools/clang-check/CMakeLists.txt2
-rw-r--r--tools/clang-check/Makefile2
-rw-r--r--tools/diagtool/CMakeLists.txt1
-rw-r--r--tools/diagtool/Makefile2
-rw-r--r--tools/driver/CMakeLists.txt1
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/libclang/CIndex.cpp30
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/Makefile2
-rw-r--r--tools/libclang/libclang.exports2
-rw-r--r--unittests/Frontend/Makefile2
-rw-r--r--unittests/Tooling/Makefile2
41 files changed, 1005 insertions, 35 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index c9742e2483..b7bd8bb738 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -3188,6 +3188,19 @@ CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
/**
+ * \brief Given a cursor that represents a declaration, return the associated
+ * comment's source range. The range may include multiple consecutive comments
+ * with whitespace in between.
+ */
+CINDEX_LINKAGE CXSourceRange clang_Cursor_getCommentRange(CXCursor C);
+
+/**
+ * \brief Given a cursor that represents a declaration, return the associated
+ * comment text, including comment markers.
+ */
+CINDEX_LINKAGE CXString clang_Cursor_getRawCommentText(CXCursor C);
+
+/**
* @}
*/
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 6ceed17eb8..172ac88edf 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -27,6 +27,7 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
+#include "clang/Comments/RawCommentList.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -51,7 +52,6 @@ namespace clang {
class ASTMutationListener;
class IdentifierTable;
class SelectorTable;
- class SourceManager;
class TargetInfo;
class CXXABI;
// Decls
@@ -418,6 +418,30 @@ public:
return FullSourceLoc(Loc,SourceMgr);
}
+ /// \brief All comments in this translation unit.
+ RawCommentList Comments;
+
+ /// \brief True if comments are already loaded from ExternalASTSource.
+ mutable bool CommentsLoaded;
+
+ /// \brief Mapping from declarations to their comments (stored within
+ /// Comments list), once we have already looked up the comment associated
+ /// with a given declaration.
+ mutable llvm::DenseMap<const Decl *, const RawComment *> DeclComments;
+
+ /// \brief Return the Doxygen-style comment attached to a given declaration,
+ /// without looking into cache.
+ const RawComment *getRawCommentForDeclNoCache(const Decl *D) const;
+
+public:
+ void addComment(const RawComment &RC) {
+ Comments.addComment(RC, *this);
+ }
+
+ /// \brief Return the Doxygen-style comment attached to a given declaration.
+ /// Returns NULL if no comment is attached.
+ const RawComment *getRawCommentForDecl(const Decl *D) const;
+
/// \brief Retrieve the attributes for the given declaration.
AttrVec& getDeclAttrs(const Decl *D);
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index e2a60d5cf0..7aedfe2ef6 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -179,6 +179,9 @@ public:
/// \c ObjCInterfaceDecl::setExternallyCompleted().
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
+ /// \brief Loads comment ranges.
+ virtual void ReadComments() { }
+
/// \brief Notify ExternalASTSource that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
/// decls that are initializing. Must be paired with FinishedDeserializing.
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 603bfebfd3..19fa52ee1d 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -1244,19 +1244,6 @@ public:
/// \returns true if LHS source location comes before RHS, false otherwise.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
- /// \brief Comparison function class.
- class LocBeforeThanCompare : public std::binary_function<SourceLocation,
- SourceLocation, bool> {
- SourceManager &SM;
-
- public:
- explicit LocBeforeThanCompare(SourceManager &SM) : SM(SM) { }
-
- bool operator()(SourceLocation LHS, SourceLocation RHS) const {
- return SM.isBeforeInTranslationUnit(LHS, RHS);
- }
- };
-
/// \brief Determines the order of 2 source locations in the "source location
/// address space".
bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const {
@@ -1500,6 +1487,35 @@ private:
friend class ASTWriter;
};
+/// \brief Comparison function object.
+template<typename T>
+class BeforeThanCompare;
+
+/// \brief Compare two source locations.
+template<>
+class BeforeThanCompare<SourceLocation> {
+ SourceManager &SM;
+
+public:
+ explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { }
+
+ bool operator()(SourceLocation LHS, SourceLocation RHS) const {
+ return SM.isBeforeInTranslationUnit(LHS, RHS);
+ }
+};
+
+/// \brief Compare two non-overlapping source ranges.
+template<>
+class BeforeThanCompare<SourceRange> {
+ SourceManager &SM;
+
+public:
+ explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { }
+
+ bool operator()(SourceRange LHS, SourceRange RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin());
+ }
+};
} // end namespace clang
diff --git a/include/clang/Comments/RawCommentList.h b/include/clang/Comments/RawCommentList.h
new file mode 100644
index 0000000000..bf0b616383
--- /dev/null
+++ b/include/clang/Comments/RawCommentList.h
@@ -0,0 +1,172 @@
+//===--- RawCommentList.h - Classes for 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_COMMENTS_RAW_COMMENT_LIST_H
+#define LLVM_CLANG_COMMENTS_RAW_COMMENT_LIST_H
+
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace clang {
+
+class ASTContext;
+class ASTReader;
+
+class RawComment {
+public:
+ enum CommentKind {
+ CK_Invalid, ///< Invalid comment
+ CK_OrdinaryBCPL, ///< Any normal BCPL comments
+ CK_OrdinaryC, ///< Any normal C comment
+ CK_BCPLSlash, ///< \code /// stuff \endcode
+ CK_BCPLExcl, ///< \code //! stuff \endcode
+ CK_JavaDoc, ///< \code /** stuff */ \endcode
+ CK_Qt, ///< \code /*! stuff */ \endcode, also used by HeaderDoc
+ CK_Merged ///< Two or more Doxygen comments merged together
+ };
+
+ RawComment() : Kind(CK_Invalid), IsAlmostTrailingComment(false) { }
+
+ RawComment(const SourceManager &SourceMgr, SourceRange SR,
+ bool Merged = false);
+
+ CommentKind getKind() const LLVM_READONLY {
+ return (CommentKind) Kind;
+ }
+
+ bool isInvalid() const LLVM_READONLY {
+ return Kind == CK_Invalid;
+ }
+
+ bool isMerged() const LLVM_READONLY {
+ return Kind == CK_Merged;
+ }
+
+ /// Returns true if it is a comment that should be put after a member:
+ /// \code ///< stuff \endcode
+ /// \code //!< stuff \endcode
+ /// \code /**< stuff */ \endcode
+ /// \code /*!< stuff */ \endcode
+ bool isTrailingComment() const LLVM_READONLY {
+ assert(isDoxygen());
+ return IsTrailingComment;
+ }
+
+ /// Returns true if it is a probable typo:
+ /// \code //< stuff \endcode
+ /// \code /*< stuff */ \endcode
+ bool isAlmostTrailingComment() const LLVM_READONLY {
+ return IsAlmostTrailingComment;
+ }
+
+ /// Returns true if this comment is not a Doxygen comment.
+ bool isOrdinary() const LLVM_READONLY {
+ return (Kind == CK_OrdinaryBCPL) || (Kind == CK_OrdinaryC);
+ }
+
+ /// Returns true if this comment any kind of a Doxygen comment.
+ bool isDoxygen() const LLVM_READONLY {
+ return !isInvalid() && !isOrdinary();
+ }
+
+ /// Returns raw comment text with comment markers.
+ StringRef getRawText(const SourceManager &SourceMgr) const {
+ if (RawTextValid)
+ return RawText;
+
+ RawText = getRawTextSlow(SourceMgr);
+ RawTextValid = true;
+ return RawText;
+ }
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return Range;
+ }
+
+ unsigned getBeginLine(const SourceManager &SM) const;
+ unsigned getEndLine(const SourceManager &SM) const;
+
+private:
+ SourceRange Range;
+
+ mutable StringRef RawText;
+ mutable bool RawTextValid : 1; ///< True if RawText is valid
+
+ unsigned Kind : 3;
+
+ bool IsTrailingComment : 1;
+ bool IsAlmostTrailingComment : 1;
+
+ mutable bool BeginLineValid : 1; ///< True if BeginLine is valid
+ mutable bool EndLineValid : 1; ///< True if EndLine is valid
+ mutable unsigned BeginLine; ///< Cached line number
+ mutable unsigned EndLine; ///< Cached line number
+
+ /// \brief Constructor for AST deserialization.
+ RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
+ bool IsAlmostTrailingComment) :
+ Range(SR), RawTextValid(false), Kind(K),
+ IsTrailingComment(IsTrailingComment),
+ IsAlmostTrailingComment(IsAlmostTrailingComment),
+ BeginLineValid(false), EndLineValid(false)
+ { }
+
+ StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
+
+ friend class ASTReader;
+};
+
+/// \brief Compare comments' source locations.
+template<>
+class BeforeThanCompare<RawComment> {
+ const SourceManager &SM;
+
+public:
+ explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
+
+ bool operator()(const RawComment &LHS, const SourceRange &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getSourceRange().getBegin(),
+ RHS.getBegin());
+ }
+};
+
+/// \brief This class represents all comments included in the translation unit,
+/// sorted in order of appearance in the translation unit.
+class RawCommentList {
+public:
+ RawCommentList(SourceManager &SourceMgr) :
+ SourceMgr(SourceMgr), OnlyWhitespaceSeen(true) { }
+
+ void addComment(const RawComment &RC, ASTContext &Context);
+
+ ArrayRef<RawComment> getComments() const {
+ return Comments;
+ }
+
+private:
+ SourceManager &SourceMgr;
+ std::vector<RawComment> Comments;
+ RawComment LastComment;
+ bool OnlyWhitespaceSeen;
+
+ void addCommentsToFront(const std::vector<RawComment> &C) {
+ size_t OldSize = Comments.size();
+ Comments.resize(C.size() + OldSize);
+ std::copy_backward(Comments.begin(), Comments.begin() + OldSize,
+ Comments.end());
+ std::copy(C.begin(), C.end(), Comments.begin());
+ }
+
+ friend class ASTReader;
+};
+
+} // end namespace clang
+
+#endif
+
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 7d3d6e1080..3b94a5725e 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -510,12 +510,12 @@ public:
}
/// \brief Add the specified comment handler to the preprocessor.
- void AddCommentHandler(CommentHandler *Handler);
+ void addCommentHandler(CommentHandler *Handler);
/// \brief Remove the specified comment handler.
///
/// It is an error to remove a handler that has not been registered.
- void RemoveCommentHandler(CommentHandler *Handler);
+ void removeCommentHandler(CommentHandler *Handler);
/// \brief Set the code completion handler to the given object.
void setCodeCompletionHandler(CodeCompletionHandler &Handler) {
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index cf308327f3..b451ed97e9 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -170,6 +170,7 @@ class Parser : public CodeCompletionHandler {
OwningPtr<PragmaHandler> RedefineExtnameHandler;
OwningPtr<PragmaHandler> FPContractHandler;
OwningPtr<PragmaHandler> OpenCLExtensionHandler;
+ OwningPtr<CommentHandler> CommentHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 408763f5cf..4be823a8db 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -849,6 +849,8 @@ public:
/// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls
SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+ void ActOnComment(SourceRange Comment);
+
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
//
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 42d0ad2467..2049da9730 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -207,7 +207,10 @@ namespace clang {
PREPROCESSOR_DETAIL_BLOCK_ID,
/// \brief The block containing the submodule structure.
- SUBMODULE_BLOCK_ID
+ SUBMODULE_BLOCK_ID,
+
+ /// \brief The block containing comments.
+ COMMENTS_BLOCK_ID
};
/// \brief Record types that occur within the AST block itself.
@@ -545,7 +548,12 @@ namespace clang {
/// \brief Specifies a required feature.
SUBMODULE_REQUIRES = 7
};
-
+
+ /// \brief Record types used within a comments block.
+ enum CommentRecordTypes {
+ COMMENTS_RAW_COMMENT = 0
+ };
+
/// \defgroup ASTAST AST file AST constants
///
/// The constants in this group describe various components of the
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 21fd674b2a..d084254ead 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -1501,6 +1501,13 @@ public:
SwitchCase *getSwitchCaseWithID(unsigned ID);
void ClearSwitchCaseIDs();
+
+ /// \brief Cursors for comments blocks.
+ SmallVector<std::pair<llvm::BitstreamCursor,
+ serialization::ModuleFile *>, 8> CommentsCursors;
+
+ /// \brief Loads comments ranges.
+ void ReadComments();
};
/// \brief Helper class that saves the current stream position and
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 16c3766f8f..472b407992 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -414,6 +414,7 @@ private:
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
void WriteTypeDeclOffsets();
void WriteFileDeclIDsMap();
+ void WriteComments();
void WriteSelectors(Sema &SemaRef);
void WriteReferencedSelectorsPool(Sema &SemaRef);
void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver,
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index 0f6c799374..d8fabcd948 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -44,7 +44,7 @@ static bool isEmptyARCMTMacroStatement(NullStmt *S,
SourceManager &SM = Ctx.getSourceManager();
std::vector<SourceLocation>::iterator
I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc,
- SourceManager::LocBeforeThanCompare(SM));
+ BeforeThanCompare<SourceLocation>(SM));
--I;
SourceLocation
AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 9ad3a7f2e7..d8677c2ee1 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -53,6 +53,107 @@ enum FloatingRank {
HalfRank, FloatRank, DoubleRank, LongDoubleRank
};
+const RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
+ if (!CommentsLoaded && ExternalSource) {
+ ExternalSource->ReadComments();
+ CommentsLoaded = true;
+ }
+
+ assert(D);
+
+ // TODO: handle comments for function parameters properly.
+ if (isa<ParmVarDecl>(D))
+ return NULL;
+
+ ArrayRef<RawComment> RawComments = Comments.getComments();
+
+ // If there are no comments anywhere, we won't find anything.
+ if (RawComments.empty())
+ return NULL;
+
+ // If the declaration doesn't map directly to a location in a file, we
+ // can't find the comment.
+ SourceLocation DeclLoc = D->getLocation();
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ return NULL;
+
+ // Find the comment that occurs just after this declaration.
+ ArrayRef<RawComment>::iterator Comment
+ = std::lower_bound(RawComments.begin(),
+ RawComments.end(),
+ SourceRange(DeclLoc),
+ BeforeThanCompare<RawComment>(SourceMgr));
+
+ // Decompose the location for the declaration and find the beginning of the
+ // file buffer.
+ std::pair<FileID, unsigned> DeclLocDecomp = SourceMgr.getDecomposedLoc(DeclLoc);
+
+ // First check whether we have a trailing comment.
+ if (Comment != RawComments.end() &&
+ Comment->isDoxygen() && Comment->isTrailingComment() &&
+ !isa<TagDecl>(D) && !isa<NamespaceDecl>(D)) {
+ std::pair<FileID, unsigned> CommentBeginDecomp
+ = SourceMgr.getDecomposedLoc(Comment->getSourceRange().getBegin());
+ // Check that Doxygen trailing comment comes after the declaration, starts
+ // on the same line and in the same file as the declaration.
+ if (DeclLocDecomp.first == CommentBeginDecomp.first &&
+ SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second)
+ == SourceMgr.getLineNumber(CommentBeginDecomp.first,
+ CommentBeginDecomp.second)) {
+ return &*Comment;
+ }
+ }
+
+ // The comment just after the declaration was not a trailing comment.
+ // Let's look at the previous comment.
+ if (Comment == RawComments.begin())
+ return NULL;
+ --Comment;
+
+ // Check that we actually have a non-member Doxygen comment.
+ if (!Comment->isDoxygen() || Comment->isTrailingComment())
+ return NULL;
+
+ // Decompose the end of the comment.
+ std::pair<FileID, unsigned> CommentEndDecomp
+ = SourceMgr.getDecomposedLoc(Comment->getSourceRange().getEnd());
+
+ // If the comment and the declaration aren't in the same file, then they
+ // aren't related.
+ if (DeclLocDecomp.first != CommentEndDecomp.first)
+ return NULL;
+
+ // Get the corresponding buffer.
+ bool Invalid = false;
+ const char *Buffer = SourceMgr.getBufferData(DeclLocDecomp.first,
+ &Invalid).data();
+ if (Invalid)
+ return NULL;
+
+ // Extract text between the comment and declaration.
+ StringRef Text(Buffer + CommentEndDecomp.second,
+ DeclLocDecomp.second - CommentEndDecomp.second);
+
+ // There should be no other declarations between comment and declaration.
+ if (Text.find_first_of(",;{}") != StringRef::npos)
+ return NULL;
+
+ return &*Comment;
+}
+
+const RawComment *ASTContext::getRawCommentForDecl(const Decl *D) const {
+ // Check whether we have cached a comment string for this declaration
+ // already.
+ llvm::DenseMap<const Decl *, const RawComment *>::iterator Pos
+ = DeclComments.find(D);
+ if (Pos != DeclComments.end())
+ return Pos->second;
+
+ const RawComment *RC = getRawCommentForDeclNoCache(D);
+ DeclComments[D] = RC;
+ return RC;
+}
+
void
ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
TemplateTemplateParmDecl *Parm) {
@@ -244,6 +345,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
BuiltinInfo(builtins),
DeclarationNames(*this),
ExternalSource(0), Listener(0),
+ Comments(SM), CommentsLoaded(false),
LastSDM(0, 0),
UniqueBlockByRefTypeID(0)
{
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index dfb9d61ff5..228b43b235 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -15,3 +15,4 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Tooling)
add_subdirectory(StaticAnalyzer)
+add_subdirectory(Comments)
diff --git a/lib/Comments/CMakeLists.txt b/lib/Comments/CMakeLists.txt
new file mode 100644
index 0000000000..f9561c649c
--- /dev/null
+++ b/lib/Comments/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(LLVM_USED_LIBS clangBasic clangAST clangLex)
+
+add_clang_library(clangComments
+ CommentLexer.cpp
+ RawCommentList.cpp
+ )
+
diff --git a/lib/Comments/Makefile b/lib/Comments/Makefile
new file mode 100644
index 0000000000..0783f1f26c
--- /dev/null
+++ b/lib/Comments/Makefile
@@ -0,0 +1,14 @@
+##===- clang/lib/Comments/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangComments
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Comments/RawCommentList.cpp b/lib/Comments/RawCommentList.cpp
new file mode 100644
index 0000000000..7db9175c17
--- /dev/null
+++ b/lib/Comments/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/Comments/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(