From 1c883b9b57001a73bc1f3db7536d2555eb78de5a Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 10 Oct 2012 18:34:52 +0000 Subject: [PATCH] [Doc parsing] This patch searches overridden objc/c++ methods looking for documentation on a particular base class inherited by any method that overrides the base class. In case of redeclaration, as when objc method is defined in the implementation, it also looks up for documentation in class/class extension being redeclared. llvm-svn: 165643 --- clang/include/clang/AST/Comment.h | 61 ++++++++++---- clang/include/clang/AST/DeclObjC.h | 3 +- clang/lib/AST/ASTContext.cpp | 60 ++++++++++++- clang/lib/AST/Comment.cpp | 20 ++--- clang/lib/AST/CommentDumper.cpp | 2 +- clang/lib/AST/CommentSema.cpp | 12 +-- clang/lib/AST/DeclObjC.cpp | 2 + clang/test/Index/overriding-method-comments.mm | 111 +++++++++++++++++++++++++ clang/tools/libclang/CXComment.cpp | 37 +++++---- clang/unittests/AST/CommentParser.cpp | 2 +- 10 files changed, 255 insertions(+), 55 deletions(-) create mode 100644 clang/test/Index/overriding-method-comments.mm diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h index cf43fc3..ea03979 100644 --- a/clang/include/clang/AST/Comment.h +++ b/clang/include/clang/AST/Comment.h @@ -17,6 +17,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/AST/Type.h" #include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/DeclObjC.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" @@ -727,7 +728,17 @@ public: return getNumArgs() > 0; } - StringRef getParamName() const { + StringRef getParamName(const Decl *OverridingDecl) const { + if (OverridingDecl && isParamIndexValid()) { + if (const ObjCMethodDecl *OMD = dyn_cast(OverridingDecl)) { + const ParmVarDecl *ParamDecl = OMD->param_begin()[getParamIndex()]; + return ParamDecl->getName(); + } + else if (const FunctionDecl *FD = dyn_cast(OverridingDecl)) { + const ParmVarDecl *ParamDecl = FD->param_begin()[getParamIndex()]; + return ParamDecl->getName(); + } + } return Args[0].Text; } @@ -936,22 +947,22 @@ public: /// Information about the declaration, useful to clients of FullComment. struct DeclInfo { /// Declaration the comment is attached to. Should not be NULL. - const Decl *ThisDecl; - - /// Parameters that can be referenced by \\param if \c ThisDecl is something + const Decl *CommentDecl; + + /// Parameters that can be referenced by \\param if \c CommentDecl is something /// that we consider a "function". ArrayRef ParamVars; - /// Function result type if \c ThisDecl is something that we consider + /// Function result type if \c CommentDecl is something that we consider /// a "function". QualType ResultType; - /// Template parameters that can be referenced by \\tparam if \c ThisDecl is + /// Template parameters that can be referenced by \\tparam if \c CommentDecl is /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is /// true). const TemplateParameterList *TemplateParameters; - /// A simplified description of \c ThisDecl kind that should be good enough + /// A simplified description of \c CommentDecl kind that should be good enough /// for documentation rendering purposes. enum DeclKind { /// Everything else not explicitly mentioned below. @@ -992,7 +1003,7 @@ struct DeclInfo { EnumKind }; - /// What kind of template specialization \c ThisDecl is. + /// What kind of template specialization \c CommentDecl is. enum TemplateDeclKind { NotTemplate, Template, @@ -1000,16 +1011,16 @@ struct DeclInfo { TemplatePartialSpecialization }; - /// If false, only \c ThisDecl is valid. + /// If false, only \c CommentDecl is valid. unsigned IsFilled : 1; - /// Simplified kind of \c ThisDecl, see\c DeclKind enum. + /// Simplified kind of \c CommentDecl, see\c DeclKind enum. unsigned Kind : 3; - /// Is \c ThisDecl a template declaration. + /// Is \c CommentDecl a template declaration. unsigned TemplateKind : 2; - /// Is \c ThisDecl an ObjCMethodDecl. + /// Is \c CommentDecl an ObjCMethodDecl. unsigned IsObjCMethod : 1; /// Is \c ThisDecl a non-static member function of C++ class or @@ -1017,7 +1028,7 @@ struct DeclInfo { /// Can be true only if \c IsFunctionDecl is true. unsigned IsInstanceMethod : 1; - /// Is \c ThisDecl a static member function of C++ class or + /// Is \c CommentDecl a static member function of C++ class or /// class method of ObjC class. /// Can be true only if \c IsFunctionDecl is true. unsigned IsClassMethod : 1; @@ -1038,11 +1049,16 @@ class FullComment : public Comment { llvm::ArrayRef Blocks; DeclInfo *ThisDeclInfo; + /// Declaration that a comment is being looked for. This declaration and + /// CommentDecl in ThisDeclInfo are generally the same. But they could be + /// different when ThisDecl does not have comment and uses CommentDecl's comment. + const Decl *ThisDecl; public: - FullComment(llvm::ArrayRef Blocks, DeclInfo *D) : + FullComment(llvm::ArrayRef Blocks, DeclInfo *D, + Decl *TD) : Comment(FullCommentKind, SourceLocation(), SourceLocation()), - Blocks(Blocks), ThisDeclInfo(D) { + Blocks(Blocks), ThisDeclInfo(D), ThisDecl(TD) { if (Blocks.empty()) return; @@ -1066,16 +1082,27 @@ public: } const Decl *getDecl() const LLVM_READONLY { - return ThisDeclInfo->ThisDecl; + return ThisDeclInfo->CommentDecl; } + const Decl *getDeclForCommentLookup() const LLVM_READONLY { + return ThisDecl; + } + const DeclInfo *getDeclInfo() const LLVM_READONLY { if (!ThisDeclInfo->IsFilled) ThisDeclInfo->fill(); return ThisDeclInfo; } + + DeclInfo *getThisDeclInfo() const LLVM_READONLY { + return ThisDeclInfo; + } + + llvm::ArrayRef getBlocks() const { return Blocks; } + }; - + } // end namespace comments } // end namespace clang diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 530546e..5ff0514 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -421,7 +421,8 @@ public: /// \brief Return overridden methods for the given \p Method. /// /// An ObjC method is considered to override any method in the class's - /// base classes, its protocols, or its categories' protocols, that has + /// base classes (and base's categories), its protocols, or its categories' + /// protocols, that has /// the same selector and is of the same kind (class or instance). /// A method in an implementation is not considered as overriding the same /// method in the interface or its categories. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8748618..a58eca6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Mangle.h" +#include "clang/AST/Comment.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -355,21 +356,72 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl( return RC; } +static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, + SmallVectorImpl &Redeclared) { + const DeclContext *DC = ObjCMethod->getDeclContext(); + if (const ObjCImplDecl *IMD = dyn_cast(DC)) { + const ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // Add redeclared method here. + for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + if (ObjCMethodDecl *RedeclaredMethod = + ClsExtDecl->getMethod(ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) + Redeclared.push_back(RedeclaredMethod); + } + } +} + comments::FullComment *ASTContext::getCommentForDecl( const Decl *D, const Preprocessor *PP) const { D = adjustDeclToTemplate(D); + const Decl *Canonical = D->getCanonicalDecl(); llvm::DenseMap::iterator Pos = ParsedComments.find(Canonical); - if (Pos != ParsedComments.end()) + + if (Pos != ParsedComments.end()) { + if (Canonical != D && + (isa(D) || isa(D))) { + // case of method being redeclaration of the canonical, not + // overriding it; i.e. method in implementation, canonical in + // interface. Or, out-of-line cxx-method definition. + comments::FullComment *FC = Pos->second; + comments::FullComment *CFC = + new (*this) comments::FullComment(FC->getBlocks(), + FC->getThisDeclInfo(), + const_cast(D)); + return CFC; + } return Pos->second; - + } + const Decl *OriginalDecl; + const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); - if (!RC) + if (!RC) { + if (isa(D) || isa(D)) { + SmallVector overridden; + if (const ObjCMethodDecl *OMD = dyn_cast(D)) + addRedeclaredMethods(OMD, overridden); + const_cast(this)->getOverriddenMethods(dyn_cast(D), + overridden); + for (unsigned i = 0, e = overridden.size(); i < e; i++) { + if (comments::FullComment *FC = getCommentForDecl(overridden[i], PP)) { + comments::FullComment *CFC = + new (*this) comments::FullComment(FC->getBlocks(), + FC->getThisDeclInfo(), + const_cast(D)); + return CFC; + } + } + } return NULL; - + } + // If the RawComment was attached to other redeclaration of this Decl, we // should parse the comment in context of that other Decl. This is important // because comments can contain references to parameter names which can be diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index 4336885..09f4290 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -151,13 +151,13 @@ void DeclInfo::fill() { ParamVars = ArrayRef(); TemplateParameters = NULL; - if (!ThisDecl) { + if (!CommentDecl) { // If there is no declaration, the defaults is our only guess. IsFilled = true; return; } - Decl::Kind K = ThisDecl->getKind(); + Decl::Kind K = CommentDecl->getKind(); switch (K) { default: // Defaults are should be good for declarations we don't handle explicitly. @@ -167,7 +167,7 @@ void DeclInfo::fill() { case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: { - const FunctionDecl *FD = cast(ThisDecl); + const FunctionDecl *FD = cast(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef(FD->param_begin(), FD->getNumParams()); @@ -181,14 +181,14 @@ void DeclInfo::fill() { if (K == Decl::CXXMethod || K == Decl::CXXConstructor || K == Decl::CXXDestructor || K == Decl::CXXConversion) { - const CXXMethodDecl *MD = cast(ThisDecl); + const CXXMethodDecl *MD = cast(CommentDecl); IsInstanceMethod = MD->isInstance(); IsClassMethod = !IsInstanceMethod; } break; } case Decl::ObjCMethod: { - const ObjCMethodDecl *MD = cast(ThisDecl); + const ObjCMethodDecl *MD = cast(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef(MD->param_begin(), MD->param_size()); @@ -199,7 +199,7 @@ void DeclInfo::fill() { break; } case Decl::FunctionTemplate: { - const FunctionTemplateDecl *FTD = cast(ThisDecl); + const FunctionTemplateDecl *FTD = cast(CommentDecl); Kind = FunctionKind; TemplateKind = Template; const FunctionDecl *FD = FTD->getTemplatedDecl(); @@ -210,7 +210,7 @@ void DeclInfo::fill() { break; } case Decl::ClassTemplate: { - const ClassTemplateDecl *CTD = cast(ThisDecl); + const ClassTemplateDecl *CTD = cast(CommentDecl); Kind = ClassKind; TemplateKind = Template; TemplateParameters = CTD->getTemplateParameters(); @@ -218,7 +218,7 @@ void DeclInfo::fill() { } case Decl::ClassTemplatePartialSpecialization: { const ClassTemplatePartialSpecializationDecl *CTPSD = - cast(ThisDecl); + cast(CommentDecl); Kind = ClassKind; TemplateKind = TemplatePartialSpecialization; TemplateParameters = CTPSD->getTemplateParameters(); @@ -246,7 +246,7 @@ void DeclInfo::fill() { Kind = TypedefKind; // If this is a typedef to something we consider a function, extract // arguments and return type. - const TypedefDecl *TD = cast(ThisDecl); + const TypedefDecl *TD = cast(CommentDecl); const TypeSourceInfo *TSI = TD->getTypeSourceInfo(); if (!TSI) break; @@ -290,7 +290,7 @@ void DeclInfo::fill() { Kind = TypedefKind; break; case Decl::TypeAliasTemplate: { - const TypeAliasTemplateDecl *TAT = cast(ThisDecl); + const TypeAliasTemplateDecl *TAT = cast(CommentDecl); Kind = TypedefKind; TemplateKind = Template; TemplateParameters = TAT->getTemplateParameters(); diff --git a/clang/lib/AST/CommentDumper.cpp b/clang/lib/AST/CommentDumper.cpp index f6fb3b1..f9050d5 100644 --- a/clang/lib/AST/CommentDumper.cpp +++ b/clang/lib/AST/CommentDumper.cpp @@ -183,7 +183,7 @@ void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) { OS << " implicitly"; if (C->hasParamName()) - OS << " Param=\"" << C->getParamName() << "\""; + OS << " Param=\"" << C->getParamName(0) << "\""; if (C->isParamIndexValid()) OS << " ParamIndex=" << C->getParamIndex(); diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index dd746ad..59dc6c7 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -36,7 +36,7 @@ void Sema::setDecl(const Decl *D) { return; ThisDeclInfo = new (Allocator) DeclInfo; - ThisDeclInfo->ThisDecl = D; + ThisDeclInfo->CommentDecl = D; ThisDeclInfo->IsFilled = false; } @@ -413,7 +413,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, FullComment *Sema::actOnFullComment( ArrayRef Blocks) { - FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); + FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo, 0); resolveParamCommandIndexes(FC); return FC; } @@ -441,7 +441,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { if (isFunctionDecl()) { if (ThisDeclInfo->ResultType->isVoidType()) { unsigned DiagKind; - switch (ThisDeclInfo->ThisDecl->getKind()) { + switch (ThisDeclInfo->CommentDecl->getKind()) { default: if (ThisDeclInfo->IsObjCMethod) DiagKind = 3; @@ -508,7 +508,7 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) return; - const Decl *D = ThisDeclInfo->ThisDecl; + const Decl *D = ThisDeclInfo->CommentDecl; if (!D) return; @@ -574,7 +574,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { ParamCommandComment *PCC = dyn_cast(*I); if (!PCC || !PCC->hasParamName()) continue; - StringRef ParamName = PCC->getParamName(); + StringRef ParamName = PCC->getParamName(0); // Check that referenced parameter name is in the function decl. const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, @@ -609,7 +609,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { const ParamCommandComment *PCC = UnresolvedParamCommands[i]; SourceRange ArgRange = PCC->getParamNameRange(); - StringRef ParamName = PCC->getParamName(); + StringRef ParamName = PCC->getParamName(0); Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) << ParamName << ArgRange; diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 90b8807..f4a0bdf 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -859,6 +859,8 @@ static void collectOnCategoriesAfterLocation(SourceLocation Loc, /// overrides lookup that it does for methods, inside implementations, will /// stop at the interface level (if there is a method there) and not look /// further in super classes. +/// Methods in an implementation can overide methods in super class's category +/// but not in current class's category. But, such methods static void collectOverriddenMethodsFast(SourceManager &SM, const ObjCMethodDecl *Method, SmallVectorImpl &Methods) { diff --git a/clang/test/Index/overriding-method-comments.mm b/clang/test/Index/overriding-method-comments.mm new file mode 100644 index 0000000..ab0e921 --- /dev/null +++ b/clang/test/Index/overriding-method-comments.mm @@ -0,0 +1,111 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s > %t/out +// RUN: FileCheck %s < %t/out +// rdar://12378793 + +// Ensure that XML we generate is not invalid. +// RUN: FileCheck %s -check-prefix=WRONG < %t/out +// WRONG-NOT: CommentXMLInvalid + +@protocol P +- (void)METH:(id)PPP; +@end + +@interface Root

+/** + * \param[in] AAA ZZZ + */ +- (void)METH:(id)AAA; +@end + +@interface Sub : Root +@end + +@interface Sub (CAT) +- (void)METH:(id)BBB; +@end + +@implementation Sub(CAT) +- (void)METH:(id)III {} +@end + +// CHECK: FullCommentAsHTML=[

AAA
ZZZ
] FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:AAA0in ZZZ + +// CHECK: FullCommentAsHTML=[
BBB
ZZZ
] FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:BBB0in ZZZ + +// CHECK: FullCommentAsHTML=[
III
ZZZ
] FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:III0in ZZZ + +@interface Redec : Root +@end + +@interface Redec() +/** + * \param[in] AAA input value + * \param[out] CCC output value is int + * \param[in] BBB 2nd input value is double + */ +- (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC; +@end + +@implementation Redec +- (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {} +@end + +// CHECK: FullCommentAsHTML=[
AAA
input value
BBB
2nd input value is double
CCC
output value is int
] FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::AAA0in input value BBB1in 2nd input value is double CCC2out output value is int + +// CHECK: FullCommentAsHTML=[
PPP
input value
QQQ
2nd input value is double
RRR
output value is int
] FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::PPP0in input value QQQ1in 2nd input value is double RRR2out output value is int + +struct Base { + /// \brief Does something. + /// \param AAA argument to foo_pure. + virtual void foo_pure(int AAA) = 0; + + /// \brief Does something. + /// \param BBB argument to defined virtual. + virtual void foo_inline(int BBB) {} + + /// \brief Does something. + /// \param CCC argument to undefined virtual. + virtual void foo_outofline(int CCC); +}; + +void Base::foo_outofline(int RRR) {} + +struct Derived : public Base { + virtual void foo_pure(int PPP); + + virtual void foo_inline(int QQQ) {} +}; + +/// \brief Does something. +/// \param DDD a value. +void foo(int DDD); + +void foo(int SSS) {} + +/// \brief Does something. +/// \param EEE argument to function decl. +void foo1(int EEE); + +void foo1(int TTT); + +// CHECK: FullCommentAsHTML=[

Does something.

AAA
argument to foo_pure.
] FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I# Does something. AAA0in argument to foo_pure. + +// CHECK: FullCommentAsHTML=[

