зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
f9c29088a8
Коммит
f50555eede
|
@ -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,
|
||||
|
||||
/// \brief Mapping from declarations to their comments.
|
||||
/// 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 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.
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,17 +17,35 @@ public:
|
|||
namespace T5 {
|
||||
}
|
||||
|
||||
void test() {
|
||||
struct T6 {
|
||||
/// \brief Fff.
|
||||
void T7();
|
||||
|
||||
T2 t2;
|
||||
t2.
|
||||
/// \brief Ggg.
|
||||
void T8();
|
||||
};
|
||||
|
||||
void T6::T7() {
|
||||
}
|
||||
|
||||
// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:21:1 %s | FileCheck -check-prefix=CC1 %s
|
||||
void test1() {
|
||||
|
||||
T2 t2;
|
||||
t2.T4;
|
||||
|
||||
T6 t6;
|
||||
t6.T8();
|
||||
}
|
||||
|
||||
// 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.)
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче