//===--- Comment.cpp - Comment AST node implementation --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/Comment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/CharInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" namespace clang { namespace comments { const char *Comment::getCommentKindName() const { switch (getCommentKind()) { case NoCommentKind: return "NoCommentKind"; #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ case CLASS##Kind: \ return #CLASS; #include "clang/AST/CommentNodes.inc" #undef COMMENT #undef ABSTRACT_COMMENT } llvm_unreachable("Unknown comment kind!"); } namespace { struct good {}; struct bad {}; template good implements_child_begin_end(Comment::child_iterator (T::*)() const) { return good(); } LLVM_ATTRIBUTE_UNUSED static inline bad implements_child_begin_end( Comment::child_iterator (Comment::*)() const) { return bad(); } #define ASSERT_IMPLEMENTS_child_begin(function) \ (void) good(implements_child_begin_end(function)) LLVM_ATTRIBUTE_UNUSED static inline void CheckCommentASTNodes() { #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); #include "clang/AST/CommentNodes.inc" #undef COMMENT #undef ABSTRACT_COMMENT } #undef ASSERT_IMPLEMENTS_child_begin } // end unnamed namespace Comment::child_iterator Comment::child_begin() const { switch (getCommentKind()) { case NoCommentKind: llvm_unreachable("comment without a kind"); #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ case CLASS##Kind: \ return static_cast(this)->child_begin(); #include "clang/AST/CommentNodes.inc" #undef COMMENT #undef ABSTRACT_COMMENT } llvm_unreachable("Unknown comment kind!"); } Comment::child_iterator Comment::child_end() const { switch (getCommentKind()) { case NoCommentKind: llvm_unreachable("comment without a kind"); #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ case CLASS##Kind: \ return static_cast(this)->child_end(); #include "clang/AST/CommentNodes.inc" #undef COMMENT #undef ABSTRACT_COMMENT } llvm_unreachable("Unknown comment kind!"); } bool TextComment::isWhitespaceNoCache() const { for (StringRef::const_iterator I = Text.begin(), E = Text.end(); I != E; ++I) { if (!clang::isWhitespace(*I)) return false; } return true; } bool ParagraphComment::isWhitespaceNoCache() const { for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { if (const TextComment *TC = dyn_cast(*I)) { if (!TC->isWhitespace()) return false; } else return false; } return true; } const char *ParamCommandComment::getDirectionAsString(PassDirection D) { switch (D) { case ParamCommandComment::In: return "[in]"; case ParamCommandComment::Out: return "[out]"; case ParamCommandComment::InOut: return "[in,out]"; } llvm_unreachable("unknown PassDirection"); } void DeclInfo::fill() { assert(!IsFilled); // Set defaults. Kind = OtherKind; TemplateKind = NotTemplate; IsObjCMethod = false; IsInstanceMethod = false; IsClassMethod = false; ParamVars = None; TemplateParameters = NULL; if (!CommentDecl) { // If there is no declaration, the defaults is our only guess. IsFilled = true; return; } CurrentDecl = CommentDecl; Decl::Kind K = CommentDecl->getKind(); switch (K) { default: // Defaults are should be good for declarations we don't handle explicitly. break; case Decl::Function: case Decl::CXXMethod: case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: { const FunctionDecl *FD = cast(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef(FD->param_begin(), FD->getNumParams()); ResultType = FD->getResultType(); unsigned NumLists = FD->getNumTemplateParameterLists(); if (NumLists != 0) { TemplateKind = TemplateSpecialization; TemplateParameters = FD->getTemplateParameterList(NumLists - 1); } if (K == Decl::CXXMethod || K == Decl::CXXConstructor || K == Decl::CXXDestructor || K == Decl::CXXConversion) { const CXXMethodDecl *MD = cast(CommentDecl); IsInstanceMethod = MD->isInstance(); IsClassMethod = !IsInstanceMethod; } break; } case Decl::ObjCMethod: { const ObjCMethodDecl *MD = cast(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef(MD->param_begin(), MD->param_size()); ResultType = MD->getResultType(); IsObjCMethod = true; IsInstanceMethod = MD->isInstanceMethod(); IsClassMethod = !IsInstanceMethod; break; } case Decl::FunctionTemplate: { const FunctionTemplateDecl *FTD = cast(CommentDecl); Kind = FunctionKind; TemplateKind = Template; const FunctionDecl *FD = FTD->getTemplatedDecl(); ParamVars = ArrayRef(FD->param_begin(), FD->getNumParams()); ResultType = FD->getResultType(); TemplateParameters = FTD->getTemplateParameters(); break; } case Decl::ClassTemplate: { const ClassTemplateDecl *CTD = cast(CommentDecl); Kind = ClassKind; TemplateKind = Template; TemplateParameters = CTD->getTemplateParameters(); break; } case Decl::ClassTemplatePartialSpecialization: { const ClassTemplatePartialSpecializationDecl *CTPSD = cast(CommentDecl); Kind = ClassKind; TemplateKind = TemplatePartialSpecialization; TemplateParameters = CTPSD->getTemplateParameters(); break; } case Decl::ClassTemplateSpecialization: Kind = ClassKind; TemplateKind = TemplateSpecialization; break; case Decl::Record: case Decl::CXXRecord: Kind = ClassKind; break; case Decl::Var: case Decl::Field: case Decl::EnumConstant: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: Kind = VariableKind; break; case Decl::Namespace: Kind = NamespaceKind; break; case Decl::Typedef: { Kind = TypedefKind; // If this is a typedef to something we consider a function, extract // arguments and return type. const TypedefDecl *TD = cast(CommentDecl); const TypeSourceInfo *TSI = TD->getTypeSourceInfo(); if (!TSI) break; TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); while (true) { TL = TL.IgnoreParens(); // Look through qualified types. if (QualifiedTypeLoc QualifiedTL = TL.getAs()) { TL = QualifiedTL.getUnqualifiedLoc(); continue; } // Look through pointer types. if (PointerTypeLoc PointerTL = TL.getAs()) { TL = PointerTL.getPointeeLoc().getUnqualifiedLoc(); continue; } if (BlockPointerTypeLoc BlockPointerTL = TL.getAs()) { TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); continue; } if (MemberPointerTypeLoc MemberPointerTL = TL.getAs()) { TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); continue; } // Is this a typedef for a function type? if (FunctionTypeLoc FTL = TL.getAs()) { Kind = FunctionKind; ArrayRef Params = FTL.getParams(); ParamVars = ArrayRef(Params.data(), Params.size()); ResultType = FTL.getResultLoc().getType(); break; } break; } break; } case Decl::TypeAlias: Kind = TypedefKind; break; case Decl::TypeAliasTemplate: { const TypeAliasTemplateDecl *TAT = cast(CommentDecl); Kind = TypedefKind; TemplateKind = Template; TemplateParameters = TAT->getTemplateParameters(); break; } case Decl::Enum: Kind = EnumKind; break; } IsFilled = true; } StringRef ParamCommandComment::getParamName(const FullComment *FC) const { assert(isParamIndexValid()); if (isVarArgParam()) return "..."; return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); } StringRef TParamCommandComment::getParamName(const FullComment *FC) const { assert(isPositionValid()); const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; for (unsigned i = 0, e = getDepth(); i != e; ++i) { if (i == e-1) return TPL->getParam(getIndex(i))->getName(); const NamedDecl *Param = TPL->getParam(getIndex(i)); if (const TemplateTemplateParmDecl *TTP = dyn_cast(Param)) TPL = TTP->getTemplateParameters(); } return ""; } } // end namespace comments } // end namespace clang