]> granicus.if.org Git - clang/commitdiff
[Doc parsing] This patch searches overridden objc/c++
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 10 Oct 2012 18:34:52 +0000 (18:34 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 10 Oct 2012 18:34:52 +0000 (18:34 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165643 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Comment.h
include/clang/AST/DeclObjC.h
lib/AST/ASTContext.cpp
lib/AST/Comment.cpp
lib/AST/CommentDumper.cpp
lib/AST/CommentSema.cpp
lib/AST/DeclObjC.cpp
test/Index/overriding-method-comments.mm [new file with mode: 0644]
tools/libclang/CXComment.cpp
unittests/AST/CommentParser.cpp

index cf43fc3e20347035d00e0c5098fad50eebbba7b5..ea039795e905e1c6c161a1316324df2fdf829378 100644 (file)
@@ -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
 
index 530546ecc3609ef82395d36118f911192a5b9a6f..5ff0514ae50183e2d33054640ebf6aa1befef25a 100644 (file)
@@ -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.
index 874861872a644a27fd1007a10e1cd371d87a3ede..a58eca6a0a4cfa499f691ddf3f75ddc551b8a3c9 100644 (file)
@@ -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
index 4336885d394cc23ebceb157e0c5503aa80117e30..09f4290f1b7d727370ea380d96d1c509509f0b2b 100644 (file)
@@ -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();
index f6fb3b1baa8a36fda50c0fbce34f2c7c280e608f..f9050d5f71a51ef49a8a2aea630e87eb4f886ffa 100644 (file)
@@ -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();
index dd746ad1196eb3fa8b4b825d7ee5c06d41f523ba..59dc6c729555377f77d2672525b6ce8651b98da3 100644 (file)
@@ -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;
 
index 90b8807be995da0a107a900469f1864a9ba6bab4..f4a0bdf38bebcfafa52f340e3b7dba9caa1320a4 100644 (file)
@@ -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 (file)
index 0000000..ab0e921
--- /dev/null
@@ -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>
index b0e190a204ad46397d675e33cf63c95dbafe11d8..5fac0d8779798be88a480dca9a903ef065ae45b6 100644 (file)
@@ -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);
 }
index d6b1f58f345e3cc8546260d4b0684fe0b9754f04..ab787c48ca1d17f5bdf9e924349977f33f60138f 100644 (file)
@@ -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()