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 19namespace clang { 20namespace comments { 21 22const 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 36namespace { 37struct good {}; 38struct bad {}; 39 40template <typename T> 41good implements_child_begin_end(Comment::child_iterator (T::*)() const) { 42 return good(); 43} 44 45LLVM_ATTRIBUTE_UNUSED 46static 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 54LLVM_ATTRIBUTE_UNUSED 55static 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 69Comment::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 83Comment::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 97bool 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 106bool 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 117const 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 129void 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 = llvm::makeArrayRef(FD->param_begin(), FD->getNumParams()); 161 ReturnType = FD->getReturnType(); 162 unsigned NumLists = FD->getNumTemplateParameterLists(); 163 if (NumLists != 0) { 164 TemplateKind = TemplateSpecialization; 165 TemplateParameters = 166 FD->getTemplateParameterList(NumLists - 1); 167 } 168 169 if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 170 K == Decl::CXXDestructor || K == Decl::CXXConversion) { 171 const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 172 IsInstanceMethod = MD->isInstance(); 173 IsClassMethod = !IsInstanceMethod; 174 } 175 break; 176 } 177 case Decl::ObjCMethod: { 178 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 179 Kind = FunctionKind; 180 ParamVars = llvm::makeArrayRef(MD->param_begin(), MD->param_size()); 181 ReturnType = MD->getReturnType(); 182 IsObjCMethod = true; 183 IsInstanceMethod = MD->isInstanceMethod(); 184 IsClassMethod = !IsInstanceMethod; 185 break; 186 } 187 case Decl::FunctionTemplate: { 188 const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); 189 Kind = FunctionKind; 190 TemplateKind = Template; 191 const FunctionDecl *FD = FTD->getTemplatedDecl(); 192 ParamVars = llvm::makeArrayRef(FD->param_begin(), FD->getNumParams()); 193 ReturnType = FD->getReturnType(); 194 TemplateParameters = FTD->getTemplateParameters(); 195 break; 196 } 197 case Decl::ClassTemplate: { 198 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 199 Kind = ClassKind; 200 TemplateKind = Template; 201 TemplateParameters = CTD->getTemplateParameters(); 202 break; 203 } 204 case Decl::ClassTemplatePartialSpecialization: { 205 const ClassTemplatePartialSpecializationDecl *CTPSD = 206 cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 207 Kind = ClassKind; 208 TemplateKind = TemplatePartialSpecialization; 209 TemplateParameters = CTPSD->getTemplateParameters(); 210 break; 211 } 212 case Decl::ClassTemplateSpecialization: 213 Kind = ClassKind; 214 TemplateKind = TemplateSpecialization; 215 break; 216 case Decl::Record: 217 case Decl::CXXRecord: 218 Kind = ClassKind; 219 break; 220 case Decl::Var: 221 case Decl::Field: 222 case Decl::EnumConstant: 223 case Decl::ObjCIvar: 224 case Decl::ObjCAtDefsField: 225 Kind = VariableKind; 226 break; 227 case Decl::Namespace: 228 Kind = NamespaceKind; 229 break; 230 case Decl::Typedef: { 231 Kind = TypedefKind; 232 // If this is a typedef to something we consider a function, extract 233 // arguments and return type. 234 const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl); 235 const TypeSourceInfo *TSI = TD->getTypeSourceInfo(); 236 if (!TSI) 237 break; 238 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 239 while (true) { 240 TL = TL.IgnoreParens(); 241 // Look through qualified types. 242 if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) { 243 TL = QualifiedTL.getUnqualifiedLoc(); 244 continue; 245 } 246 // Look through pointer types. 247 if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) { 248 TL = PointerTL.getPointeeLoc().getUnqualifiedLoc(); 249 continue; 250 } 251 // Look through reference types. 252 if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) { 253 TL = ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); 254 continue; 255 } 256 // Look through adjusted types. 257 if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) { 258 TL = ATL.getOriginalLoc(); 259 continue; 260 } 261 if (BlockPointerTypeLoc BlockPointerTL = 262 TL.getAs<BlockPointerTypeLoc>()) { 263 TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 264 continue; 265 } 266 if (MemberPointerTypeLoc MemberPointerTL = 267 TL.getAs<MemberPointerTypeLoc>()) { 268 TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 269 continue; 270 } 271 if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) { 272 TL = ETL.getNamedTypeLoc(); 273 continue; 274 } 275 // Is this a typedef for a function type? 276 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 277 Kind = FunctionKind; 278 ParamVars = FTL.getParams(); 279 ReturnType = FTL.getReturnLoc().getType(); 280 break; 281 } 282 if (TemplateSpecializationTypeLoc STL = 283 TL.getAs<TemplateSpecializationTypeLoc>()) { 284 // If we have a typedef to a template specialization with exactly one 285 // template argument of a function type, this looks like std::function, 286 // boost::function, or other function wrapper. Treat these typedefs as 287 // functions. 288 if (STL.getNumArgs() != 1) 289 break; 290 TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); 291 if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) 292 break; 293 TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); 294 TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); 295 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 296 Kind = FunctionKind; 297 ParamVars = FTL.getParams(); 298 ReturnType = FTL.getReturnLoc().getType(); 299 } 300 break; 301 } 302 break; 303 } 304 break; 305 } 306 case Decl::TypeAlias: 307 Kind = TypedefKind; 308 break; 309 case Decl::TypeAliasTemplate: { 310 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 311 Kind = TypedefKind; 312 TemplateKind = Template; 313 TemplateParameters = TAT->getTemplateParameters(); 314 break; 315 } 316 case Decl::Enum: 317 Kind = EnumKind; 318 break; 319 } 320 321 IsFilled = true; 322} 323 324StringRef ParamCommandComment::getParamName(const FullComment *FC) const { 325 assert(isParamIndexValid()); 326 if (isVarArgParam()) 327 return "..."; 328 return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 329} 330 331StringRef TParamCommandComment::getParamName(const FullComment *FC) const { 332 assert(isPositionValid()); 333 const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 334 for (unsigned i = 0, e = getDepth(); i != e; ++i) { 335 if (i == e-1) 336 return TPL->getParam(getIndex(i))->getName(); 337 const NamedDecl *Param = TPL->getParam(getIndex(i)); 338 if (const TemplateTemplateParmDecl *TTP = 339 dyn_cast<TemplateTemplateParmDecl>(Param)) 340 TPL = TTP->getTemplateParameters(); 341 } 342 return ""; 343} 344 345} // end namespace comments 346} // end namespace clang 347 348