1 //===--- Comment.cpp - Comment AST node implementation --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/AST/Comment.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/Decl.h" 12 #include "clang/AST/DeclObjC.h" 13 #include "clang/AST/DeclTemplate.h" 14 #include "clang/Basic/CharInfo.h" 15 #include "llvm/Support/ErrorHandling.h" 16 #include <type_traits> 17 18 namespace clang { 19 namespace comments { 20 21 // Check that no comment class has a non-trival destructor. They are allocated 22 // with a BumpPtrAllocator and therefore their destructor is not executed. 23 #define ABSTRACT_COMMENT(COMMENT) 24 #define COMMENT(CLASS, PARENT) \ 25 static_assert(std::is_trivially_destructible<CLASS>::value, \ 26 #CLASS " should be trivially destructible!"); 27 #include "clang/AST/CommentNodes.inc" 28 #undef COMMENT 29 #undef ABSTRACT_COMMENT 30 31 // DeclInfo is also allocated with a BumpPtrAllocator. 32 static_assert(std::is_trivially_destructible_v<DeclInfo>, 33 "DeclInfo should be trivially destructible!"); 34 35 const char *Comment::getCommentKindName() const { 36 switch (getCommentKind()) { 37 case NoCommentKind: return "NoCommentKind"; 38 #define ABSTRACT_COMMENT(COMMENT) 39 #define COMMENT(CLASS, PARENT) \ 40 case CLASS##Kind: \ 41 return #CLASS; 42 #include "clang/AST/CommentNodes.inc" 43 #undef COMMENT 44 #undef ABSTRACT_COMMENT 45 } 46 llvm_unreachable("Unknown comment kind!"); 47 } 48 49 namespace { 50 struct good {}; 51 struct bad {}; 52 53 template <typename T> 54 good implements_child_begin_end(Comment::child_iterator (T::*)() const) { 55 return good(); 56 } 57 58 LLVM_ATTRIBUTE_UNUSED 59 static inline bad implements_child_begin_end( 60 Comment::child_iterator (Comment::*)() const) { 61 return bad(); 62 } 63 64 #define ASSERT_IMPLEMENTS_child_begin(function) \ 65 (void) good(implements_child_begin_end(function)) 66 67 LLVM_ATTRIBUTE_UNUSED 68 static inline void CheckCommentASTNodes() { 69 #define ABSTRACT_COMMENT(COMMENT) 70 #define COMMENT(CLASS, PARENT) \ 71 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ 72 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); 73 #include "clang/AST/CommentNodes.inc" 74 #undef COMMENT 75 #undef ABSTRACT_COMMENT 76 } 77 78 #undef ASSERT_IMPLEMENTS_child_begin 79 80 } // end unnamed namespace 81 82 Comment::child_iterator Comment::child_begin() const { 83 switch (getCommentKind()) { 84 case NoCommentKind: llvm_unreachable("comment without a kind"); 85 #define ABSTRACT_COMMENT(COMMENT) 86 #define COMMENT(CLASS, PARENT) \ 87 case CLASS##Kind: \ 88 return static_cast<const CLASS *>(this)->child_begin(); 89 #include "clang/AST/CommentNodes.inc" 90 #undef COMMENT 91 #undef ABSTRACT_COMMENT 92 } 93 llvm_unreachable("Unknown comment kind!"); 94 } 95 96 Comment::child_iterator Comment::child_end() const { 97 switch (getCommentKind()) { 98 case NoCommentKind: llvm_unreachable("comment without a kind"); 99 #define ABSTRACT_COMMENT(COMMENT) 100 #define COMMENT(CLASS, PARENT) \ 101 case CLASS##Kind: \ 102 return static_cast<const CLASS *>(this)->child_end(); 103 #include "clang/AST/CommentNodes.inc" 104 #undef COMMENT 105 #undef ABSTRACT_COMMENT 106 } 107 llvm_unreachable("Unknown comment kind!"); 108 } 109 110 bool TextComment::isWhitespaceNoCache() const { 111 return llvm::all_of(Text, clang::isWhitespace); 112 } 113 114 bool ParagraphComment::isWhitespaceNoCache() const { 115 for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { 116 if (const TextComment *TC = dyn_cast<TextComment>(*I)) { 117 if (!TC->isWhitespace()) 118 return false; 119 } else 120 return false; 121 } 122 return true; 123 } 124 125 static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { 126 TypeLoc TL = SrcTL.IgnoreParens(); 127 128 // Look through attribute types. 129 if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>()) 130 return AttributeTL.getModifiedLoc(); 131 // Look through qualified types. 132 if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) 133 return QualifiedTL.getUnqualifiedLoc(); 134 // Look through pointer types. 135 if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) 136 return PointerTL.getPointeeLoc().getUnqualifiedLoc(); 137 // Look through reference types. 138 if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) 139 return ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); 140 // Look through adjusted types. 141 if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) 142 return ATL.getOriginalLoc(); 143 if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>()) 144 return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 145 if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) 146 return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 147 if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) 148 return ETL.getNamedTypeLoc(); 149 150 return TL; 151 } 152 153 static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) { 154 TypeLoc PrevTL; 155 while (PrevTL != TL) { 156 PrevTL = TL; 157 TL = lookThroughTypedefOrTypeAliasLocs(TL); 158 } 159 160 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 161 ResFTL = FTL; 162 return true; 163 } 164 165 if (TemplateSpecializationTypeLoc STL = 166 TL.getAs<TemplateSpecializationTypeLoc>()) { 167 // If we have a typedef to a template specialization with exactly one 168 // template argument of a function type, this looks like std::function, 169 // boost::function, or other function wrapper. Treat these typedefs as 170 // functions. 171 if (STL.getNumArgs() != 1) 172 return false; 173 TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); 174 if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) 175 return false; 176 TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); 177 TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); 178 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 179 ResFTL = FTL; 180 return true; 181 } 182 } 183 184 return false; 185 } 186 187 const char *ParamCommandComment::getDirectionAsString(PassDirection D) { 188 switch (D) { 189 case ParamCommandComment::In: 190 return "[in]"; 191 case ParamCommandComment::Out: 192 return "[out]"; 193 case ParamCommandComment::InOut: 194 return "[in,out]"; 195 } 196 llvm_unreachable("unknown PassDirection"); 197 } 198 199 void DeclInfo::fill() { 200 assert(!IsFilled); 201 202 // Set defaults. 203 Kind = OtherKind; 204 TemplateKind = NotTemplate; 205 IsObjCMethod = false; 206 IsInstanceMethod = false; 207 IsClassMethod = false; 208 IsVariadic = false; 209 ParamVars = std::nullopt; 210 TemplateParameters = nullptr; 211 212 if (!CommentDecl) { 213 // If there is no declaration, the defaults is our only guess. 214 IsFilled = true; 215 return; 216 } 217 CurrentDecl = CommentDecl; 218 219 Decl::Kind K = CommentDecl->getKind(); 220 const TypeSourceInfo *TSI = nullptr; 221 switch (K) { 222 default: 223 // Defaults are should be good for declarations we don't handle explicitly. 224 break; 225 case Decl::Function: 226 case Decl::CXXMethod: 227 case Decl::CXXConstructor: 228 case Decl::CXXDestructor: 229 case Decl::CXXConversion: { 230 const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); 231 Kind = FunctionKind; 232 ParamVars = FD->parameters(); 233 ReturnType = FD->getReturnType(); 234 unsigned NumLists = FD->getNumTemplateParameterLists(); 235 if (NumLists != 0) { 236 TemplateKind = TemplateSpecialization; 237 TemplateParameters = 238 FD->getTemplateParameterList(NumLists - 1); 239 } 240 241 if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 242 K == Decl::CXXDestructor || K == Decl::CXXConversion) { 243 const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 244 IsInstanceMethod = MD->isInstance(); 245 IsClassMethod = !IsInstanceMethod; 246 } 247 IsVariadic = FD->isVariadic(); 248 assert(involvesFunctionType()); 249 break; 250 } 251 case Decl::ObjCMethod: { 252 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 253 Kind = FunctionKind; 254 ParamVars = MD->parameters(); 255 ReturnType = MD->getReturnType(); 256 IsObjCMethod = true; 257 IsInstanceMethod = MD->isInstanceMethod(); 258 IsClassMethod = !IsInstanceMethod; 259 IsVariadic = MD->isVariadic(); 260 assert(involvesFunctionType()); 261 break; 262 } 263 case Decl::FunctionTemplate: { 264 const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); 265 Kind = FunctionKind; 266 TemplateKind = Template; 267 const FunctionDecl *FD = FTD->getTemplatedDecl(); 268 ParamVars = FD->parameters(); 269 ReturnType = FD->getReturnType(); 270 TemplateParameters = FTD->getTemplateParameters(); 271 IsVariadic = FD->isVariadic(); 272 assert(involvesFunctionType()); 273 break; 274 } 275 case Decl::ClassTemplate: { 276 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 277 Kind = ClassKind; 278 TemplateKind = Template; 279 TemplateParameters = CTD->getTemplateParameters(); 280 break; 281 } 282 case Decl::ClassTemplatePartialSpecialization: { 283 const ClassTemplatePartialSpecializationDecl *CTPSD = 284 cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 285 Kind = ClassKind; 286 TemplateKind = TemplatePartialSpecialization; 287 TemplateParameters = CTPSD->getTemplateParameters(); 288 break; 289 } 290 case Decl::ClassTemplateSpecialization: 291 Kind = ClassKind; 292 TemplateKind = TemplateSpecialization; 293 break; 294 case Decl::Record: 295 case Decl::CXXRecord: 296 Kind = ClassKind; 297 break; 298 case Decl::Var: 299 if (const VarTemplateDecl *VTD = 300 cast<VarDecl>(CommentDecl)->getDescribedVarTemplate()) { 301 TemplateKind = TemplateSpecialization; 302 TemplateParameters = VTD->getTemplateParameters(); 303 } 304 [[fallthrough]]; 305 case Decl::Field: 306 case Decl::EnumConstant: 307 case Decl::ObjCIvar: 308 case Decl::ObjCAtDefsField: 309 case Decl::ObjCProperty: 310 if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl)) 311 TSI = VD->getTypeSourceInfo(); 312 else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl)) 313 TSI = PD->getTypeSourceInfo(); 314 Kind = VariableKind; 315 break; 316 case Decl::VarTemplate: { 317 const VarTemplateDecl *VTD = cast<VarTemplateDecl>(CommentDecl); 318 Kind = VariableKind; 319 TemplateKind = Template; 320 TemplateParameters = VTD->getTemplateParameters(); 321 if (const VarDecl *VD = VTD->getTemplatedDecl()) 322 TSI = VD->getTypeSourceInfo(); 323 break; 324 } 325 case Decl::Namespace: 326 Kind = NamespaceKind; 327 break; 328 case Decl::TypeAlias: 329 case Decl::Typedef: 330 Kind = TypedefKind; 331 TSI = cast<TypedefNameDecl>(CommentDecl)->getTypeSourceInfo(); 332 break; 333 case Decl::TypeAliasTemplate: { 334 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 335 Kind = TypedefKind; 336 TemplateKind = Template; 337 TemplateParameters = TAT->getTemplateParameters(); 338 if (TypeAliasDecl *TAD = TAT->getTemplatedDecl()) 339 TSI = TAD->getTypeSourceInfo(); 340 break; 341 } 342 case Decl::Enum: 343 Kind = EnumKind; 344 break; 345 } 346 347 // If the type is a typedef / using to something we consider a function, 348 // extract arguments and return type. 349 if (TSI) { 350 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 351 FunctionTypeLoc FTL; 352 if (getFunctionTypeLoc(TL, FTL)) { 353 ParamVars = FTL.getParams(); 354 ReturnType = FTL.getReturnLoc().getType(); 355 if (const auto *FPT = dyn_cast<FunctionProtoType>(FTL.getTypePtr())) 356 IsVariadic = FPT->isVariadic(); 357 assert(involvesFunctionType()); 358 } 359 } 360 361 IsFilled = true; 362 } 363 364 StringRef ParamCommandComment::getParamName(const FullComment *FC) const { 365 assert(isParamIndexValid()); 366 if (isVarArgParam()) 367 return "..."; 368 return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 369 } 370 371 StringRef TParamCommandComment::getParamName(const FullComment *FC) const { 372 assert(isPositionValid()); 373 const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 374 for (unsigned i = 0, e = getDepth(); i != e; ++i) { 375 assert(TPL && "Unknown TemplateParameterList"); 376 if (i == e - 1) 377 return TPL->getParam(getIndex(i))->getName(); 378 const NamedDecl *Param = TPL->getParam(getIndex(i)); 379 if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) 380 TPL = TTP->getTemplateParameters(); 381 } 382 return ""; 383 } 384 385 } // end namespace comments 386 } // end namespace clang 387 388