summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Comment.h61
-rw-r--r--include/clang/AST/DeclObjC.h3
-rw-r--r--lib/AST/ASTContext.cpp60
-rw-r--r--lib/AST/Comment.cpp20
-rw-r--r--lib/AST/CommentDumper.cpp2
-rw-r--r--lib/AST/CommentSema.cpp12
-rw-r--r--lib/AST/DeclObjC.cpp2
-rw-r--r--test/Index/overriding-method-comments.mm111
-rw-r--r--tools/libclang/CXComment.cpp37
-rw-r--r--unittests/AST/CommentParser.cpp2
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()