diff options
-rw-r--r-- | include/clang/AST/Comment.h | 61 | ||||
-rw-r--r-- | include/clang/AST/DeclObjC.h | 3 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 60 | ||||
-rw-r--r-- | lib/AST/Comment.cpp | 20 | ||||
-rw-r--r-- | lib/AST/CommentDumper.cpp | 2 | ||||
-rw-r--r-- | lib/AST/CommentSema.cpp | 12 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 2 | ||||
-rw-r--r-- | test/Index/overriding-method-comments.mm | 111 | ||||
-rw-r--r-- | tools/libclang/CXComment.cpp | 37 | ||||
-rw-r--r-- | unittests/AST/CommentParser.cpp | 2 |
10 files changed, 255 insertions, 55 deletions
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h index cf43fc3e20..ea039795e9 100644 --- a/include/clang/AST/Comment.h +++ b/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<ObjCMethodDecl>(OverridingDecl)) { + const ParmVarDecl *ParamDecl = OMD->param_begin()[getParamIndex()]; + return ParamDecl->getName(); + } + else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(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<const ParmVarDecl *> 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<BlockContentComment *> 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<BlockContentComment *> Blocks, DeclInfo *D) : + FullComment(llvm::ArrayRef<BlockContentComment *> 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<BlockContentComment *> getBlocks() const { return Blocks; } + }; - + } // end namespace comments } // end namespace clang diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 530546ecc3..5ff0514ae5 100644 --- a/include/clang/AST/DeclObjC.h +++ b/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/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 874861872a..a58eca6a0a 100644 --- a/lib/AST/ASTContext.cpp +++ b/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<const NamedDecl *> &Redeclared) { + const DeclContext *DC = ObjCMethod->getDeclContext(); + if (const ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(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<const Decl *, comments::FullComment *>::iterator Pos = ParsedComments.find(Canonical); - if (Pos != ParsedComments.end()) + + if (Pos != ParsedComments.end()) { + if (Canonical != D && + (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(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<Decl *>(D)); + return CFC; + } return Pos->second; - + } + const Decl *OriginalDecl; + const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); - if (!RC) + if (!RC) { + if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { + SmallVector<const NamedDecl*, 8> overridden; + if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) + addRedeclaredMethods(OMD, overridden); + const_cast<ASTContext *>(this)->getOverriddenMethods(dyn_cast<NamedDecl>(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<Decl *>(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/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 4336885d39..09f4290f1b 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -151,13 +151,13 @@ void DeclInfo::fill() { ParamVars = ArrayRef<const ParmVarDecl *>(); 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<FunctionDecl>(ThisDecl); + const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef<const ParmVarDecl *>(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<CXXMethodDecl>(ThisDecl); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); IsInstanceMethod = MD->isInstance(); IsClassMethod = !IsInstanceMethod; } break; } case Decl::ObjCMethod: { - const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl); + const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(), MD->param_size()); @@ -199,7 +199,7 @@ void DeclInfo::fill() { break; } case Decl::FunctionTemplate: { - const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl); + const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(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<ClassTemplateDecl>(ThisDecl); + const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); Kind = ClassKind; TemplateKind = Template; TemplateParameters = CTD->getTemplateParameters(); @@ -218,7 +218,7 @@ void DeclInfo::fill() { } case Decl::ClassTemplatePartialSpecialization: { const ClassTemplatePartialSpecializationDecl *CTPSD = - cast<ClassTemplatePartialSpecializationDecl>(ThisDecl); + cast<ClassTemplatePartialSpecializationDecl>(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<TypedefDecl>(ThisDecl); + const TypedefDecl *TD = cast<TypedefDecl>(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<TypeAliasTemplateDecl>(ThisDecl); + const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); Kind = TypedefKind; TemplateKind = Template; TemplateParameters = TAT->getTemplateParameters(); diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp index f6fb3b1baa..f9050d5f71 100644 --- a/lib/AST/CommentDumper.cpp +++ b/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/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index dd746ad119..59dc6c7295 100644 --- a/lib/AST/CommentSema.cpp +++ b/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<BlockContentComment *> 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<ParamCommandComment>(*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/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 90b8807be9..f4a0bdf38b 100644 --- a/lib/AST/DeclObjC.cpp +++ b/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<const ObjCMethodDecl *> &Methods) { diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm new file mode 100644 index 0000000000..ab0e9217db --- /dev/null +++ b/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<P> +/** + * \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=[<dl><dt class="param-name-index-0">AAA</dt><dd class="param-descr-index-0"> ZZZ </dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="19" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<dl><dt class="param-name-index-0">BBB</dt><dd class="param-descr-index-0"> ZZZ </dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="19" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<dl><dt class="param-name-index-0">III</dt><dd class="param-descr-index-0"> ZZZ </dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="19" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function> + +@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=[<dl><dt class="param-name-index-0">AAA</dt><dd class="param-descr-index-0"> input value </dd><dt class="param-name-index-1">BBB</dt><dd class="param-descr-index-1"> 2nd input value is double </dd><dt class="param-name-index-2">CCC</dt><dd class="param-descr-index-2"> output value is int </dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="48" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<dl><dt class="param-name-index-0">PPP</dt><dd class="param-descr-index-0"> input value </dd><dt class="param-name-index-1">QQQ</dt><dd class="param-descr-index-1"> 2nd input value is double </dd><dt class="param-name-index-2">RRR</dt><dd class="param-descr-index-2"> output value is int </dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="48" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function> + +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=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">AAA</dt><dd class="param-descr-index-0"> argument to foo_pure.</dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="62" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">BBB</dt><dd class="param-descr-index-0"> argument to defined virtual.</dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="66" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">CCC</dt><dd class="param-descr-index-0"> argument to undefined virtual.</dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="70" column="16"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>CCC</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">RRR</dt><dd class="param-descr-index-0"> argument to undefined virtual.</dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="70" column="16"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">PPP</dt><dd class="param-descr-index-0"> argument to foo_pure.</dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="62" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">QQQ</dt><dd class="param-descr-index-0"> argument to defined virtual.</dd></dl>] FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="66" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>QQQ</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">DDD</dt><dd class="param-descr-index-0"> a value.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="83" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>DDD</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">SSS</dt><dd class="param-descr-index-0"> a value.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="83" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>SSS</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">EEE</dt><dd class="param-descr-index-0"> argument to function decl. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="89" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>EEE</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl. </Para></Discussion></Parameter></Parameters></Function> + +// CHECK: FullCommentAsHTML=[<p class="para-brief"> Does something. </p><dl><dt class="param-name-index-0">TTT</dt><dd class="param-descr-index-0"> argument to function decl. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="89" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>TTT</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl. </Para></Discussion></Parameter></Parameters></Function> diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp index b0e190a204..5fac0d8779 100644 --- a/tools/libclang/CXComment.cpp +++ b/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<CommentASTToHTMLConverter> { public: /// \param Str accumulator for HTML. - CommentASTToHTMLConverter(SmallVectorImpl<char> &Str, + CommentASTToHTMLConverter(FullComment *FC, + SmallVectorImpl<char> &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 << "<dt class=\"param-name-index-invalid\">"; - appendToResultWithHTMLEscaping(C->getParamName()); + appendToResultWithHTMLEscaping(C->getParamName(FC->getDeclForCommentLookup())); Result << "</dt>"; 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<FullComment *>(FC), + HTML, getCommandTraits(CXC)); Converter.visit(FC); return createCXString(HTML.str(), /* DupString = */ true); } @@ -850,10 +853,11 @@ class CommentASTToXMLConverter : public ConstCommentVisitor<CommentASTToXMLConverter> { public: /// \param Str accumulator for XML. - CommentASTToXMLConverter(SmallVectorImpl<char> &Str, + CommentASTToXMLConverter(FullComment *FC, + SmallVectorImpl<char> &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 << "<Parameter><Name>"; - appendToResultWithXMLEscaping(C->getParamName()); + appendToResultWithXMLEscaping(C->getParamName(FC->getDeclForCommentLookup())); Result << "</Name>"; 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<FileID, unsigned> 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<NamedDecl>(DI->ThisDecl)) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) { if (DeclarationName DeclName = ND->getDeclName()) { Result << "<Name>"; 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 << "<USR>"; appendToResultWithXMLEscaping(USR); @@ -1171,8 +1177,8 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { Result << "</ResultDiscussion>"; } - 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<AvailabilityAttr>(Attrs[i]); if (!AA) { @@ -1295,7 +1301,8 @@ CXString clang_FullComment_getAsXML(CXComment CXC) { SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager(); SmallString<1024> XML; - CommentASTToXMLConverter Converter(XML, getCommandTraits(CXC), SM); + CommentASTToXMLConverter Converter(const_cast<FullComment *>(FC), XML, + getCommandTraits(CXC), SM); Converter.visit(FC); return createCXString(XML.str(), /* DupString = */ true); } diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp index d6b1f58f34..ab787c48ca 100644 --- a/unittests/AST/CommentParser.cpp +++ b/unittests/AST/CommentParser.cpp @@ -213,7 +213,7 @@ template <typename T> 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() |