1239313Sdim//===--- Comment.cpp - Comment AST node implementation --------------------===// 2239313Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6239313Sdim// 7239313Sdim//===----------------------------------------------------------------------===// 8239313Sdim 9314564Sdim#include "clang/AST/Comment.h" 10243830Sdim#include "clang/AST/ASTContext.h" 11239313Sdim#include "clang/AST/Decl.h" 12239313Sdim#include "clang/AST/DeclObjC.h" 13239313Sdim#include "clang/AST/DeclTemplate.h" 14261991Sdim#include "clang/Basic/CharInfo.h" 15239313Sdim#include "llvm/Support/ErrorHandling.h" 16360784Sdim#include <type_traits> 17239313Sdim 18239313Sdimnamespace clang { 19239313Sdimnamespace comments { 20239313Sdim 21360784Sdim// Check that no comment class has a non-trival destructor. They are allocated 22360784Sdim// with a BumpPtrAllocator and therefore their destructor is not executed. 23360784Sdim#define ABSTRACT_COMMENT(COMMENT) 24360784Sdim#define COMMENT(CLASS, PARENT) \ 25360784Sdim static_assert(std::is_trivially_destructible<CLASS>::value, \ 26360784Sdim #CLASS " should be trivially destructible!"); 27360784Sdim#include "clang/AST/CommentNodes.inc" 28360784Sdim#undef COMMENT 29360784Sdim#undef ABSTRACT_COMMENT 30360784Sdim 31360784Sdim// DeclInfo is also allocated with a BumpPtrAllocator. 32360784Sdimstatic_assert(std::is_trivially_destructible<DeclInfo>::value, 33360784Sdim "DeclInfo should be trivially destructible!"); 34360784Sdim 35239313Sdimconst char *Comment::getCommentKindName() const { 36239313Sdim switch (getCommentKind()) { 37239313Sdim case NoCommentKind: return "NoCommentKind"; 38239313Sdim#define ABSTRACT_COMMENT(COMMENT) 39239313Sdim#define COMMENT(CLASS, PARENT) \ 40239313Sdim case CLASS##Kind: \ 41239313Sdim return #CLASS; 42239313Sdim#include "clang/AST/CommentNodes.inc" 43239313Sdim#undef COMMENT 44239313Sdim#undef ABSTRACT_COMMENT 45239313Sdim } 46239313Sdim llvm_unreachable("Unknown comment kind!"); 47239313Sdim} 48239313Sdim 49239313Sdimnamespace { 50239313Sdimstruct good {}; 51239313Sdimstruct bad {}; 52239313Sdim 53239313Sdimtemplate <typename T> 54239313Sdimgood implements_child_begin_end(Comment::child_iterator (T::*)() const) { 55239313Sdim return good(); 56239313Sdim} 57239313Sdim 58261991SdimLLVM_ATTRIBUTE_UNUSED 59239313Sdimstatic inline bad implements_child_begin_end( 60239313Sdim Comment::child_iterator (Comment::*)() const) { 61239313Sdim return bad(); 62239313Sdim} 63239313Sdim 64239313Sdim#define ASSERT_IMPLEMENTS_child_begin(function) \ 65261991Sdim (void) good(implements_child_begin_end(function)) 66239313Sdim 67261991SdimLLVM_ATTRIBUTE_UNUSED 68239313Sdimstatic inline void CheckCommentASTNodes() { 69239313Sdim#define ABSTRACT_COMMENT(COMMENT) 70239313Sdim#define COMMENT(CLASS, PARENT) \ 71239313Sdim ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ 72239313Sdim ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); 73239313Sdim#include "clang/AST/CommentNodes.inc" 74239313Sdim#undef COMMENT 75239313Sdim#undef ABSTRACT_COMMENT 76239313Sdim} 77239313Sdim 78239313Sdim#undef ASSERT_IMPLEMENTS_child_begin 79239313Sdim 80239313Sdim} // end unnamed namespace 81239313Sdim 82239313SdimComment::child_iterator Comment::child_begin() const { 83239313Sdim switch (getCommentKind()) { 84239313Sdim case NoCommentKind: llvm_unreachable("comment without a kind"); 85239313Sdim#define ABSTRACT_COMMENT(COMMENT) 86239313Sdim#define COMMENT(CLASS, PARENT) \ 87239313Sdim case CLASS##Kind: \ 88239313Sdim return static_cast<const CLASS *>(this)->child_begin(); 89239313Sdim#include "clang/AST/CommentNodes.inc" 90239313Sdim#undef COMMENT 91239313Sdim#undef ABSTRACT_COMMENT 92239313Sdim } 93239313Sdim llvm_unreachable("Unknown comment kind!"); 94239313Sdim} 95239313Sdim 96239313SdimComment::child_iterator Comment::child_end() const { 97239313Sdim switch (getCommentKind()) { 98239313Sdim case NoCommentKind: llvm_unreachable("comment without a kind"); 99239313Sdim#define ABSTRACT_COMMENT(COMMENT) 100239313Sdim#define COMMENT(CLASS, PARENT) \ 101239313Sdim case CLASS##Kind: \ 102239313Sdim return static_cast<const CLASS *>(this)->child_end(); 103239313Sdim#include "clang/AST/CommentNodes.inc" 104239313Sdim#undef COMMENT 105239313Sdim#undef ABSTRACT_COMMENT 106239313Sdim } 107239313Sdim llvm_unreachable("Unknown comment kind!"); 108239313Sdim} 109239313Sdim 110239313Sdimbool TextComment::isWhitespaceNoCache() const { 111239313Sdim for (StringRef::const_iterator I = Text.begin(), E = Text.end(); 112239313Sdim I != E; ++I) { 113261991Sdim if (!clang::isWhitespace(*I)) 114239313Sdim return false; 115239313Sdim } 116239313Sdim return true; 117239313Sdim} 118239313Sdim 119239313Sdimbool ParagraphComment::isWhitespaceNoCache() const { 120239313Sdim for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { 121239313Sdim if (const TextComment *TC = dyn_cast<TextComment>(*I)) { 122239313Sdim if (!TC->isWhitespace()) 123239313Sdim return false; 124239313Sdim } else 125239313Sdim return false; 126239313Sdim } 127239313Sdim return true; 128239313Sdim} 129239313Sdim 130314564Sdimstatic TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { 131314564Sdim TypeLoc TL = SrcTL.IgnoreParens(); 132314564Sdim 133321369Sdim // Look through attribute types. 134321369Sdim if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>()) 135321369Sdim return AttributeTL.getModifiedLoc(); 136314564Sdim // Look through qualified types. 137314564Sdim if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) 138314564Sdim return QualifiedTL.getUnqualifiedLoc(); 139314564Sdim // Look through pointer types. 140314564Sdim if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) 141314564Sdim return PointerTL.getPointeeLoc().getUnqualifiedLoc(); 142314564Sdim // Look through reference types. 143314564Sdim if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) 144314564Sdim return ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); 145314564Sdim // Look through adjusted types. 146314564Sdim if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) 147314564Sdim return ATL.getOriginalLoc(); 148314564Sdim if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>()) 149314564Sdim return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 150314564Sdim if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) 151314564Sdim return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 152314564Sdim if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) 153314564Sdim return ETL.getNamedTypeLoc(); 154314564Sdim 155314564Sdim return TL; 156314564Sdim} 157314564Sdim 158314564Sdimstatic bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) { 159314564Sdim TypeLoc PrevTL; 160314564Sdim while (PrevTL != TL) { 161314564Sdim PrevTL = TL; 162314564Sdim TL = lookThroughTypedefOrTypeAliasLocs(TL); 163314564Sdim } 164314564Sdim 165314564Sdim if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 166314564Sdim ResFTL = FTL; 167314564Sdim return true; 168314564Sdim } 169314564Sdim 170314564Sdim if (TemplateSpecializationTypeLoc STL = 171314564Sdim TL.getAs<TemplateSpecializationTypeLoc>()) { 172314564Sdim // If we have a typedef to a template specialization with exactly one 173314564Sdim // template argument of a function type, this looks like std::function, 174314564Sdim // boost::function, or other function wrapper. Treat these typedefs as 175314564Sdim // functions. 176314564Sdim if (STL.getNumArgs() != 1) 177314564Sdim return false; 178314564Sdim TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); 179314564Sdim if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) 180314564Sdim return false; 181314564Sdim TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); 182314564Sdim TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); 183314564Sdim if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 184314564Sdim ResFTL = FTL; 185314564Sdim return true; 186314564Sdim } 187314564Sdim } 188314564Sdim 189314564Sdim return false; 190314564Sdim} 191314564Sdim 192239313Sdimconst char *ParamCommandComment::getDirectionAsString(PassDirection D) { 193239313Sdim switch (D) { 194239313Sdim case ParamCommandComment::In: 195239313Sdim return "[in]"; 196239313Sdim case ParamCommandComment::Out: 197239313Sdim return "[out]"; 198239313Sdim case ParamCommandComment::InOut: 199239313Sdim return "[in,out]"; 200239313Sdim } 201239313Sdim llvm_unreachable("unknown PassDirection"); 202239313Sdim} 203239313Sdim 204239313Sdimvoid DeclInfo::fill() { 205239313Sdim assert(!IsFilled); 206239313Sdim 207239313Sdim // Set defaults. 208239313Sdim Kind = OtherKind; 209239313Sdim TemplateKind = NotTemplate; 210239313Sdim IsObjCMethod = false; 211239313Sdim IsInstanceMethod = false; 212239313Sdim IsClassMethod = false; 213251662Sdim ParamVars = None; 214276479Sdim TemplateParameters = nullptr; 215239313Sdim 216243830Sdim if (!CommentDecl) { 217239313Sdim // If there is no declaration, the defaults is our only guess. 218239313Sdim IsFilled = true; 219239313Sdim return; 220239313Sdim } 221243830Sdim CurrentDecl = CommentDecl; 222341825Sdim 223243830Sdim Decl::Kind K = CommentDecl->getKind(); 224239313Sdim switch (K) { 225239313Sdim default: 226239313Sdim // Defaults are should be good for declarations we don't handle explicitly. 227239313Sdim break; 228239313Sdim case Decl::Function: 229239313Sdim case Decl::CXXMethod: 230239313Sdim case Decl::CXXConstructor: 231239313Sdim case Decl::CXXDestructor: 232239313Sdim case Decl::CXXConversion: { 233243830Sdim const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); 234239313Sdim Kind = FunctionKind; 235309124Sdim ParamVars = FD->parameters(); 236276479Sdim ReturnType = FD->getReturnType(); 237239313Sdim unsigned NumLists = FD->getNumTemplateParameterLists(); 238239313Sdim if (NumLists != 0) { 239239313Sdim TemplateKind = TemplateSpecialization; 240239313Sdim TemplateParameters = 241239313Sdim FD->getTemplateParameterList(NumLists - 1); 242239313Sdim } 243239313Sdim 244239313Sdim if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 245239313Sdim K == Decl::CXXDestructor || K == Decl::CXXConversion) { 246243830Sdim const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 247239313Sdim IsInstanceMethod = MD->isInstance(); 248239313Sdim IsClassMethod = !IsInstanceMethod; 249239313Sdim } 250239313Sdim break; 251239313Sdim } 252239313Sdim case Decl::ObjCMethod: { 253243830Sdim const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 254239313Sdim Kind = FunctionKind; 255309124Sdim ParamVars = MD->parameters(); 256276479Sdim ReturnType = MD->getReturnType(); 257239313Sdim IsObjCMethod = true; 258239313Sdim IsInstanceMethod = MD->isInstanceMethod(); 259239313Sdim IsClassMethod = !IsInstanceMethod; 260239313Sdim break; 261239313Sdim } 262239313Sdim case Decl::FunctionTemplate: { 263243830Sdim const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); 264239313Sdim Kind = FunctionKind; 265239313Sdim TemplateKind = Template; 266239313Sdim const FunctionDecl *FD = FTD->getTemplatedDecl(); 267309124Sdim ParamVars = FD->parameters(); 268276479Sdim ReturnType = FD->getReturnType(); 269239313Sdim TemplateParameters = FTD->getTemplateParameters(); 270239313Sdim break; 271239313Sdim } 272239313Sdim case Decl::ClassTemplate: { 273243830Sdim const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 274239313Sdim Kind = ClassKind; 275239313Sdim TemplateKind = Template; 276239313Sdim TemplateParameters = CTD->getTemplateParameters(); 277239313Sdim break; 278239313Sdim } 279239313Sdim case Decl::ClassTemplatePartialSpecialization: { 280239313Sdim const ClassTemplatePartialSpecializationDecl *CTPSD = 281243830Sdim cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 282239313Sdim Kind = ClassKind; 283239313Sdim TemplateKind = TemplatePartialSpecialization; 284239313Sdim TemplateParameters = CTPSD->getTemplateParameters(); 285239313Sdim break; 286239313Sdim } 287239313Sdim case Decl::ClassTemplateSpecialization: 288239313Sdim Kind = ClassKind; 289239313Sdim TemplateKind = TemplateSpecialization; 290239313Sdim break; 291239313Sdim case Decl::Record: 292239313Sdim case Decl::CXXRecord: 293239313Sdim Kind = ClassKind; 294239313Sdim break; 295239313Sdim case Decl::Var: 296239313Sdim case Decl::Field: 297239313Sdim case Decl::EnumConstant: 298239313Sdim case Decl::ObjCIvar: 299239313Sdim case Decl::ObjCAtDefsField: 300321369Sdim case Decl::ObjCProperty: { 301321369Sdim const TypeSourceInfo *TSI; 302321369Sdim if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl)) 303321369Sdim TSI = VD->getTypeSourceInfo(); 304321369Sdim else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl)) 305321369Sdim TSI = PD->getTypeSourceInfo(); 306321369Sdim else 307321369Sdim TSI = nullptr; 308321369Sdim if (TSI) { 309321369Sdim TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 310321369Sdim FunctionTypeLoc FTL; 311321369Sdim if (getFunctionTypeLoc(TL, FTL)) { 312321369Sdim ParamVars = FTL.getParams(); 313321369Sdim ReturnType = FTL.getReturnLoc().getType(); 314321369Sdim } 315321369Sdim } 316239313Sdim Kind = VariableKind; 317239313Sdim break; 318321369Sdim } 319239313Sdim case Decl::Namespace: 320239313Sdim Kind = NamespaceKind; 321239313Sdim break; 322314564Sdim case Decl::TypeAlias: 323243830Sdim case Decl::Typedef: { 324243830Sdim Kind = TypedefKind; 325314564Sdim // If this is a typedef / using to something we consider a function, extract 326243830Sdim // arguments and return type. 327314564Sdim const TypeSourceInfo *TSI = 328314564Sdim K == Decl::Typedef 329314564Sdim ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo() 330314564Sdim : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo(); 331243830Sdim if (!TSI) 332243830Sdim break; 333243830Sdim TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 334314564Sdim FunctionTypeLoc FTL; 335314564Sdim if (getFunctionTypeLoc(TL, FTL)) { 336314564Sdim Kind = FunctionKind; 337314564Sdim ParamVars = FTL.getParams(); 338314564Sdim ReturnType = FTL.getReturnLoc().getType(); 339243830Sdim } 340243830Sdim break; 341243830Sdim } 342239313Sdim case Decl::TypeAliasTemplate: { 343243830Sdim const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 344239313Sdim Kind = TypedefKind; 345239313Sdim TemplateKind = Template; 346239313Sdim TemplateParameters = TAT->getTemplateParameters(); 347314564Sdim TypeAliasDecl *TAD = TAT->getTemplatedDecl(); 348314564Sdim if (!TAD) 349314564Sdim break; 350314564Sdim 351314564Sdim const TypeSourceInfo *TSI = TAD->getTypeSourceInfo(); 352314564Sdim if (!TSI) 353314564Sdim break; 354314564Sdim TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 355314564Sdim FunctionTypeLoc FTL; 356314564Sdim if (getFunctionTypeLoc(TL, FTL)) { 357314564Sdim Kind = FunctionKind; 358314564Sdim ParamVars = FTL.getParams(); 359314564Sdim ReturnType = FTL.getReturnLoc().getType(); 360314564Sdim } 361239313Sdim break; 362239313Sdim } 363239313Sdim case Decl::Enum: 364239313Sdim Kind = EnumKind; 365239313Sdim break; 366239313Sdim } 367239313Sdim 368239313Sdim IsFilled = true; 369239313Sdim} 370239313Sdim 371243830SdimStringRef ParamCommandComment::getParamName(const FullComment *FC) const { 372243830Sdim assert(isParamIndexValid()); 373261991Sdim if (isVarArgParam()) 374261991Sdim return "..."; 375261991Sdim return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 376243830Sdim} 377243830Sdim 378243830SdimStringRef TParamCommandComment::getParamName(const FullComment *FC) const { 379243830Sdim assert(isPositionValid()); 380261991Sdim const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 381243830Sdim for (unsigned i = 0, e = getDepth(); i != e; ++i) { 382360784Sdim assert(TPL && "Unknown TemplateParameterList"); 383360784Sdim if (i == e - 1) 384243830Sdim return TPL->getParam(getIndex(i))->getName(); 385243830Sdim const NamedDecl *Param = TPL->getParam(getIndex(i)); 386360784Sdim if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) 387243830Sdim TPL = TTP->getTemplateParameters(); 388243830Sdim } 389243830Sdim return ""; 390243830Sdim} 391243830Sdim 392239313Sdim} // end namespace comments 393239313Sdim} // end namespace clang 394239313Sdim 395