static Optional<DocComment *> getAnyBaseClassDocComment(swift::markup::MarkupContext &MC, const ClassDecl *CD, const Decl *D) { RawComment RC; if (const auto *VD = dyn_cast<ValueDecl>(D)) { const auto *BaseDecl = VD->getOverriddenDecl(); while (BaseDecl) { RC = BaseDecl->getRawComment(); if (!RC.isEmpty()) { swift::markup::LineList LL = MC.getLineList(RC); auto *Doc = swift::markup::parseDocument(MC, LL); auto Parts = extractCommentParts(MC, Doc); SmallString<48> RawCascadeText; llvm::raw_svector_ostream OS(RawCascadeText); OS << "This documentation comment was inherited from "; auto *Text = swift::markup::Text::create(MC, MC.allocateCopy(OS.str())); auto BaseClass = BaseDecl->getDeclContext()->getAsClassOrClassExtensionContext(); auto *BaseClassMonospace = swift::markup::Code::create(MC, MC.allocateCopy(BaseClass->getNameStr())); auto *Period = swift::markup::Text::create(MC, "."); auto *Para = swift::markup::Paragraph::create(MC, { Text, BaseClassMonospace, Period }); auto CascadeNote = swift::markup::NoteField::create(MC, {Para}); SmallVector<const swift::markup::MarkupASTNode *, 8> BodyNodes { Parts.BodyNodes.begin(), Parts.BodyNodes.end() }; BodyNodes.push_back(CascadeNote); Parts.BodyNodes = MC.allocateCopy(llvm::makeArrayRef(BodyNodes)); return new (MC) DocComment(D, Doc, Parts); } BaseDecl = BaseDecl->getOverriddenDecl(); } } return None; }
static swift::markup::CommentParts extractCommentParts(swift::markup::MarkupContext &MC, swift::markup::MarkupASTNode *Node) { swift::markup::CommentParts Parts; auto Children = Node->getChildren(); if (Children.empty()) return Parts; auto FirstParagraph = dyn_cast<swift::markup::Paragraph>(Node->getChildren().front()); if (FirstParagraph) Parts.Brief = FirstParagraph; SmallVector<const swift::markup::MarkupASTNode *, 4> BodyNodes; SmallVector<swift::markup::ParamField *, 8> ParamFields; // Look for special top-level lists size_t StartOffset = FirstParagraph == nullptr ? 0 : 1; for (auto C = Children.begin() + StartOffset; C != Children.end(); ++C) { if (auto L = dyn_cast<swift::markup::List>(*C)) { // Could be one of the following: // 1. A parameter outline: // - Parameters: // - x: ... // - y: ... // 2. An exploded parameter list: // - parameter x: ... // - parameter y: ... // 3. Some other simple field, including "returns" (see SimpleFields.def) auto ListNowEmpty = extractParameterOutline(MC, L, ParamFields); ListNowEmpty |= extractSeparatedParams(MC, L, ParamFields); ListNowEmpty |= extractSimpleField(MC, L, Parts, BodyNodes); if (ListNowEmpty) continue; // This drops the empty list from the doc comment body. } BodyNodes.push_back(*C); } // Copy BodyNodes and ParamFields into the MarkupContext. Parts.BodyNodes = MC.allocateCopy(llvm::makeArrayRef(BodyNodes)); Parts.ParamFields = MC.allocateCopy(llvm::makeArrayRef(ParamFields)); for (auto Param : Parts.ParamFields) { auto ParamParts = extractCommentParts(MC, Param); Param->setParts(ParamParts); } return Parts; }
bool extractSimpleField( swift::markup::MarkupContext &MC, swift::markup::List *L, swift::markup::CommentParts &Parts, SmallVectorImpl<const swift::markup::MarkupASTNode *> &BodyNodes) { auto Children = L->getChildren(); SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems; for (auto Child : Children) { auto I = dyn_cast<swift::markup::Item>(Child); if (!I) { NormalItems.push_back(Child); continue; } auto ItemChildren = I->getChildren(); if (ItemChildren.empty()) { NormalItems.push_back(Child); continue; } auto FirstParagraph = dyn_cast<swift::markup::Paragraph>(ItemChildren.front()); if (!FirstParagraph) { NormalItems.push_back(Child); continue; } auto ParagraphChildren = FirstParagraph->getChildren(); if (ParagraphChildren.empty()) { NormalItems.push_back(Child); continue; } auto ParagraphText = dyn_cast<swift::markup::Text>(ParagraphChildren.front()); if (!ParagraphText) { NormalItems.push_back(Child); continue; } StringRef Tag; StringRef Remainder; std::tie(Tag, Remainder) = ParagraphText->getLiteralContent().split(':'); Tag = Tag.ltrim().rtrim(); Remainder = Remainder.ltrim(); if (!swift::markup::isAFieldTag(Tag)) { NormalItems.push_back(Child); continue; } ParagraphText->setLiteralContent(Remainder); auto Field = swift::markup::createSimpleField(MC, Tag, ItemChildren); if (auto RF = dyn_cast<swift::markup::ReturnsField>(Field)) { Parts.ReturnsField = RF; } else if (auto TF = dyn_cast<swift::markup::ThrowsField>(Field)) { Parts.ThrowsField = TF; } else if (auto TF = dyn_cast<swift::markup::TagField>(Field)) { llvm::SmallString<64> Scratch; llvm::raw_svector_ostream OS(Scratch); printInlinesUnder(TF, OS); Parts.Tags.insert(MC.allocateCopy(OS.str())); } else if (auto LKF = dyn_cast<markup::LocalizationKeyField>(Field)) { Parts.LocalizationKeyField = LKF; } else { BodyNodes.push_back(Field); } } if (NormalItems.size() != Children.size()) L->setChildren(NormalItems); return NormalItems.empty(); }