Comment.cpp revision 3520868fcffb6e3405014cd47973bfa757487a40
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 45static inline bad implements_child_begin_end( 46 Comment::child_iterator (Comment::*)() const) { 47 return bad(); 48} 49 50#define ASSERT_IMPLEMENTS_child_begin(function) \ 51 (void) sizeof(good(implements_child_begin_end(function))) 52 53static 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 67Comment::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 81Comment::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 95bool 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 104bool 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 115const char *ParamCommandComment::getDirectionAsString(PassDirection D) { 116 switch (D) { 117 case ParamCommandComment::In: 118 return "[in]"; 119 case ParamCommandComment::Out: 120 return "[out]"; 121 case ParamCommandComment::InOut: 122 return "[in,out]"; 123 } 124 llvm_unreachable("unknown PassDirection"); 125} 126 127void DeclInfo::fill() { 128 assert(!IsFilled); 129 130 // Set defaults. 131 Kind = OtherKind; 132 TemplateKind = NotTemplate; 133 IsObjCMethod = false; 134 IsInstanceMethod = false; 135 IsClassMethod = false; 136 ParamVars = None; 137 TemplateParameters = NULL; 138 139 if (!CommentDecl) { 140 // If there is no declaration, the defaults is our only guess. 141 IsFilled = true; 142 return; 143 } 144 CurrentDecl = CommentDecl; 145 146 Decl::Kind K = CommentDecl->getKind(); 147 switch (K) { 148 default: 149 // Defaults are should be good for declarations we don't handle explicitly. 150 break; 151 case Decl::Function: 152 case Decl::CXXMethod: 153 case Decl::CXXConstructor: 154 case Decl::CXXDestructor: 155 case Decl::CXXConversion: { 156 const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); 157 Kind = FunctionKind; 158 ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), 159 FD->getNumParams()); 160 ResultType = FD->getResultType(); 161 unsigned NumLists = FD->getNumTemplateParameterLists(); 162 if (NumLists != 0) { 163 TemplateKind = TemplateSpecialization; 164 TemplateParameters = 165 FD->getTemplateParameterList(NumLists - 1); 166 } 167 168 if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 169 K == Decl::CXXDestructor || K == Decl::CXXConversion) { 170 const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); 171 IsInstanceMethod = MD->isInstance(); 172 IsClassMethod = !IsInstanceMethod; 173 } 174 break; 175 } 176 case Decl::ObjCMethod: { 177 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); 178 Kind = FunctionKind; 179 ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(), 180 MD->param_size()); 181 ResultType = MD->getResultType(); 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 = ArrayRef<const ParmVarDecl *>(FD->param_begin(), 193 FD->getNumParams()); 194 ResultType = FD->getResultType(); 195 TemplateParameters = FTD->getTemplateParameters(); 196 break; 197 } 198 case Decl::ClassTemplate: { 199 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); 200 Kind = ClassKind; 201 TemplateKind = Template; 202 TemplateParameters = CTD->getTemplateParameters(); 203 break; 204 } 205 case Decl::ClassTemplatePartialSpecialization: { 206 const ClassTemplatePartialSpecializationDecl *CTPSD = 207 cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); 208 Kind = ClassKind; 209 TemplateKind = TemplatePartialSpecialization; 210 TemplateParameters = CTPSD->getTemplateParameters(); 211 break; 212 } 213 case Decl::ClassTemplateSpecialization: 214 Kind = ClassKind; 215 TemplateKind = TemplateSpecialization; 216 break; 217 case Decl::Record: 218 case Decl::CXXRecord: 219 Kind = ClassKind; 220 break; 221 case Decl::Var: 222 case Decl::Field: 223 case Decl::EnumConstant: 224 case Decl::ObjCIvar: 225 case Decl::ObjCAtDefsField: 226 Kind = VariableKind; 227 break; 228 case Decl::Namespace: 229 Kind = NamespaceKind; 230 break; 231 case Decl::Typedef: { 232 Kind = TypedefKind; 233 // If this is a typedef to something we consider a function, extract 234 // arguments and return type. 235 const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl); 236 const TypeSourceInfo *TSI = TD->getTypeSourceInfo(); 237 if (!TSI) 238 break; 239 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); 240 while (true) { 241 TL = TL.IgnoreParens(); 242 // Look through qualified types. 243 if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) { 244 TL = QualifiedTL.getUnqualifiedLoc(); 245 continue; 246 } 247 // Look through pointer types. 248 if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) { 249 TL = PointerTL.getPointeeLoc().getUnqualifiedLoc(); 250 continue; 251 } 252 if (BlockPointerTypeLoc BlockPointerTL = 253 TL.getAs<BlockPointerTypeLoc>()) { 254 TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); 255 continue; 256 } 257 if (MemberPointerTypeLoc MemberPointerTL = 258 TL.getAs<MemberPointerTypeLoc>()) { 259 TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); 260 continue; 261 } 262 // Is this a typedef for a function type? 263 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { 264 Kind = FunctionKind; 265 ArrayRef<ParmVarDecl *> Params = FTL.getParams(); 266 ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(), 267 Params.size()); 268 ResultType = FTL.getResultLoc().getType(); 269 break; 270 } 271 break; 272 } 273 break; 274 } 275 case Decl::TypeAlias: 276 Kind = TypedefKind; 277 break; 278 case Decl::TypeAliasTemplate: { 279 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); 280 Kind = TypedefKind; 281 TemplateKind = Template; 282 TemplateParameters = TAT->getTemplateParameters(); 283 break; 284 } 285 case Decl::Enum: 286 Kind = EnumKind; 287 break; 288 } 289 290 IsFilled = true; 291} 292 293StringRef ParamCommandComment::getParamName(const FullComment *FC) const { 294 assert(isParamIndexValid()); 295 if (isVarArgParam()) 296 return "..."; 297 return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); 298} 299 300StringRef TParamCommandComment::getParamName(const FullComment *FC) const { 301 assert(isPositionValid()); 302 const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; 303 for (unsigned i = 0, e = getDepth(); i != e; ++i) { 304 if (i == e-1) 305 return TPL->getParam(getIndex(i))->getName(); 306 const NamedDecl *Param = TPL->getParam(getIndex(i)); 307 if (const TemplateTemplateParmDecl *TTP = 308 dyn_cast<TemplateTemplateParmDecl>(Param)) 309 TPL = TTP->getTemplateParameters(); 310 } 311 return ""; 312} 313 314} // end namespace comments 315} // end namespace clang 316 317