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