1 //===-- Serializer.cpp - ClangDoc Serializer --------------------*- C++ -*-===// 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 "Serialize.h" 11 #include "BitcodeWriter.h" 12 #include "clang/AST/Comment.h" 13 #include "clang/Index/USRGeneration.h" 14 #include "llvm/ADT/Hashing.h" 15 #include "llvm/ADT/StringExtras.h" 16 #include "llvm/Support/SHA1.h" 17 18 using clang::comments::FullComment; 19 20 namespace clang { 21 namespace doc { 22 namespace serialize { 23 24 SymbolID hashUSR(llvm::StringRef USR) { 25 return llvm::SHA1::hash(arrayRefFromStringRef(USR)); 26 } 27 28 class ClangDocCommentVisitor 29 : public ConstCommentVisitor<ClangDocCommentVisitor> { 30 public: 31 ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {} 32 33 void parseComment(const comments::Comment *C); 34 35 void visitTextComment(const TextComment *C); 36 void visitInlineCommandComment(const InlineCommandComment *C); 37 void visitHTMLStartTagComment(const HTMLStartTagComment *C); 38 void visitHTMLEndTagComment(const HTMLEndTagComment *C); 39 void visitBlockCommandComment(const BlockCommandComment *C); 40 void visitParamCommandComment(const ParamCommandComment *C); 41 void visitTParamCommandComment(const TParamCommandComment *C); 42 void visitVerbatimBlockComment(const VerbatimBlockComment *C); 43 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 44 void visitVerbatimLineComment(const VerbatimLineComment *C); 45 46 private: 47 std::string getCommandName(unsigned CommandID) const; 48 bool isWhitespaceOnly(StringRef S) const; 49 50 CommentInfo &CurrentCI; 51 }; 52 53 void ClangDocCommentVisitor::parseComment(const comments::Comment *C) { 54 CurrentCI.Kind = C->getCommentKindName(); 55 ConstCommentVisitor<ClangDocCommentVisitor>::visit(C); 56 for (comments::Comment *Child : 57 llvm::make_range(C->child_begin(), C->child_end())) { 58 CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>()); 59 ClangDocCommentVisitor Visitor(*CurrentCI.Children.back()); 60 Visitor.parseComment(Child); 61 } 62 } 63 64 void ClangDocCommentVisitor::visitTextComment(const TextComment *C) { 65 if (!isWhitespaceOnly(C->getText())) 66 CurrentCI.Text = C->getText(); 67 } 68 69 void ClangDocCommentVisitor::visitInlineCommandComment( 70 const InlineCommandComment *C) { 71 CurrentCI.Name = getCommandName(C->getCommandID()); 72 for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I) 73 CurrentCI.Args.push_back(C->getArgText(I)); 74 } 75 76 void ClangDocCommentVisitor::visitHTMLStartTagComment( 77 const HTMLStartTagComment *C) { 78 CurrentCI.Name = C->getTagName(); 79 CurrentCI.SelfClosing = C->isSelfClosing(); 80 for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) { 81 const HTMLStartTagComment::Attribute &Attr = C->getAttr(I); 82 CurrentCI.AttrKeys.push_back(Attr.Name); 83 CurrentCI.AttrValues.push_back(Attr.Value); 84 } 85 } 86 87 void ClangDocCommentVisitor::visitHTMLEndTagComment( 88 const HTMLEndTagComment *C) { 89 CurrentCI.Name = C->getTagName(); 90 CurrentCI.SelfClosing = true; 91 } 92 93 void ClangDocCommentVisitor::visitBlockCommandComment( 94 const BlockCommandComment *C) { 95 CurrentCI.Name = getCommandName(C->getCommandID()); 96 for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I) 97 CurrentCI.Args.push_back(C->getArgText(I)); 98 } 99 100 void ClangDocCommentVisitor::visitParamCommandComment( 101 const ParamCommandComment *C) { 102 CurrentCI.Direction = 103 ParamCommandComment::getDirectionAsString(C->getDirection()); 104 CurrentCI.Explicit = C->isDirectionExplicit(); 105 if (C->hasParamName()) 106 CurrentCI.ParamName = C->getParamNameAsWritten(); 107 } 108 109 void ClangDocCommentVisitor::visitTParamCommandComment( 110 const TParamCommandComment *C) { 111 if (C->hasParamName()) 112 CurrentCI.ParamName = C->getParamNameAsWritten(); 113 } 114 115 void ClangDocCommentVisitor::visitVerbatimBlockComment( 116 const VerbatimBlockComment *C) { 117 CurrentCI.Name = getCommandName(C->getCommandID()); 118 CurrentCI.CloseName = C->getCloseName(); 119 } 120 121 void ClangDocCommentVisitor::visitVerbatimBlockLineComment( 122 const VerbatimBlockLineComment *C) { 123 if (!isWhitespaceOnly(C->getText())) 124 CurrentCI.Text = C->getText(); 125 } 126 127 void ClangDocCommentVisitor::visitVerbatimLineComment( 128 const VerbatimLineComment *C) { 129 if (!isWhitespaceOnly(C->getText())) 130 CurrentCI.Text = C->getText(); 131 } 132 133 bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const { 134 return std::all_of(S.begin(), S.end(), isspace); 135 } 136 137 std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const { 138 const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); 139 if (Info) 140 return Info->Name; 141 // TODO: Add parsing for \file command. 142 return "<not a builtin command>"; 143 } 144 145 // Serializing functions. 146 147 template <typename T> static std::string serialize(T &I) { 148 SmallString<2048> Buffer; 149 llvm::BitstreamWriter Stream(Buffer); 150 ClangDocBitcodeWriter Writer(Stream); 151 Writer.emitBlock(I); 152 return Buffer.str().str(); 153 } 154 155 std::string serialize(std::unique_ptr<Info> &I) { 156 switch (I->IT) { 157 case InfoType::IT_namespace: 158 return serialize(*static_cast<NamespaceInfo *>(I.get())); 159 case InfoType::IT_record: 160 return serialize(*static_cast<RecordInfo *>(I.get())); 161 case InfoType::IT_enum: 162 return serialize(*static_cast<EnumInfo *>(I.get())); 163 case InfoType::IT_function: 164 return serialize(*static_cast<FunctionInfo *>(I.get())); 165 default: 166 return ""; 167 } 168 } 169 170 static void parseFullComment(const FullComment *C, CommentInfo &CI) { 171 ClangDocCommentVisitor Visitor(CI); 172 Visitor.parseComment(C); 173 } 174 175 static SymbolID getUSRForDecl(const Decl *D) { 176 llvm::SmallString<128> USR; 177 if (index::generateUSRForDecl(D, USR)) 178 return SymbolID(); 179 return hashUSR(USR); 180 } 181 182 static RecordDecl *getDeclForType(const QualType &T) { 183 auto *Ty = T->getAs<RecordType>(); 184 if (!Ty) 185 return nullptr; 186 return Ty->getDecl()->getDefinition(); 187 } 188 189 static bool isPublic(const clang::AccessSpecifier AS, 190 const clang::Linkage Link) { 191 if (AS == clang::AccessSpecifier::AS_private) 192 return false; 193 else if ((Link == clang::Linkage::ModuleLinkage) || 194 (Link == clang::Linkage::ExternalLinkage)) 195 return true; 196 return false; // otherwise, linkage is some form of internal linkage 197 } 198 199 static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) { 200 for (const FieldDecl *F : D->fields()) { 201 if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal())) 202 continue; 203 if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) { 204 // Use getAccessUnsafe so that we just get the default AS_none if it's not 205 // valid, as opposed to an assert. 206 if (const auto *N = dyn_cast<EnumDecl>(T)) { 207 I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(), 208 InfoType::IT_enum, F->getNameAsString(), 209 N->getAccessUnsafe()); 210 continue; 211 } else if (const auto *N = dyn_cast<RecordDecl>(T)) { 212 I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(), 213 InfoType::IT_record, F->getNameAsString(), 214 N->getAccessUnsafe()); 215 continue; 216 } 217 } 218 I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(), 219 F->getNameAsString(), F->getAccessUnsafe()); 220 } 221 } 222 223 static void parseEnumerators(EnumInfo &I, const EnumDecl *D) { 224 for (const EnumConstantDecl *E : D->enumerators()) 225 I.Members.emplace_back(E->getNameAsString()); 226 } 227 228 static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { 229 for (const ParmVarDecl *P : D->parameters()) { 230 if (const auto *T = getDeclForType(P->getOriginalType())) { 231 if (const auto *N = dyn_cast<EnumDecl>(T)) { 232 I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(), 233 InfoType::IT_enum, P->getNameAsString()); 234 continue; 235 } else if (const auto *N = dyn_cast<RecordDecl>(T)) { 236 I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(), 237 InfoType::IT_record, P->getNameAsString()); 238 continue; 239 } 240 } 241 I.Params.emplace_back(P->getOriginalType().getAsString(), 242 P->getNameAsString()); 243 } 244 } 245 246 static void parseBases(RecordInfo &I, const CXXRecordDecl *D) { 247 // Don't parse bases if this isn't a definition. 248 if (!D->isThisDeclarationADefinition()) 249 return; 250 for (const CXXBaseSpecifier &B : D->bases()) { 251 if (B.isVirtual()) 252 continue; 253 if (const auto *P = getDeclForType(B.getType())) 254 I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(), 255 InfoType::IT_record); 256 else 257 I.Parents.emplace_back(B.getType().getAsString()); 258 } 259 for (const CXXBaseSpecifier &B : D->vbases()) { 260 if (const auto *P = getDeclForType(B.getType())) 261 I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(), 262 InfoType::IT_record); 263 else 264 I.VirtualParents.emplace_back(B.getType().getAsString()); 265 } 266 } 267 268 template <typename T> 269 static void 270 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces, 271 const T *D) { 272 const auto *DC = dyn_cast<DeclContext>(D); 273 while ((DC = DC->getParent())) { 274 if (const auto *N = dyn_cast<NamespaceDecl>(DC)) 275 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 276 InfoType::IT_namespace); 277 else if (const auto *N = dyn_cast<RecordDecl>(DC)) 278 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 279 InfoType::IT_record); 280 else if (const auto *N = dyn_cast<FunctionDecl>(DC)) 281 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 282 InfoType::IT_function); 283 else if (const auto *N = dyn_cast<EnumDecl>(DC)) 284 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 285 InfoType::IT_enum); 286 } 287 } 288 289 template <typename T> 290 static void populateInfo(Info &I, const T *D, const FullComment *C) { 291 I.USR = getUSRForDecl(D); 292 I.Name = D->getNameAsString(); 293 populateParentNamespaces(I.Namespace, D); 294 if (C) { 295 I.Description.emplace_back(); 296 parseFullComment(C, I.Description.back()); 297 } 298 } 299 300 template <typename T> 301 static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, 302 int LineNumber, StringRef Filename) { 303 populateInfo(I, D, C); 304 if (D->isThisDeclarationADefinition()) 305 I.DefLoc.emplace(LineNumber, Filename); 306 else 307 I.Loc.emplace_back(LineNumber, Filename); 308 } 309 310 static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, 311 const FullComment *FC, int LineNumber, 312 StringRef Filename) { 313 populateSymbolInfo(I, D, FC, LineNumber, Filename); 314 if (const auto *T = getDeclForType(D->getReturnType())) { 315 if (dyn_cast<EnumDecl>(T)) 316 I.ReturnType = 317 TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum); 318 else if (dyn_cast<RecordDecl>(T)) 319 I.ReturnType = 320 TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record); 321 } else { 322 I.ReturnType = TypeInfo(D->getReturnType().getAsString()); 323 } 324 parseParameters(I, D); 325 } 326 327 std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC, 328 int LineNumber, llvm::StringRef File, 329 bool PublicOnly) { 330 if (PublicOnly && ((D->isAnonymousNamespace()) || 331 !isPublic(D->getAccess(), D->getLinkageInternal()))) 332 return nullptr; 333 auto I = llvm::make_unique<NamespaceInfo>(); 334 populateInfo(*I, D, FC); 335 return std::unique_ptr<Info>{std::move(I)}; 336 } 337 338 std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC, 339 int LineNumber, llvm::StringRef File, 340 bool PublicOnly) { 341 if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal())) 342 return nullptr; 343 auto I = llvm::make_unique<RecordInfo>(); 344 populateSymbolInfo(*I, D, FC, LineNumber, File); 345 I->TagType = D->getTagKind(); 346 parseFields(*I, D, PublicOnly); 347 if (const auto *C = dyn_cast<CXXRecordDecl>(D)) 348 parseBases(*I, C); 349 return std::unique_ptr<Info>{std::move(I)}; 350 } 351 352 std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC, 353 int LineNumber, llvm::StringRef File, 354 bool PublicOnly) { 355 if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal())) 356 return nullptr; 357 FunctionInfo Func; 358 populateFunctionInfo(Func, D, FC, LineNumber, File); 359 Func.Access = clang::AccessSpecifier::AS_none; 360 361 // Wrap in enclosing scope 362 auto I = llvm::make_unique<NamespaceInfo>(); 363 if (!Func.Namespace.empty()) 364 I->USR = Func.Namespace[0].USR; 365 else 366 I->USR = SymbolID(); 367 I->ChildFunctions.emplace_back(std::move(Func)); 368 return std::unique_ptr<Info>{std::move(I)}; 369 } 370 371 std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC, 372 int LineNumber, llvm::StringRef File, 373 bool PublicOnly) { 374 if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal())) 375 return nullptr; 376 FunctionInfo Func; 377 populateFunctionInfo(Func, D, FC, LineNumber, File); 378 Func.IsMethod = true; 379 380 SymbolID ParentUSR = getUSRForDecl(D->getParent()); 381 Func.Parent = Reference{ParentUSR, D->getParent()->getNameAsString(), 382 InfoType::IT_record}; 383 Func.Access = D->getAccess(); 384 385 // Wrap in enclosing scope 386 auto I = llvm::make_unique<RecordInfo>(); 387 I->USR = ParentUSR; 388 I->ChildFunctions.emplace_back(std::move(Func)); 389 return std::unique_ptr<Info>{std::move(I)}; 390 } 391 392 std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC, 393 int LineNumber, llvm::StringRef File, 394 bool PublicOnly) { 395 if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal())) 396 return nullptr; 397 EnumInfo Enum; 398 populateSymbolInfo(Enum, D, FC, LineNumber, File); 399 Enum.Scoped = D->isScoped(); 400 parseEnumerators(Enum, D); 401 402 // Wrap in enclosing scope 403 if (!Enum.Namespace.empty()) { 404 switch (Enum.Namespace[0].RefType) { 405 case InfoType::IT_namespace: { 406 auto I = llvm::make_unique<NamespaceInfo>(); 407 I->USR = Enum.Namespace[0].USR; 408 I->ChildEnums.emplace_back(std::move(Enum)); 409 return std::unique_ptr<Info>{std::move(I)}; 410 } 411 case InfoType::IT_record: { 412 auto I = llvm::make_unique<RecordInfo>(); 413 I->USR = Enum.Namespace[0].USR; 414 I->ChildEnums.emplace_back(std::move(Enum)); 415 return std::unique_ptr<Info>{std::move(I)}; 416 } 417 default: 418 break; 419 } 420 } 421 422 // Put in global namespace 423 auto I = llvm::make_unique<NamespaceInfo>(); 424 I->USR = SymbolID(); 425 I->ChildEnums.emplace_back(std::move(Enum)); 426 return std::unique_ptr<Info>{std::move(I)}; 427 } 428 429 } // namespace serialize 430 } // namespace doc 431 } // namespace clang 432