diff options
author | Dmitri Gribenko <gribozavr@gmail.com> | 2012-08-11 00:51:43 +0000 |
---|---|---|
committer | Dmitri Gribenko <gribozavr@gmail.com> | 2012-08-11 00:51:43 +0000 |
commit | f50555eedef33fd5a67d369aa0ae8a6f1d201543 (patch) | |
tree | 8bce783eed109a75cf613bf47cf2e881fac5745c | |
parent | f9c29088a8f64d4af2423fb7b556419597c996df (diff) |
Attaching comments to declarations: find comment attached to any redeclaration
Not only look for the comment near the declaration itself, but also walk the
redeclaration chain: the previous declaration might have had a documentation
comment.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161722 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 53 | ||||
-rw-r--r-- | include/clang/AST/RawCommentList.h | 35 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 98 | ||||
-rw-r--r-- | lib/AST/RawCommentList.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 2 | ||||
-rw-r--r-- | test/Index/complete-documentation.cpp | 26 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 6 |
7 files changed, 190 insertions, 64 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 37a86dbd91..8fd7d6ef42 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -433,14 +433,57 @@ public: /// \brief True if comments are already loaded from ExternalASTSource. mutable bool CommentsLoaded; - typedef std::pair<const RawComment *, comments::FullComment *> - RawAndParsedComment; + class RawCommentAndCacheFlags { + public: + enum Kind { + /// We searched for a comment attached to the particular declaration, but + /// didn't find any. + /// + /// getRaw() == 0. + NoCommentInDecl = 0, + + /// We have found a comment attached to this particular declaration. + /// + /// getRaw() != 0. + FromDecl, + + /// This declaration does not have an attached comment, and we have + /// searched the redeclaration chain. + /// + /// If getRaw() == 0, the whole redeclaration chain does not have any + /// comments. + /// + /// If getRaw() != 0, it is a comment propagated from other + /// redeclaration. + FromRedecl + }; + + Kind getKind() const LLVM_READONLY { + return Data.getInt(); + } + + void setKind(Kind K) { + Data.setInt(K); + } + + const RawComment *getRaw() const LLVM_READONLY { + return Data.getPointer(); + } + + void setRaw(const RawComment *RC) { + Data.setPointer(RC); + } + + private: + llvm::PointerIntPair<const RawComment *, 2, Kind> Data; + }; - /// \brief Mapping from declarations to their comments. + /// \brief Mapping from declarations to comments attached to any + /// redeclaration. /// /// Raw comments are owned by Comments list. This mapping is populated /// lazily. - mutable llvm::DenseMap<const Decl *, RawAndParsedComment> DeclComments; + mutable llvm::DenseMap<const Decl *, RawCommentAndCacheFlags> RedeclComments; /// \brief Return the documentation comment attached to a given declaration, /// without looking into cache. @@ -457,7 +500,7 @@ public: /// \brief Return the documentation comment attached to a given declaration. /// Returns NULL if no comment is attached. - const RawComment *getRawCommentForDecl(const Decl *D) const; + const RawComment *getRawCommentForAnyRedecl(const Decl *D) const; /// Return parsed documentation comment attached to a given declaration. /// Returns NULL if no comment is attached. diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h index 370f4124c1..4901d07c3c 100644 --- a/include/clang/AST/RawCommentList.h +++ b/include/clang/AST/RawCommentList.h @@ -17,6 +17,11 @@ namespace clang { class ASTContext; class ASTReader; +class Decl; + +namespace comments { + class FullComment; +} // end namespace comments class RawComment { public: @@ -48,12 +53,18 @@ public: return Kind == RCK_Merged; } + /// Is this comment attached to any declaration? bool isAttached() const LLVM_READONLY { - return IsAttached; + return !DeclOrParsedComment.isNull(); } - void setAttached() { - IsAttached = true; + /// Return the declaration that this comment is attached to. + const Decl *getDecl() const; + + /// Set the declaration that this comment is attached to. + void setDecl(const Decl *D) { + assert(DeclOrParsedComment.isNull()); + DeclOrParsedComment = D; } /// Returns true if it is a comment that should be put after a member: @@ -107,20 +118,28 @@ public: return extractBriefText(Context); } + /// Returns a \c FullComment AST node, parsing the comment if needed. + comments::FullComment *getParsed(const ASTContext &Context) const { + if (comments::FullComment *FC = + DeclOrParsedComment.dyn_cast<comments::FullComment *>()) + return FC; + + return parse(Context); + } + private: SourceRange Range; mutable StringRef RawText; mutable const char *BriefText; + mutable llvm::PointerUnion<const Decl *, comments::FullComment *> + DeclOrParsedComment; mutable bool RawTextValid : 1; ///< True if RawText is valid mutable bool BriefTextValid : 1; ///< True if BriefText is valid unsigned Kind : 3; - /// True if comment is attached to a declaration in ASTContext. - bool IsAttached : 1; - bool IsTrailingComment : 1; bool IsAlmostTrailingComment : 1; @@ -133,7 +152,7 @@ private: RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment, bool IsAlmostTrailingComment) : Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K), - IsAttached(false), IsTrailingComment(IsTrailingComment), + IsTrailingComment(IsTrailingComment), IsAlmostTrailingComment(IsAlmostTrailingComment), BeginLineValid(false), EndLineValid(false) { } @@ -142,6 +161,8 @@ private: const char *extractBriefText(const ASTContext &Context) const; + comments::FullComment *parse(const ASTContext &Context) const; + friend class ASTReader; }; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4e8587d191..10cba7a813 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -13,11 +13,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" -#include "clang/AST/Comment.h" #include "clang/AST/CommentCommandTraits.h" -#include "clang/AST/CommentLexer.h" -#include "clang/AST/CommentSema.h" -#include "clang/AST/CommentParser.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -149,6 +145,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) == SourceMgr.getLineNumber(CommentBeginDecomp.first, CommentBeginDecomp.second)) { + (*Comment)->setDecl(D); return *Comment; } } @@ -188,59 +185,74 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (Text.find_first_of(",;{}#@") != StringRef::npos) return NULL; + (*Comment)->setDecl(D); 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 *, RawAndParsedComment>::iterator Pos - = DeclComments.find(D); - if (Pos != DeclComments.end()) { - RawAndParsedComment C = Pos->second; - return C.first; +const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { + // Check whether we have cached a comment for this declaration already. + { + llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos = + RedeclComments.find(D); + if (Pos != RedeclComments.end()) { + const RawCommentAndCacheFlags &Raw = Pos->second; + if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) + return Raw.getRaw(); + } + } + + // Search for comments attached to declarations in the redeclaration chain. + const RawComment *RC = NULL; + for (Decl::redecl_iterator I = D->redecls_begin(), + E = D->redecls_end(); + I != E; ++I) { + llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos = + RedeclComments.find(*I); + if (Pos != RedeclComments.end()) { + const RawCommentAndCacheFlags &Raw = Pos->second; + if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) { + RC = Raw.getRaw(); + break; + } + } else { + RC = getRawCommentForDeclNoCache(*I); + RawCommentAndCacheFlags Raw; + if (RC) { + Raw.setRaw(RC); + Raw.setKind(RawCommentAndCacheFlags::FromDecl); + } else + Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl); + RedeclComments[*I] = Raw; + if (RC) + break; + } } - RawComment *RC = getRawCommentForDeclNoCache(D); // If we found a comment, it should be a documentation comment. assert(!RC || RC->isDocumentation()); - DeclComments[D] = - RawAndParsedComment(RC, static_cast<comments::FullComment *>(NULL)); - if (RC) - RC->setAttached(); + + // Update cache for every declaration in the redeclaration chain. + RawCommentAndCacheFlags Raw; + Raw.setRaw(RC); + Raw.setKind(RawCommentAndCacheFlags::FromRedecl); + + for (Decl::redecl_iterator I = D->redecls_begin(), + E = D->redecls_end(); + I != E; ++I) { + RawCommentAndCacheFlags &R = RedeclComments[*I]; + if (R.getKind() == RawCommentAndCacheFlags::NoCommentInDecl) + R = Raw; + } + return RC; } comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const { - llvm::DenseMap<const Decl *, RawAndParsedComment>::iterator Pos - = DeclComments.find(D); - const RawComment *RC; - if (Pos != DeclComments.end()) { - RawAndParsedComment C = Pos->second; - if (comments::FullComment *FC = C.second) - return FC; - RC = C.first; - } else - RC = getRawCommentForDecl(D); - + const RawComment *RC = getRawCommentForAnyRedecl(D); if (!RC) return NULL; - const StringRef RawText = RC->getRawText(SourceMgr); - comments::CommandTraits Traits; - comments::Lexer L(getAllocator(), Traits, - RC->getSourceRange().getBegin(), comments::CommentOptions(), - RawText.begin(), RawText.end()); - - comments::Sema S(getAllocator(), getSourceManager(), getDiagnostics(), - Traits); - S.setDecl(D); - comments::Parser P(L, S, getAllocator(), getSourceManager(), - getDiagnostics(), Traits); - - comments::FullComment *FC = P.parseFullComment(); - DeclComments[D].second = FC; - return FC; + return RC->getParsed(*this); } void diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index 4f7165f0e4..c704cabe69 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -9,8 +9,11 @@ #include "clang/AST/RawCommentList.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Comment.h" #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentBriefParser.h" +#include "clang/AST/CommentSema.h" +#include "clang/AST/CommentParser.h" #include "clang/AST/CommentCommandTraits.h" #include "llvm/ADT/STLExtras.h" @@ -62,7 +65,7 @@ bool mergedCommentIsTrailingComment(StringRef Comment) { RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, bool Merged) : Range(SR), RawTextValid(false), BriefTextValid(false), - IsAttached(false), IsAlmostTrailingComment(false), + IsAlmostTrailingComment(false), BeginLineValid(false), EndLineValid(false) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { @@ -84,6 +87,16 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, } } +const Decl *RawComment::getDecl() const { + if (DeclOrParsedComment.isNull()) + return NULL; + + if (const Decl *D = DeclOrParsedComment.dyn_cast<const Decl *>()) + return D; + + return DeclOrParsedComment.get<comments::FullComment *>()->getDecl(); +} + unsigned RawComment::getBeginLine(const SourceManager &SM) const { if (BeginLineValid) return BeginLine; @@ -156,6 +169,25 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { return BriefTextPtr; } +comments::FullComment *RawComment::parse(const ASTContext &Context) const { + // Make sure that RawText is valid. + getRawText(Context.getSourceManager()); + + comments::CommandTraits Traits; + comments::Lexer L(Context.getAllocator(), Traits, + getSourceRange().getBegin(), comments::CommentOptions(), + RawText.begin(), RawText.end()); + comments::Sema S(Context.getAllocator(), Context.getSourceManager(), + Context.getDiagnostics(), Traits); + S.setDecl(getDecl()); + comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(), + Context.getDiagnostics(), Traits); + + comments::FullComment *FC = P.parseFullComment(); + DeclOrParsedComment = FC; + return FC; +} + namespace { bool containsOnlyWhitespace(StringRef Str) { return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 2e099e96a4..9fa757d50a 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2543,7 +2543,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, if (IncludeBriefComments) { // Add documentation comment, if it exists. - if (const RawComment *RC = Ctx.getRawCommentForDecl(ND)) { + if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(ND)) { Result.addBriefComment(RC->getBriefText(Ctx)); } } diff --git a/test/Index/complete-documentation.cpp b/test/Index/complete-documentation.cpp index 6cb7ca6b40..a64e62f239 100644 --- a/test/Index/complete-documentation.cpp +++ b/test/Index/complete-documentation.cpp @@ -17,17 +17,35 @@ public: namespace T5 { } -void test() { +struct T6 { + /// \brief Fff. + void T7(); + + /// \brief Ggg. + void T8(); +}; + +void T6::T7() { +} + +void test1() { T2 t2; - t2. + t2.T4; + + T6 t6; + t6.T8(); } -// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:21:1 %s | FileCheck -check-prefix=CC1 %s +// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:32:1 %s | FileCheck -check-prefix=CC1 %s // CHECK-CC1: FunctionDecl:{ResultType void}{TypedText T1}{{.*}}(brief comment: Aaa.) // CHECK-CC1: ClassDecl:{TypedText T2}{{.*}}(brief comment: Bbb.) // CHECK-CC1: Namespace:{TypedText T5}{{.*}}(brief comment: Eee.) -// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:23:6 %s | FileCheck -check-prefix=CC2 %s +// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:34:6 %s | FileCheck -check-prefix=CC2 %s // CHECK-CC2: CXXMethod:{ResultType void}{TypedText T3}{{.*}}(brief comment: Ccc.) // CHECK-CC2: FieldDecl:{ResultType int}{TypedText T4}{{.*}}(brief comment: Ddd.) + +// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:37:6 %s | FileCheck -check-prefix=CC3 %s +// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T7}{LeftParen (}{RightParen )} (34) (parent: StructDecl 'T6')(brief comment: Fff.) +// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T8}{LeftParen (}{RightParen )} (34) (parent: StructDecl 'T6')(brief comment: Ggg.) diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index b1e4bad14d..bd27b4cad1 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -5689,7 +5689,7 @@ CXSourceRange clang_Cursor_getCommentRange(CXCursor C) { const Decl *D = getCursorDecl(C); ASTContext &Context = getCursorContext(C); - const RawComment *RC = Context.getRawCommentForDecl(D); + const RawComment *RC = Context.getRawCommentForAnyRedecl(D); if (!RC) return clang_getNullRange(); @@ -5702,7 +5702,7 @@ CXString clang_Cursor_getRawCommentText(CXCursor C) { const Decl *D = getCursorDecl(C); ASTContext &Context = getCursorContext(C); - const RawComment *RC = Context.getRawCommentForDecl(D); + const RawComment *RC = Context.getRawCommentForAnyRedecl(D); StringRef RawText = RC ? RC->getRawText(Context.getSourceManager()) : StringRef(); @@ -5717,7 +5717,7 @@ CXString clang_Cursor_getBriefCommentText(CXCursor C) { const Decl *D = getCursorDecl(C); const ASTContext &Context = getCursorContext(C); - const RawComment *RC = Context.getRawCommentForDecl(D); + const RawComment *RC = Context.getRawCommentForAnyRedecl(D); if (RC) { StringRef BriefText = RC->getBriefText(Context); |