xref: /freebsd/contrib/llvm-project/clang/lib/AST/Comment.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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