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/Comment.h" 11 #include "clang/AST/Decl.h" 12 #include "clang/AST/DeclObjC.h" 13 #include "clang/AST/DeclTemplate.h" 14 #include "llvm/Support/ErrorHandling.h" 15 #include "llvm/Support/raw_ostream.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 void Comment::dump() const { 35 // It is important that Comment::dump() is defined in a different TU than 36 // Comment::dump(raw_ostream, SourceManager). If both functions were defined 37 // in CommentDumper.cpp, that object file would be removed by linker because 38 // none of its functions are referenced by other object files, despite the 39 // LLVM_ATTRIBUTE_USED. 40 dump(llvm::errs(), NULL); 41 } 42 43 void Comment::dump(SourceManager &SM) const { 44 dump(llvm::errs(), &SM); 45 } 46 47 namespace { 48 struct good {}; 49 struct bad {}; 50 51 template <typename T> 52 good implements_child_begin_end(Comment::child_iterator (T::*)() const) { 53 return good(); 54 } 55 56 static inline bad implements_child_begin_end( 57 Comment::child_iterator (Comment::*)() const) { 58 return bad(); 59 } 60 61 #define ASSERT_IMPLEMENTS_child_begin(function) \ 62 (void) sizeof(good(implements_child_begin_end(function))) 63 64 static inline void CheckCommentASTNodes() { 65 #define ABSTRACT_COMMENT(COMMENT) 66 #define COMMENT(CLASS, PARENT) \ 67 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ 68 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); 69 #include "clang/AST/CommentNodes.inc" 70 #undef COMMENT 71 #undef ABSTRACT_COMMENT 72 } 73 74 #undef ASSERT_IMPLEMENTS_child_begin 75 76 } // end unnamed namespace 77 78 Comment::child_iterator Comment::child_begin() const { 79 switch (getCommentKind()) { 80 case NoCommentKind: llvm_unreachable("comment without a kind"); 81 #define ABSTRACT_COMMENT(COMMENT) 82 #define COMMENT(CLASS, PARENT) \ 83 case CLASS##Kind: \ 84 return static_cast<const CLASS *>(this)->child_begin(); 85 #include "clang/AST/CommentNodes.inc" 86 #undef COMMENT 87 #undef ABSTRACT_COMMENT 88 } 89 llvm_unreachable("Unknown comment kind!"); 90 } 91 92 Comment::child_iterator Comment::child_end() const { 93 switch (getCommentKind()) { 94 case NoCommentKind: llvm_unreachable("comment without a kind"); 95 #define ABSTRACT_COMMENT(COMMENT) 96 #define COMMENT(CLASS, PARENT) \ 97 case CLASS##Kind: \ 98 return static_cast<const CLASS *>(this)->child_end(); 99 #include "clang/AST/CommentNodes.inc" 100 #undef COMMENT 101 #undef ABSTRACT_COMMENT 102 } 103 llvm_unreachable("Unknown comment kind!"); 104 } 105 106 bool TextComment::isWhitespaceNoCache() const { 107 for (StringRef::const_iterator I = Text.begin(), E = Text.end(); 108 I != E; ++I) { 109 const char C = *I; 110 if (C != ' ' && C != '\n' && C != '\r' && 111 C != '\t' && C != '\f' && C != '\v') 112 return false; 113 } 114 return true; 115 } 116 117 bool ParagraphComment::isWhitespaceNoCache() const { 118 for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { 119 if (const TextComment *TC = dyn_cast<TextComment>(*I)) { 120 if (!TC->isWhitespace()) 121 return false; 122 } else 123 return false; 124 } 125 return true; 126 } 127 128 const char *ParamCommandComment::getDirectionAsString(PassDirection D) { 129 switch (D) { 130 case ParamCommandComment::In: 131 return "[in]"; 132 case ParamCommandComment::Out: 133 return "[out]"; 134 case ParamCommandComment::InOut: 135 return "[in,out]"; 136 } 137 llvm_unreachable("unknown PassDirection"); 138 } 139 140 void DeclInfo::fill() { 141 assert(!IsFilled); 142 143 // Set defaults. 144 Kind = OtherKind; 145 IsTemplateDecl = false; 146 IsTemplateSpecialization = false; 147 IsTemplatePartialSpecialization = false; 148 IsInstanceMethod = false; 149 IsClassMethod = false; 150 ParamVars = ArrayRef<const ParmVarDecl *>(); 151 TemplateParameters = NULL; 152 153 if (!ThisDecl) { 154 // If there is no declaration, the defaults is our only guess. 155 IsFilled = true; 156 return; 157 } 158 159 Decl::Kind K = ThisDecl->getKind(); 160 switch (K) { 161 default: 162 // Defaults are should be good for declarations we don't handle explicitly. 163 break; 164 case Decl::Function: 165 case Decl::CXXMethod: 166 case Decl::CXXConstructor: 167 case Decl::CXXDestructor: 168 case Decl::CXXConversion: { 169 const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl); 170 Kind = FunctionKind; 171 ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), 172 FD->getNumParams()); 173 ResultType = FD->getResultType(); 174 unsigned NumLists = FD->getNumTemplateParameterLists(); 175 if (NumLists != 0) { 176 IsTemplateDecl = true; 177 IsTemplateSpecialization = true; 178 TemplateParameters = 179 FD->getTemplateParameterList(NumLists - 1); 180 } 181 182 if (K == Decl::CXXMethod || K == Decl::CXXConstructor || 183 K == Decl::CXXDestructor || K == Decl::CXXConversion) { 184 const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl); 185 IsInstanceMethod = MD->isInstance(); 186 IsClassMethod = !IsInstanceMethod; 187 } 188 break; 189 } 190 case Decl::ObjCMethod: { 191 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl); 192 Kind = FunctionKind; 193 ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(), 194 MD->param_size()); 195 ResultType = MD->getResultType(); 196 IsInstanceMethod = MD->isInstanceMethod(); 197 IsClassMethod = !IsInstanceMethod; 198 break; 199 } 200 case Decl::FunctionTemplate: { 201 const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl); 202 Kind = FunctionKind; 203 IsTemplateDecl = true; 204 const FunctionDecl *FD = FTD->getTemplatedDecl(); 205 ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), 206 FD->getNumParams()); 207 ResultType = FD->getResultType(); 208 TemplateParameters = FTD->getTemplateParameters(); 209 break; 210 } 211 case Decl::ClassTemplate: { 212 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl); 213 Kind = ClassKind; 214 IsTemplateDecl = true; 215 TemplateParameters = CTD->getTemplateParameters(); 216 break; 217 } 218 case Decl::ClassTemplatePartialSpecialization: { 219 const ClassTemplatePartialSpecializationDecl *CTPSD = 220 cast<ClassTemplatePartialSpecializationDecl>(ThisDecl); 221 Kind = ClassKind; 222 IsTemplateDecl = true; 223 IsTemplatePartialSpecialization = true; 224 TemplateParameters = CTPSD->getTemplateParameters(); 225 break; 226 } 227 case Decl::ClassTemplateSpecialization: 228 Kind = ClassKind; 229 IsTemplateDecl = true; 230 IsTemplateSpecialization = true; 231 break; 232 case Decl::Record: 233 case Decl::CXXRecord: 234 Kind = ClassKind; 235 break; 236 case Decl::Var: 237 case Decl::Field: 238 case Decl::ObjCIvar: 239 case Decl::ObjCAtDefsField: 240 Kind = VariableKind; 241 break; 242 case Decl::Namespace: 243 Kind = NamespaceKind; 244 break; 245 case Decl::Typedef: 246 case Decl::TypeAlias: 247 Kind = TypedefKind; 248 break; 249 case Decl::TypeAliasTemplate: { 250 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl); 251 Kind = TypedefKind; 252 IsTemplateDecl = true; 253 TemplateParameters = TAT->getTemplateParameters(); 254 break; 255 } 256 } 257 258 IsFilled = true; 259 } 260 261 } // end namespace comments 262 } // end namespace clang 263 264