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