10b57cec5SDimitry Andric //===--- Comment.cpp - Comment AST node implementation --------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/AST/Comment.h" 100b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 110b57cec5SDimitry Andric #include "clang/AST/Decl.h" 120b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h" 130b57cec5SDimitry Andric #include "clang/AST/DeclTemplate.h" 140b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h" 150b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 16a7dea167SDimitry Andric #include <type_traits> 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric namespace clang { 190b57cec5SDimitry Andric namespace comments { 200b57cec5SDimitry Andric 21a7dea167SDimitry Andric // Check that no comment class has a non-trival destructor. They are allocated 22a7dea167SDimitry Andric // with a BumpPtrAllocator and therefore their destructor is not executed. 23a7dea167SDimitry Andric #define ABSTRACT_COMMENT(COMMENT) 24a7dea167SDimitry Andric #define COMMENT(CLASS, PARENT) \ 25a7dea167SDimitry Andric static_assert(std::is_trivially_destructible<CLASS>::value, \ 26a7dea167SDimitry Andric #CLASS " should be trivially destructible!"); 27a7dea167SDimitry Andric #include "clang/AST/CommentNodes.inc" 28a7dea167SDimitry Andric #undef COMMENT 29a7dea167SDimitry Andric #undef ABSTRACT_COMMENT 30a7dea167SDimitry Andric 31a7dea167SDimitry Andric // DeclInfo is also allocated with a BumpPtrAllocator. 32bdd1243dSDimitry Andric static_assert(std::is_trivially_destructible_v<DeclInfo>, 33a7dea167SDimitry Andric "DeclInfo should be trivially destructible!"); 34a7dea167SDimitry Andric 350b57cec5SDimitry Andric const char *Comment::getCommentKindName() const { 360b57cec5SDimitry Andric switch (getCommentKind()) { 37*5f757f3fSDimitry Andric case CommentKind::None: 38*5f757f3fSDimitry Andric return "None"; 390b57cec5SDimitry Andric #define ABSTRACT_COMMENT(COMMENT) 400b57cec5SDimitry Andric #define COMMENT(CLASS, PARENT) \ 41*5f757f3fSDimitry Andric case CommentKind::CLASS: \ 420b57cec5SDimitry Andric return #CLASS; 430b57cec5SDimitry Andric #include "clang/AST/CommentNodes.inc" 440b57cec5SDimitry Andric #undef COMMENT 450b57cec5SDimitry Andric #undef ABSTRACT_COMMENT 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric llvm_unreachable("Unknown comment kind!"); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric namespace { 510b57cec5SDimitry Andric struct good {}; 520b57cec5SDimitry Andric struct bad {}; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric template <typename T> 550b57cec5SDimitry Andric good implements_child_begin_end(Comment::child_iterator (T::*)() const) { 560b57cec5SDimitry Andric return good(); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric LLVM_ATTRIBUTE_UNUSED 600b57cec5SDimitry Andric static inline bad implements_child_begin_end( 610b57cec5SDimitry Andric Comment::child_iterator (Comment::*)() const) { 620b57cec5SDimitry Andric return bad(); 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric #define ASSERT_IMPLEMENTS_child_begin(function) \ 660b57cec5SDimitry Andric (void) good(implements_child_begin_end(function)) 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric LLVM_ATTRIBUTE_UNUSED 690b57cec5SDimitry Andric static inline void CheckCommentASTNodes() { 700b57cec5SDimitry Andric #define ABSTRACT_COMMENT(COMMENT) 710b57cec5SDimitry Andric #define COMMENT(CLASS, PARENT) \ 720b57cec5SDimitry Andric ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ 730b57cec5SDimitry Andric ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); 740b57cec5SDimitry Andric #include "clang/AST/CommentNodes.inc" 750b57cec5SDimitry Andric #undef COMMENT 760b57cec5SDimitry Andric #undef ABSTRACT_COMMENT 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric #undef ASSERT_IMPLEMENTS_child_begin 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric } // end unnamed namespace 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric Comment::child_iterator Comment::child_begin() const { 840b57cec5SDimitry Andric switch (getCommentKind()) { 85*5f757f3fSDimitry Andric case CommentKind::None: 86*5f757f3fSDimitry Andric llvm_unreachable("comment without a kind"); 870b57cec5SDimitry Andric #define ABSTRACT_COMMENT(COMMENT) 880b57cec5SDimitry Andric #define COMMENT(CLASS, PARENT) \ 89*5f757f3fSDimitry Andric case CommentKind::CLASS: \ 900b57cec5SDimitry Andric return static_cast<const CLASS *>(this)->child_begin(); 910b57cec5SDimitry Andric #include "clang/AST/CommentNodes.inc" 920b57cec5SDimitry Andric #undef COMMENT 930b57cec5SDimitry Andric #undef ABSTRACT_COMMENT 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric llvm_unreachable("Unknown comment kind!"); 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric Comment::child_iterator Comment::child_end() const { 990b57cec5SDimitry Andric switch (getCommentKind()) { 100*5f757f3fSDimitry Andric case CommentKind::None: 101*5f757f3fSDimitry Andric llvm_unreachable("comment without a kind"); 1020b57cec5SDimitry Andric #define ABSTRACT_COMMENT(COMMENT) 1030b57cec5SDimitry Andric #define COMMENT(CLASS, PARENT) \ 104*5f757f3fSDimitry Andric case CommentKind::CLASS: \ 1050b57cec5SDimitry Andric return static_cast<const CLASS *>(this)->child_end(); 1060b57cec5SDimitry Andric #include "clang/AST/CommentNodes.inc" 1070b57cec5SDimitry Andric #undef COMMENT 1080b57cec5SDimitry Andric #undef ABSTRACT_COMMENT 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric llvm_unreachable("Unknown comment kind!"); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric bool TextComment::isWhitespaceNoCache() const { 1140eae32dcSDimitry Andric return llvm::all_of(Text, clang::isWhitespace); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric bool ParagraphComment::isWhitespaceNoCache() const { 1180b57cec5SDimitry Andric for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { 1190b57cec5SDimitry Andric if (const TextComment *TC = dyn_cast<TextComment>(*I)) { 1200b57cec5SDimitry Andric if (!TC->isWhitespace()) 1210b57cec5SDimitry Andric return false; 1220b57cec5SDimitry Andric } else 1230b57cec5SDimitry Andric return false; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric return true; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { 1290b57cec5SDimitry Andric TypeLoc TL = SrcTL.IgnoreParens(); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // Look through attribute types. 1320b57cec5SDimitry Andric if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>()) 1330b57cec5SDimitry Andric return AttributeTL.getModifiedLoc(); 1340b57cec5SDimitry Andric // Look through qualified types. 1350b57cec5SDimitry Andric if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) 1360b57cec5SDimitry Andric return QualifiedTL.getUnqualifiedLoc(); 1370b57cec5SDimitry Andric // Look through pointer types. 1380b57cec5SDimitry Andric if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) 1390b57cec5SDimitry Andric return PointerTL.getPointeeLoc().getUnqualifiedLoc(); 1400b57cec5SDimitry Andric // Look through reference types. 1410b57cec5SDimitry Andric if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) 1420b57cec5SDimitry Andric return ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); 1430b57cec5SDimitry Andric // Look through adjusted types. 1440b57cec5SDimitry Andric if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) 1450b57cec5SDimitry Andric return ATL.getOriginalLoc(); 1460b57cec5SDimitry Andric if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>()) 1470b57cec5SDimitry Andric return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 1480b57cec5SDimitry Andric if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) 1490b57cec5SDimitry Andric return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 1500b57cec5SDimitry Andric if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) 1510b57cec5SDimitry Andric return ETL.getNamedTypeLoc(); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric return TL; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) { 1570b57cec5SDimitry Andric TypeLoc PrevTL; 1580b57cec5SDimitry Andric while (PrevTL != TL) { 1590b57cec5SDimitry Andric PrevTL = TL; 1600b57cec5SDimitry Andric TL = lookThroughTypedefOrTypeAliasLocs(TL); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 1640b57cec5SDimitry Andric ResFTL = FTL; 1650b57cec5SDimitry Andric return true; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric if (TemplateSpecializationTypeLoc STL = 1690b57cec5SDimitry Andric TL.getAs<TemplateSpecializationTypeLoc>()) { 1700b57cec5SDimitry Andric // If we have a typedef to a template specialization with exactly one 1710b57cec5SDimitry Andric // template argument of a function type, this looks like std::function, 1720b57cec5SDimitry Andric // boost::function, or other function wrapper. Treat these typedefs as 1730b57cec5SDimitry Andric // functions. 1740b57cec5SDimitry Andric if (STL.getNumArgs() != 1) 1750b57cec5SDimitry Andric return false; 1760b57cec5SDimitry Andric TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); 1770b57cec5SDimitry Andric if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) 1780b57cec5SDimitry Andric return false; 1790b57cec5SDimitry Andric TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); 1800b57cec5SDimitry Andric TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); 1810b57cec5SDimitry Andric if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 1820b57cec5SDimitry Andric ResFTL = FTL; 1830b57cec5SDimitry Andric return true; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric return false; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 190*5f757f3fSDimitry Andric const char * 191*5f757f3fSDimitry Andric ParamCommandComment::getDirectionAsString(ParamCommandPassDirection D) { 1920b57cec5SDimitry Andric switch (D) { 193*5f757f3fSDimitry Andric case ParamCommandPassDirection::In: 1940b57cec5SDimitry Andric return "[in]"; 195*5f757f3fSDimitry Andric case ParamCommandPassDirection::Out: 1960b57cec5SDimitry Andric return "[out]"; 197*5f757f3fSDimitry Andric case ParamCommandPassDirection::InOut: 1980b57cec5SDimitry Andric return "[in,out]"; 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric llvm_unreachable("unknown PassDirection"); 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric void DeclInfo::fill() { 2040b57cec5SDimitry Andric assert(!IsFilled); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric // Set defaults. 2070b57cec5SDimitry Andric Kind = OtherKind; 2080b57cec5SDimitry Andric TemplateKind = NotTemplate; 2090b57cec5SDimitry Andric IsObjCMethod = false; 2100b57cec5SDimitry Andric IsInstanceMethod = false; 2110b57cec5SDimitry Andric IsClassMethod = false; 212349cc55cSDimitry Andric IsVariadic = false; 213bdd1243dSDimitry Andric ParamVars = std::nullopt; 2140b57cec5SDimitry Andric TemplateParameters = nullptr; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric if (!CommentDecl) { 2170b57cec5SDimitry Andric // If there is no declaration, the defaults is our only guess. 2180b57cec5SDimitry Andric IsFilled = true; 2190b57cec5SDimitry Andric return; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric CurrentDecl = CommentDecl; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric Decl::Kind K = CommentDecl->getKind(); 224349cc55cSDimitry Andric const TypeSourceInfo *TSI = nullptr; 2250b57cec5SDimitry Andric switch (K) { 2260b57cec5SDimitry Andric default: 2270b57cec5SDimitry Andric // Defaults are should be good for declarations we don't handle explicitly. 2280b57cec5SDimitry Andric break; 2290b57cec5SDimitry Andric case Decl::Function: 2300b57cec5SDimitry Andric case Decl::CXXMethod: 2310b57cec5SDimitry Andric case Decl::CXXConstructor: 2320b57cec5SDimitry Andric case Decl::CXXDestructor: 2330b57cec5SDimitry Andric case Decl::CXXConversion: { 2340b57cec5SDimitry Andric const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); 2350b57cec5SDimitry Andric Kind = FunctionKind; 2360b57cec5SDimitry Andric ParamVars = FD->parameters(); 2370b57cec5SDimitry Andric ReturnType = FD->getReturnType(); 2380b57cec5SDimitry Andric unsigned NumLists = FD->getNumTemplateParameterLists(); 2390b57cec5SDimitry Andric if (NumLists != 0) { 2400b57cec5SDimitry Andric TemplateKind = TemplateSpecialization; 2410b57cec5SDimitry Andric TemplateParameters = 2420b57cec5SDimitry Andric FD->getTemplateParameterList(NumLists - 1); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 2460b57cec5SDimitry Andric K == Decl::CXXDestructor || K == Decl::CXXConversion) { 2470b57cec5SDimitry Andric const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 2480b57cec5SDimitry Andric IsInstanceMethod = MD->isInstance(); 2490b57cec5SDimitry Andric IsClassMethod = !IsInstanceMethod; 2500b57cec5SDimitry Andric } 251349cc55cSDimitry Andric IsVariadic = FD->isVariadic(); 252349cc55cSDimitry Andric assert(involvesFunctionType()); 2530b57cec5SDimitry Andric break; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric case Decl::ObjCMethod: { 2560b57cec5SDimitry Andric const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 2570b57cec5SDimitry Andric Kind = FunctionKind; 2580b57cec5SDimitry Andric ParamVars = MD->parameters(); 2590b57cec5SDimitry Andric ReturnType = MD->getReturnType(); 2600b57cec5SDimitry Andric IsObjCMethod = true; 2610b57cec5SDimitry Andric IsInstanceMethod = MD->isInstanceMethod(); 2620b57cec5SDimitry Andric IsClassMethod = !IsInstanceMethod; 263349cc55cSDimitry Andric IsVariadic = MD->isVariadic(); 264349cc55cSDimitry Andric assert(involvesFunctionType()); 2650b57cec5SDimitry Andric break; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric case Decl::FunctionTemplate: { 2680b57cec5SDimitry Andric const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); 2690b57cec5SDimitry Andric Kind = FunctionKind; 2700b57cec5SDimitry Andric TemplateKind = Template; 2710b57cec5SDimitry Andric const FunctionDecl *FD = FTD->getTemplatedDecl(); 2720b57cec5SDimitry Andric ParamVars = FD->parameters(); 2730b57cec5SDimitry Andric ReturnType = FD->getReturnType(); 2740b57cec5SDimitry Andric TemplateParameters = FTD->getTemplateParameters(); 275349cc55cSDimitry Andric IsVariadic = FD->isVariadic(); 276349cc55cSDimitry Andric assert(involvesFunctionType()); 2770b57cec5SDimitry Andric break; 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric case Decl::ClassTemplate: { 2800b57cec5SDimitry Andric const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 2810b57cec5SDimitry Andric Kind = ClassKind; 2820b57cec5SDimitry Andric TemplateKind = Template; 2830b57cec5SDimitry Andric TemplateParameters = CTD->getTemplateParameters(); 2840b57cec5SDimitry Andric break; 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric case Decl::ClassTemplatePartialSpecialization: { 2870b57cec5SDimitry Andric const ClassTemplatePartialSpecializationDecl *CTPSD = 2880b57cec5SDimitry Andric cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 2890b57cec5SDimitry Andric Kind = ClassKind; 2900b57cec5SDimitry Andric TemplateKind = TemplatePartialSpecialization; 2910b57cec5SDimitry Andric TemplateParameters = CTPSD->getTemplateParameters(); 2920b57cec5SDimitry Andric break; 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric case Decl::ClassTemplateSpecialization: 2950b57cec5SDimitry Andric Kind = ClassKind; 2960b57cec5SDimitry Andric TemplateKind = TemplateSpecialization; 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric case Decl::Record: 2990b57cec5SDimitry Andric case Decl::CXXRecord: 3000b57cec5SDimitry Andric Kind = ClassKind; 3010b57cec5SDimitry Andric break; 3020b57cec5SDimitry Andric case Decl::Var: 303349cc55cSDimitry Andric if (const VarTemplateDecl *VTD = 304349cc55cSDimitry Andric cast<VarDecl>(CommentDecl)->getDescribedVarTemplate()) { 305349cc55cSDimitry Andric TemplateKind = TemplateSpecialization; 306349cc55cSDimitry Andric TemplateParameters = VTD->getTemplateParameters(); 307349cc55cSDimitry Andric } 308bdd1243dSDimitry Andric [[fallthrough]]; 3090b57cec5SDimitry Andric case Decl::Field: 3100b57cec5SDimitry Andric case Decl::EnumConstant: 3110b57cec5SDimitry Andric case Decl::ObjCIvar: 3120b57cec5SDimitry Andric case Decl::ObjCAtDefsField: 313349cc55cSDimitry Andric case Decl::ObjCProperty: 3140b57cec5SDimitry Andric if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl)) 3150b57cec5SDimitry Andric TSI = VD->getTypeSourceInfo(); 3160b57cec5SDimitry Andric else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl)) 3170b57cec5SDimitry Andric TSI = PD->getTypeSourceInfo(); 3180b57cec5SDimitry Andric Kind = VariableKind; 3190b57cec5SDimitry Andric break; 320349cc55cSDimitry Andric case Decl::VarTemplate: { 321349cc55cSDimitry Andric const VarTemplateDecl *VTD = cast<VarTemplateDecl>(CommentDecl); 322349cc55cSDimitry Andric Kind = VariableKind; 323349cc55cSDimitry Andric TemplateKind = Template; 324349cc55cSDimitry Andric TemplateParameters = VTD->getTemplateParameters(); 325349cc55cSDimitry Andric if (const VarDecl *VD = VTD->getTemplatedDecl()) 326349cc55cSDimitry Andric TSI = VD->getTypeSourceInfo(); 327349cc55cSDimitry Andric break; 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric case Decl::Namespace: 3300b57cec5SDimitry Andric Kind = NamespaceKind; 3310b57cec5SDimitry Andric break; 3320b57cec5SDimitry Andric case Decl::TypeAlias: 333349cc55cSDimitry Andric case Decl::Typedef: 3340b57cec5SDimitry Andric Kind = TypedefKind; 335349cc55cSDimitry Andric TSI = cast<TypedefNameDecl>(CommentDecl)->getTypeSourceInfo(); 3360b57cec5SDimitry Andric break; 3370b57cec5SDimitry Andric case Decl::TypeAliasTemplate: { 3380b57cec5SDimitry Andric const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 3390b57cec5SDimitry Andric Kind = TypedefKind; 3400b57cec5SDimitry Andric TemplateKind = Template; 3410b57cec5SDimitry Andric TemplateParameters = TAT->getTemplateParameters(); 342349cc55cSDimitry Andric if (TypeAliasDecl *TAD = TAT->getTemplatedDecl()) 343349cc55cSDimitry Andric TSI = TAD->getTypeSourceInfo(); 3440b57cec5SDimitry Andric break; 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric case Decl::Enum: 3470b57cec5SDimitry Andric Kind = EnumKind; 3480b57cec5SDimitry Andric break; 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 351349cc55cSDimitry Andric // If the type is a typedef / using to something we consider a function, 352349cc55cSDimitry Andric // extract arguments and return type. 353349cc55cSDimitry Andric if (TSI) { 354349cc55cSDimitry Andric TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 355349cc55cSDimitry Andric FunctionTypeLoc FTL; 356349cc55cSDimitry Andric if (getFunctionTypeLoc(TL, FTL)) { 357349cc55cSDimitry Andric ParamVars = FTL.getParams(); 358349cc55cSDimitry Andric ReturnType = FTL.getReturnLoc().getType(); 359349cc55cSDimitry Andric if (const auto *FPT = dyn_cast<FunctionProtoType>(FTL.getTypePtr())) 360349cc55cSDimitry Andric IsVariadic = FPT->isVariadic(); 361349cc55cSDimitry Andric assert(involvesFunctionType()); 362349cc55cSDimitry Andric } 363349cc55cSDimitry Andric } 364349cc55cSDimitry Andric 3650b57cec5SDimitry Andric IsFilled = true; 3660b57cec5SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric StringRef ParamCommandComment::getParamName(const FullComment *FC) const { 3690b57cec5SDimitry Andric assert(isParamIndexValid()); 3700b57cec5SDimitry Andric if (isVarArgParam()) 3710b57cec5SDimitry Andric return "..."; 3720b57cec5SDimitry Andric return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric StringRef TParamCommandComment::getParamName(const FullComment *FC) const { 3760b57cec5SDimitry Andric assert(isPositionValid()); 3770b57cec5SDimitry Andric const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 3780b57cec5SDimitry Andric for (unsigned i = 0, e = getDepth(); i != e; ++i) { 379480093f4SDimitry Andric assert(TPL && "Unknown TemplateParameterList"); 3800b57cec5SDimitry Andric if (i == e - 1) 3810b57cec5SDimitry Andric return TPL->getParam(getIndex(i))->getName(); 3820b57cec5SDimitry Andric const NamedDecl *Param = TPL->getParam(getIndex(i)); 383480093f4SDimitry Andric if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) 3840b57cec5SDimitry Andric TPL = TTP->getTemplateParameters(); 3850b57cec5SDimitry Andric } 3860b57cec5SDimitry Andric return ""; 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric } // end namespace comments 3900b57cec5SDimitry Andric } // end namespace clang 3910b57cec5SDimitry Andric 392