Does something.

BBB
argument to defined virtual.
] FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I# Does something. BBB0in argument to defined virtual. + +// CHECK: FullCommentAsHTML=[

Does something.

CCC
argument to undefined virtual.
] FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I# Does something. CCC0in argument to undefined virtual. + +// CHECK: FullCommentAsHTML=[

Does something.

RRR
argument to undefined virtual.
] FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I# Does something. RRR0in argument to undefined virtual. + +// CHECK: FullCommentAsHTML=[

Does something.

PPP
argument to foo_pure.
] FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I# Does something. PPP0in argument to foo_pure. + +// CHECK: FullCommentAsHTML=[

Does something.

QQQ
argument to defined virtual.
] FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I# Does something. QQQ0in argument to defined virtual. + +// CHECK: FullCommentAsHTML=[

Does something.

DDD
a value.
] FullCommentAsXML=[fooc:@F@foo#I# Does something. DDD0in a value. + +// CHECK: FullCommentAsHTML=[

Does something.

SSS
a value.
] FullCommentAsXML=[fooc:@F@foo#I# Does something. SSS0in a value. + +// CHECK: FullCommentAsHTML=[

Does something.

EEE
argument to function decl.
] FullCommentAsXML=[foo1c:@F@foo1#I# Does something. EEE0in argument to function decl. + +// CHECK: FullCommentAsHTML=[

Does something.

TTT
argument to function decl.
] FullCommentAsXML=[foo1c:@F@foo1#I# Does something. TTT0in argument to function decl. diff --git a/clang/tools/libclang/CXComment.cpp b/clang/tools/libclang/CXComment.cpp index b0e190a..5fac0d8 100644 --- a/clang/tools/libclang/CXComment.cpp +++ b/clang/tools/libclang/CXComment.cpp @@ -254,7 +254,7 @@ CXString clang_ParamCommandComment_getParamName(CXComment CXC) { if (!PCC || !PCC->hasParamName()) return createCXString((const char *) 0); - return createCXString(PCC->getParamName(), /*DupString=*/ false); + return createCXString(PCC->getParamName(0), /*DupString=*/ false); } unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) { @@ -535,9 +535,10 @@ class CommentASTToHTMLConverter : public ConstCommentVisitor { public: /// \param Str accumulator for HTML. - CommentASTToHTMLConverter(SmallVectorImpl &Str, + CommentASTToHTMLConverter(FullComment *FC, + SmallVectorImpl &Str, const CommandTraits &Traits) : - Result(Str), Traits(Traits) + FC(FC), Result(Str), Traits(Traits) { } // Inline content. @@ -566,6 +567,7 @@ public: void appendToResultWithHTMLEscaping(StringRef S); private: + FullComment *FC; /// Output stream for HTML. llvm::raw_svector_ostream Result; @@ -669,7 +671,7 @@ void CommentASTToHTMLConverter::visitParamCommandComment( } else Result << "
"; - appendToResultWithHTMLEscaping(C->getParamName()); + appendToResultWithHTMLEscaping(C->getParamName(FC->getDeclForCommentLookup())); Result << "
"; if (C->isParamIndexValid()) { @@ -827,7 +829,7 @@ CXString clang_HTMLTagComment_getAsString(CXComment CXC) { return createCXString((const char *) 0); SmallString<128> HTML; - CommentASTToHTMLConverter Converter(HTML, getCommandTraits(CXC)); + CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC)); Converter.visit(HTC); return createCXString(HTML.str(), /* DupString = */ true); } @@ -838,7 +840,8 @@ CXString clang_FullComment_getAsHTML(CXComment CXC) { return createCXString((const char *) 0); SmallString<1024> HTML; - CommentASTToHTMLConverter Converter(HTML, getCommandTraits(CXC)); + CommentASTToHTMLConverter Converter(const_cast(FC), + HTML, getCommandTraits(CXC)); Converter.visit(FC); return createCXString(HTML.str(), /* DupString = */ true); } @@ -850,10 +853,11 @@ class CommentASTToXMLConverter : public ConstCommentVisitor { public: /// \param Str accumulator for XML. - CommentASTToXMLConverter(SmallVectorImpl &Str, + CommentASTToXMLConverter(FullComment *FC, + SmallVectorImpl &Str, const CommandTraits &Traits, const SourceManager &SM) : - Result(Str), Traits(Traits), SM(SM) { } + FC(FC), Result(Str), Traits(Traits), SM(SM) { } // Inline content. void visitTextComment(const TextComment *C); @@ -876,6 +880,8 @@ public: void appendToResultWithXMLEscaping(StringRef S); private: + FullComment *FC; + /// Output stream for XML. llvm::raw_svector_ostream Result; @@ -954,7 +960,7 @@ void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandCommen void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) { Result << ""; - appendToResultWithXMLEscaping(C->getParamName()); + appendToResultWithXMLEscaping(C->getParamName(FC->getDeclForCommentLookup())); Result << ""; if (C->isParamIndexValid()) @@ -1090,7 +1096,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { { // Print line and column number. - SourceLocation Loc = DI->ThisDecl->getLocation(); + SourceLocation Loc = DI->CommentDecl->getLocation(); std::pair LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; @@ -1111,7 +1117,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { Result << ">"; bool FoundName = false; - if (const NamedDecl *ND = dyn_cast(DI->ThisDecl)) { + if (const NamedDecl *ND = dyn_cast(DI->CommentDecl)) { if (DeclarationName DeclName = ND->getDeclName()) { Result << ""; std::string Name = DeclName.getAsString(); @@ -1126,7 +1132,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { { // Print USR. SmallString<128> USR; - cxcursor::getDeclCursorUSR(DI->ThisDecl, USR); + cxcursor::getDeclCursorUSR(DI->CommentDecl, USR); if (!USR.empty()) { Result << ""; appendToResultWithXMLEscaping(USR); @@ -1171,8 +1177,8 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { Result << ""; } - if (DI->ThisDecl->hasAttrs()) { - const AttrVec &Attrs = DI->ThisDecl->getAttrs(); + if (DI->CommentDecl->hasAttrs()) { + const AttrVec &Attrs = DI->CommentDecl->getAttrs(); for (unsigned i = 0, e = Attrs.size(); i != e; i++) { const AvailabilityAttr *AA = dyn_cast(Attrs[i]); if (!AA) { @@ -1295,7 +1301,8 @@ CXString clang_FullComment_getAsXML(CXComment CXC) { SourceManager &SM = static_cast(TU->TUData)->getSourceManager(); SmallString<1024> XML; - CommentASTToXMLConverter Converter(XML, getCommandTraits(CXC), SM); + CommentASTToXMLConverter Converter(const_cast(FC), XML, + getCommandTraits(CXC), SM); Converter.visit(FC); return createCXString(XML.str(), /* DupString = */ true); } diff --git a/clang/unittests/AST/CommentParser.cpp b/clang/unittests/AST/CommentParser.cpp index d6b1f58..ab787c4 100644 --- a/clang/unittests/AST/CommentParser.cpp +++ b/clang/unittests/AST/CommentParser.cpp @@ -213,7 +213,7 @@ template return ::testing::AssertionFailure() << "ParamCommandComment has no parameter name"; - StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamName() : ""; + StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamName(0) : ""; if (ActualParamName != ParamName) return ::testing::AssertionFailure() << "ParamCommandComment has parameter name \"" << ActualParamName.str() -- 2.7.4