[Doc parsing] This patch searches overridden objc/c++
methods looking for documentation on a particular base
class inherited by any method that overrides the base class.
In case of redeclaration, as when objc method is defined
in the implementation, it also looks up for documentation
in class/class extension being redeclared.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165643 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8748618..a58eca6 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 @@
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 4336885..09f4290 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -151,13 +151,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
case Decl::ClassTemplatePartialSpecialization: {
const ClassTemplatePartialSpecializationDecl *CTPSD =
- cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
+ cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
Kind = ClassKind;
TemplateKind = TemplatePartialSpecialization;
TemplateParameters = CTPSD->getTemplateParameters();
@@ -246,7 +246,7 @@
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 @@
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 f6fb3b1..f9050d5 100644
--- a/lib/AST/CommentDumper.cpp
+++ b/lib/AST/CommentDumper.cpp
@@ -183,7 +183,7 @@
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 dd746ad..59dc6c7 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -36,7 +36,7 @@
return;
ThisDeclInfo = new (Allocator) DeclInfo;
- ThisDeclInfo->ThisDecl = D;
+ ThisDeclInfo->CommentDecl = D;
ThisDeclInfo->IsFilled = false;
}
@@ -413,7 +413,7 @@
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 @@
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 @@
if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
return;
- const Decl *D = ThisDeclInfo->ThisDecl;
+ const Decl *D = ThisDeclInfo->CommentDecl;
if (!D)
return;
@@ -574,7 +574,7 @@
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 @@
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 90b8807..f4a0bdf 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -859,6 +859,8 @@
/// 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) {