Comment.cpp revision 353358
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" 16239313Sdim 17239313Sdimnamespace clang { 18239313Sdimnamespace comments { 19239313Sdim 20239313Sdimconst char *Comment::getCommentKindName() const { 21239313Sdim switch (getCommentKind()) { 22239313Sdim case NoCommentKind: return "NoCommentKind"; 23239313Sdim#define ABSTRACT_COMMENT(COMMENT) 24239313Sdim#define COMMENT(CLASS, PARENT) \ 25239313Sdim case CLASS##Kind: \ 26239313Sdim return #CLASS; 27239313Sdim#include "clang/AST/CommentNodes.inc" 28239313Sdim#undef COMMENT 29239313Sdim#undef ABSTRACT_COMMENT 30239313Sdim } 31239313Sdim llvm_unreachable("Unknown comment kind!"); 32239313Sdim} 33239313Sdim 34239313Sdimnamespace { 35239313Sdimstruct good {}; 36239313Sdimstruct bad {}; 37239313Sdim 38239313Sdimtemplate <typename T> 39239313Sdimgood implements_child_begin_end(Comment::child_iterator (T::*)() const) { 40239313Sdim return good(); 41239313Sdim} 42239313Sdim 43261991SdimLLVM_ATTRIBUTE_UNUSED 44239313Sdimstatic inline bad implements_child_begin_end( 45239313Sdim Comment::child_iterator (Comment::*)() const) { 46239313Sdim return bad(); 47239313Sdim} 48239313Sdim 49239313Sdim#define ASSERT_IMPLEMENTS_child_begin(function) \ 50261991Sdim (void) good(implements_child_begin_end(function)) 51239313Sdim 52261991SdimLLVM_ATTRIBUTE_UNUSED 53239313Sdimstatic inline void CheckCommentASTNodes() { 54239313Sdim#define ABSTRACT_COMMENT(COMMENT) 55239313Sdim#define COMMENT(CLASS, PARENT) \ 56239313Sdim ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ 57239313Sdim ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); 58239313Sdim#include "clang/AST/CommentNodes.inc" 59239313Sdim#undef COMMENT 60239313Sdim#undef ABSTRACT_COMMENT 61239313Sdim} 62239313Sdim 63239313Sdim#undef ASSERT_IMPLEMENTS_child_begin 64239313Sdim 65239313Sdim} // end unnamed namespace 66239313Sdim 67239313SdimComment::child_iterator Comment::child_begin() const { 68239313Sdim switch (getCommentKind()) { 69239313Sdim case NoCommentKind: llvm_unreachable("comment without a kind"); 70239313Sdim#define ABSTRACT_COMMENT(COMMENT) 71239313Sdim#define COMMENT(CLASS, PARENT) \ 72239313Sdim case CLASS##Kind: \ 73239313Sdim return static_cast<const CLASS *>(this)->child_begin(); 74239313Sdim#include "clang/AST/CommentNodes.inc" 75239313Sdim#undef COMMENT 76239313Sdim#undef ABSTRACT_COMMENT 77239313Sdim } 78239313Sdim llvm_unreachable("Unknown comment kind!"); 79239313Sdim} 80239313Sdim 81239313SdimComment::child_iterator Comment::child_end() const { 82239313Sdim switch (getCommentKind()) { 83239313Sdim case NoCommentKind: llvm_unreachable("comment without a kind"); 84239313Sdim#define ABSTRACT_COMMENT(COMMENT) 85239313Sdim#define COMMENT(CLASS, PARENT) \ 86239313Sdim case CLASS##Kind: \ 87239313Sdim return static_cast<const CLASS *>(this)->child_end(); 88239313Sdim#include "clang/AST/CommentNodes.inc" 89239313Sdim#undef COMMENT 90239313Sdim#undef ABSTRACT_COMMENT 91239313Sdim } 92239313Sdim llvm_unreachable("Unknown comment kind!"); 93239313Sdim} 94239313Sdim 95239313Sdimbool TextComment::isWhitespaceNoCache() const { 96239313Sdim for (StringRef::const_iterator I = Text.begin(), E = Text.end(); 97239313Sdim I != E; ++I) { 98261991Sdim if (!clang::isWhitespace(*I)) 99239313Sdim return false; 100239313Sdim } 101239313Sdim return true; 102239313Sdim} 103239313Sdim 104239313Sdimbool ParagraphComment::isWhitespaceNoCache() const { 105239313Sdim for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { 106239313Sdim if (const TextComment *TC = dyn_cast<TextComment>(*I)) { 107239313Sdim if (!TC->isWhitespace()) 108239313Sdim return false; 109239313Sdim } else 110239313Sdim return false; 111239313Sdim } 112239313Sdim return true; 113239313Sdim} 114239313Sdim 115314564Sdimstatic TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { 116314564Sdim TypeLoc TL = SrcTL.IgnoreParens(); 117314564Sdim 118321369Sdim // Look through attribute types. 119321369Sdim if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>()) 120321369Sdim return AttributeTL.getModifiedLoc(); 121314564Sdim // Look through qualified types. 122314564Sdim if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) 123314564Sdim return QualifiedTL.getUnqualifiedLoc(); 124314564Sdim // Look through pointer types. 125314564Sdim if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) 126314564Sdim return PointerTL.getPointeeLoc().getUnqualifiedLoc(); 127314564Sdim // Look through reference types. 128314564Sdim if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) 129314564Sdim return ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); 130314564Sdim // Look through adjusted types. 131314564Sdim if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) 132314564Sdim return ATL.getOriginalLoc(); 133314564Sdim if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>()) 134314564Sdim return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 135314564Sdim if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) 136314564Sdim return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 137314564Sdim if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) 138314564Sdim return ETL.getNamedTypeLoc(); 139314564Sdim 140314564Sdim return TL; 141314564Sdim} 142314564Sdim 143314564Sdimstatic bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) { 144314564Sdim TypeLoc PrevTL; 145314564Sdim while (PrevTL != TL) { 146314564Sdim PrevTL = TL; 147314564Sdim TL = lookThroughTypedefOrTypeAliasLocs(TL); 148314564Sdim } 149314564Sdim 150314564Sdim if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 151314564Sdim ResFTL = FTL; 152314564Sdim return true; 153314564Sdim } 154314564Sdim 155314564Sdim if (TemplateSpecializationTypeLoc STL = 156314564Sdim TL.getAs<TemplateSpecializationTypeLoc>()) { 157314564Sdim // If we have a typedef to a template specialization with exactly one 158314564Sdim // template argument of a function type, this looks like std::function, 159314564Sdim // boost::function, or other function wrapper. Treat these typedefs as 160314564Sdim // functions. 161314564Sdim if (STL.getNumArgs() != 1) 162314564Sdim return false; 163314564Sdim TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); 164314564Sdim if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) 165314564Sdim return false; 166314564Sdim TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); 167314564Sdim TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); 168314564Sdim if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 169314564Sdim ResFTL = FTL; 170314564Sdim return true; 171314564Sdim } 172314564Sdim } 173314564Sdim 174314564Sdim return false; 175314564Sdim} 176314564Sdim 177239313Sdimconst char *ParamCommandComment::getDirectionAsString(PassDirection D) { 178239313Sdim switch (D) { 179239313Sdim case ParamCommandComment::In: 180239313Sdim return "[in]"; 181239313Sdim case ParamCommandComment::Out: 182239313Sdim return "[out]"; 183239313Sdim case ParamCommandComment::InOut: 184239313Sdim return "[in,out]"; 185239313Sdim } 186239313Sdim llvm_unreachable("unknown PassDirection"); 187239313Sdim} 188239313Sdim 189239313Sdimvoid DeclInfo::fill() { 190239313Sdim assert(!IsFilled); 191239313Sdim 192239313Sdim // Set defaults. 193239313Sdim Kind = OtherKind; 194239313Sdim TemplateKind = NotTemplate; 195239313Sdim IsObjCMethod = false; 196239313Sdim IsInstanceMethod = false; 197239313Sdim IsClassMethod = false; 198251662Sdim ParamVars = None; 199276479Sdim TemplateParameters = nullptr; 200239313Sdim 201243830Sdim if (!CommentDecl) { 202239313Sdim // If there is no declaration, the defaults is our only guess. 203239313Sdim IsFilled = true; 204239313Sdim return; 205239313Sdim } 206243830Sdim CurrentDecl = CommentDecl; 207341825Sdim 208243830Sdim Decl::Kind K = CommentDecl->getKind(); 209239313Sdim switch (K) { 210239313Sdim default: 211239313Sdim // Defaults are should be good for declarations we don't handle explicitly. 212239313Sdim break; 213239313Sdim case Decl::Function: 214239313Sdim case Decl::CXXMethod: 215239313Sdim case Decl::CXXConstructor: 216239313Sdim case Decl::CXXDestructor: 217239313Sdim case Decl::CXXConversion: { 218243830Sdim const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); 219239313Sdim Kind = FunctionKind; 220309124Sdim ParamVars = FD->parameters(); 221276479Sdim ReturnType = FD->getReturnType(); 222239313Sdim unsigned NumLists = FD->getNumTemplateParameterLists(); 223239313Sdim if (NumLists != 0) { 224239313Sdim TemplateKind = TemplateSpecialization; 225239313Sdim TemplateParameters = 226239313Sdim FD->getTemplateParameterList(NumLists - 1); 227239313Sdim } 228239313Sdim 229239313Sdim if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 230239313Sdim K == Decl::CXXDestructor || K == Decl::CXXConversion) { 231243830Sdim const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 232239313Sdim IsInstanceMethod = MD->isInstance(); 233239313Sdim IsClassMethod = !IsInstanceMethod; 234239313Sdim } 235239313Sdim break; 236239313Sdim } 237239313Sdim case Decl::ObjCMethod: { 238243830Sdim const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 239239313Sdim Kind = FunctionKind; 240309124Sdim ParamVars = MD->parameters(); 241276479Sdim ReturnType = MD->getReturnType(); 242239313Sdim IsObjCMethod = true; 243239313Sdim IsInstanceMethod = MD->isInstanceMethod(); 244239313Sdim IsClassMethod = !IsInstanceMethod; 245239313Sdim break; 246239313Sdim } 247239313Sdim case Decl::FunctionTemplate: { 248243830Sdim const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); 249239313Sdim Kind = FunctionKind; 250239313Sdim TemplateKind = Template; 251239313Sdim const FunctionDecl *FD = FTD->getTemplatedDecl(); 252309124Sdim ParamVars = FD->parameters(); 253276479Sdim ReturnType = FD->getReturnType(); 254239313Sdim TemplateParameters = FTD->getTemplateParameters(); 255239313Sdim break; 256239313Sdim } 257239313Sdim case Decl::ClassTemplate: { 258243830Sdim const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 259239313Sdim Kind = ClassKind; 260239313Sdim TemplateKind = Template; 261239313Sdim TemplateParameters = CTD->getTemplateParameters(); 262239313Sdim break; 263239313Sdim } 264239313Sdim case Decl::ClassTemplatePartialSpecialization: { 265239313Sdim const ClassTemplatePartialSpecializationDecl *CTPSD = 266243830Sdim cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 267239313Sdim Kind = ClassKind; 268239313Sdim TemplateKind = TemplatePartialSpecialization; 269239313Sdim TemplateParameters = CTPSD->getTemplateParameters(); 270239313Sdim break; 271239313Sdim } 272239313Sdim case Decl::ClassTemplateSpecialization: 273239313Sdim Kind = ClassKind; 274239313Sdim TemplateKind = TemplateSpecialization; 275239313Sdim break; 276239313Sdim case Decl::Record: 277239313Sdim case Decl::CXXRecord: 278239313Sdim Kind = ClassKind; 279239313Sdim break; 280239313Sdim case Decl::Var: 281239313Sdim case Decl::Field: 282239313Sdim case Decl::EnumConstant: 283239313Sdim case Decl::ObjCIvar: 284239313Sdim case Decl::ObjCAtDefsField: 285321369Sdim case Decl::ObjCProperty: { 286321369Sdim const TypeSourceInfo *TSI; 287321369Sdim if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl)) 288321369Sdim TSI = VD->getTypeSourceInfo(); 289321369Sdim else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl)) 290321369Sdim TSI = PD->getTypeSourceInfo(); 291321369Sdim else 292321369Sdim TSI = nullptr; 293321369Sdim if (TSI) { 294321369Sdim TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 295321369Sdim FunctionTypeLoc FTL; 296321369Sdim if (getFunctionTypeLoc(TL, FTL)) { 297321369Sdim ParamVars = FTL.getParams(); 298321369Sdim ReturnType = FTL.getReturnLoc().getType(); 299321369Sdim } 300321369Sdim } 301239313Sdim Kind = VariableKind; 302239313Sdim break; 303321369Sdim } 304239313Sdim case Decl::Namespace: 305239313Sdim Kind = NamespaceKind; 306239313Sdim break; 307314564Sdim case Decl::TypeAlias: 308243830Sdim case Decl::Typedef: { 309243830Sdim Kind = TypedefKind; 310314564Sdim // If this is a typedef / using to something we consider a function, extract 311243830Sdim // arguments and return type. 312314564Sdim const TypeSourceInfo *TSI = 313314564Sdim K == Decl::Typedef 314314564Sdim ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo() 315314564Sdim : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo(); 316243830Sdim if (!TSI) 317243830Sdim break; 318243830Sdim TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 319314564Sdim FunctionTypeLoc FTL; 320314564Sdim if (getFunctionTypeLoc(TL, FTL)) { 321314564Sdim Kind = FunctionKind; 322314564Sdim ParamVars = FTL.getParams(); 323314564Sdim ReturnType = FTL.getReturnLoc().getType(); 324243830Sdim } 325243830Sdim break; 326243830Sdim } 327239313Sdim case Decl::TypeAliasTemplate: { 328243830Sdim const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 329239313Sdim Kind = TypedefKind; 330239313Sdim TemplateKind = Template; 331239313Sdim TemplateParameters = TAT->getTemplateParameters(); 332314564Sdim TypeAliasDecl *TAD = TAT->getTemplatedDecl(); 333314564Sdim if (!TAD) 334314564Sdim break; 335314564Sdim 336314564Sdim const TypeSourceInfo *TSI = TAD->getTypeSourceInfo(); 337314564Sdim if (!TSI) 338314564Sdim break; 339314564Sdim TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 340314564Sdim FunctionTypeLoc FTL; 341314564Sdim if (getFunctionTypeLoc(TL, FTL)) { 342314564Sdim Kind = FunctionKind; 343314564Sdim ParamVars = FTL.getParams(); 344314564Sdim ReturnType = FTL.getReturnLoc().getType(); 345314564Sdim } 346239313Sdim break; 347239313Sdim } 348239313Sdim case Decl::Enum: 349239313Sdim Kind = EnumKind; 350239313Sdim break; 351239313Sdim } 352239313Sdim 353239313Sdim IsFilled = true; 354239313Sdim} 355239313Sdim 356243830SdimStringRef ParamCommandComment::getParamName(const FullComment *FC) const { 357243830Sdim assert(isParamIndexValid()); 358261991Sdim if (isVarArgParam()) 359261991Sdim return "..."; 360261991Sdim return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 361243830Sdim} 362243830Sdim 363243830SdimStringRef TParamCommandComment::getParamName(const FullComment *FC) const { 364243830Sdim assert(isPositionValid()); 365261991Sdim const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 366243830Sdim for (unsigned i = 0, e = getDepth(); i != e; ++i) { 367243830Sdim if (i == e-1) 368243830Sdim return TPL->getParam(getIndex(i))->getName(); 369243830Sdim const NamedDecl *Param = TPL->getParam(getIndex(i)); 370243830Sdim if (const TemplateTemplateParmDecl *TTP = 371243830Sdim dyn_cast<TemplateTemplateParmDecl>(Param)) 372243830Sdim TPL = TTP->getTemplateParameters(); 373243830Sdim } 374243830Sdim return ""; 375243830Sdim} 376243830Sdim 377239313Sdim} // end namespace comments 378239313Sdim} // end namespace clang 379239313Sdim 380