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<DeclInfo>::value, 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 for (StringRef::const_iterator I = Text.begin(), E = Text.end(); 112 I != E; ++I) { 113 if (!clang::isWhitespace(*I)) 114 return false; 115 } 116 return true; 117 } 118 119 bool ParagraphComment::isWhitespaceNoCache() const { 120 for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { 121 if (const TextComment *TC = dyn_cast<TextComment>(*I)) { 122 if (!TC->isWhitespace()) 123 return false; 124 } else 125 return false; 126 } 127 return true; 128 } 129 130 static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { 131 TypeLoc TL = SrcTL.IgnoreParens(); 132 133 // Look through attribute types. 134 if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>()) 135 return AttributeTL.getModifiedLoc(); 136 // Look through qualified types. 137 if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) 138 return QualifiedTL.getUnqualifiedLoc(); 139 // Look through pointer types. 140 if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) 141 return PointerTL.getPointeeLoc().getUnqualifiedLoc(); 142 // Look through reference types. 143 if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) 144 return ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); 145 // Look through adjusted types. 146 if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) 147 return ATL.getOriginalLoc(); 148 if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>()) 149 return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 150 if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) 151 return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 152 if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) 153 return ETL.getNamedTypeLoc(); 154 155 return TL; 156 } 157 158 static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) { 159 TypeLoc PrevTL; 160 while (PrevTL != TL) { 161 PrevTL = TL; 162 TL = lookThroughTypedefOrTypeAliasLocs(TL); 163 } 164 165 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 166 ResFTL = FTL; 167 return true; 168 } 169 170 if (TemplateSpecializationTypeLoc STL = 171 TL.getAs<TemplateSpecializationTypeLoc>()) { 172 // If we have a typedef to a template specialization with exactly one 173 // template argument of a function type, this looks like std::function, 174 // boost::function, or other function wrapper. Treat these typedefs as 175 // functions. 176 if (STL.getNumArgs() != 1) 177 return false; 178 TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); 179 if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) 180 return false; 181 TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); 182 TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); 183 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 184 ResFTL = FTL; 185 return true; 186 } 187 } 188 189 return false; 190 } 191 192 const char *ParamCommandComment::getDirectionAsString(PassDirection D) { 193 switch (D) { 194 case ParamCommandComment::In: 195 return "[in]"; 196 case ParamCommandComment::Out: 197 return "[out]"; 198 case ParamCommandComment::InOut: 199 return "[in,out]"; 200 } 201 llvm_unreachable("unknown PassDirection"); 202 } 203 204 void DeclInfo::fill() { 205 assert(!IsFilled); 206 207 // Set defaults. 208 Kind = OtherKind; 209 TemplateKind = NotTemplate; 210 IsObjCMethod = false; 211 IsInstanceMethod = false; 212 IsClassMethod = false; 213 ParamVars = None; 214 TemplateParameters = nullptr; 215 216 if (!CommentDecl) { 217 // If there is no declaration, the defaults is our only guess. 218 IsFilled = true; 219 return; 220 } 221 CurrentDecl = CommentDecl; 222 223 Decl::Kind K = CommentDecl->getKind(); 224 switch (K) { 225 default: 226 // Defaults are should be good for declarations we don't handle explicitly. 227 break; 228 case Decl::Function: 229 case Decl::CXXMethod: 230 case Decl::CXXConstructor: 231 case Decl::CXXDestructor: 232 case Decl::CXXConversion: { 233 const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); 234 Kind = FunctionKind; 235 ParamVars = FD->parameters(); 236 ReturnType = FD->getReturnType(); 237 unsigned NumLists = FD->getNumTemplateParameterLists(); 238 if (NumLists != 0) { 239 TemplateKind = TemplateSpecialization; 240 TemplateParameters = 241 FD->getTemplateParameterList(NumLists - 1); 242 } 243 244 if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 245 K == Decl::CXXDestructor || K == Decl::CXXConversion) { 246 const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 247 IsInstanceMethod = MD->isInstance(); 248 IsClassMethod = !IsInstanceMethod; 249 } 250 break; 251 } 252 case Decl::ObjCMethod: { 253 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 254 Kind = FunctionKind; 255 ParamVars = MD->parameters(); 256 ReturnType = MD->getReturnType(); 257 IsObjCMethod = true; 258 IsInstanceMethod = MD->isInstanceMethod(); 259 IsClassMethod = !IsInstanceMethod; 260 break; 261 } 262 case Decl::FunctionTemplate: { 263 const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); 264 Kind = FunctionKind; 265 TemplateKind = Template; 266 const FunctionDecl *FD = FTD->getTemplatedDecl(); 267 ParamVars = FD->parameters(); 268 ReturnType = FD->getReturnType(); 269 TemplateParameters = FTD->getTemplateParameters(); 270 break; 271 } 272 case Decl::ClassTemplate: { 273 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 274 Kind = ClassKind; 275 TemplateKind = Template; 276 TemplateParameters = CTD->getTemplateParameters(); 277 break; 278 } 279 case Decl::ClassTemplatePartialSpecialization: { 280 const ClassTemplatePartialSpecializationDecl *CTPSD = 281 cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 282 Kind = ClassKind; 283 TemplateKind = TemplatePartialSpecialization; 284 TemplateParameters = CTPSD->getTemplateParameters(); 285 break; 286 } 287 case Decl::ClassTemplateSpecialization: 288 Kind = ClassKind; 289 TemplateKind = TemplateSpecialization; 290 break; 291 case Decl::Record: 292 case Decl::CXXRecord: 293 Kind = ClassKind; 294 break; 295 case Decl::Var: 296 case Decl::Field: 297 case Decl::EnumConstant: 298 case Decl::ObjCIvar: 299 case Decl::ObjCAtDefsField: 300 case Decl::ObjCProperty: { 301 const TypeSourceInfo *TSI; 302 if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl)) 303 TSI = VD->getTypeSourceInfo(); 304 else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl)) 305 TSI = PD->getTypeSourceInfo(); 306 else 307 TSI = nullptr; 308 if (TSI) { 309 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 310 FunctionTypeLoc FTL; 311 if (getFunctionTypeLoc(TL, FTL)) { 312 ParamVars = FTL.getParams(); 313 ReturnType = FTL.getReturnLoc().getType(); 314 } 315 } 316 Kind = VariableKind; 317 break; 318 } 319 case Decl::Namespace: 320 Kind = NamespaceKind; 321 break; 322 case Decl::TypeAlias: 323 case Decl::Typedef: { 324 Kind = TypedefKind; 325 // If this is a typedef / using to something we consider a function, extract 326 // arguments and return type. 327 const TypeSourceInfo *TSI = 328 K == Decl::Typedef 329 ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo() 330 : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo(); 331 if (!TSI) 332 break; 333 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 334 FunctionTypeLoc FTL; 335 if (getFunctionTypeLoc(TL, FTL)) { 336 Kind = FunctionKind; 337 ParamVars = FTL.getParams(); 338 ReturnType = FTL.getReturnLoc().getType(); 339 } 340 break; 341 } 342 case Decl::TypeAliasTemplate: { 343 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 344 Kind = TypedefKind; 345 TemplateKind = Template; 346 TemplateParameters = TAT->getTemplateParameters(); 347 TypeAliasDecl *TAD = TAT->getTemplatedDecl(); 348 if (!TAD) 349 break; 350 351 const TypeSourceInfo *TSI = TAD->getTypeSourceInfo(); 352 if (!TSI) 353 break; 354 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 355 FunctionTypeLoc FTL; 356 if (getFunctionTypeLoc(TL, FTL)) { 357 Kind = FunctionKind; 358 ParamVars = FTL.getParams(); 359 ReturnType = FTL.getReturnLoc().getType(); 360 } 361 break; 362 } 363 case Decl::Enum: 364 Kind = EnumKind; 365 break; 366 } 367 368 IsFilled = true; 369 } 370 371 StringRef ParamCommandComment::getParamName(const FullComment *FC) const { 372 assert(isParamIndexValid()); 373 if (isVarArgParam()) 374 return "..."; 375 return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 376 } 377 378 StringRef TParamCommandComment::getParamName(const FullComment *FC) const { 379 assert(isPositionValid()); 380 const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 381 for (unsigned i = 0, e = getDepth(); i != e; ++i) { 382 assert(TPL && "Unknown TemplateParameterList"); 383 if (i == e - 1) 384 return TPL->getParam(getIndex(i))->getName(); 385 const NamedDecl *Param = TPL->getParam(getIndex(i)); 386 if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) 387 TPL = TTP->getTemplateParameters(); 388 } 389 return ""; 390 } 391 392 } // end namespace comments 393 } // end namespace clang 394 395