//===--- DocComment.cpp - Extraction of doc comments ----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements extraction of documentation comments from a Swift
/// Markup AST tree.
///
//===----------------------------------------------------------------------===//

#include "swift/AST/Comment.h"
#include "swift/AST/Decl.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/RawComment.h"
#include "swift/Markup/Markup.h"

using namespace swift;

void *DocComment::operator new(size_t Bytes, swift::markup::MarkupContext &MC,
                               unsigned Alignment) {
  return MC.allocate(Bytes, Alignment);
}

Optional<swift::markup::ParamField *> extractParamOutlineItem(
    swift::markup::MarkupContext &MC,
    swift::markup::MarkupASTNode *Node) {

  auto Item = dyn_cast<swift::markup::Item>(Node);
  if (!Item)
    return None;

  auto Children = Item->getChildren();
  if (Children.empty())
    return None;

  auto FirstChild = Children.front();
  auto FirstParagraph = dyn_cast<swift::markup::Paragraph>(FirstChild);
  if (!FirstParagraph)
    return None;

  auto FirstParagraphChildren = FirstParagraph->getChildren();
  if (FirstParagraphChildren.empty())
    return None;

  auto ParagraphText =
      dyn_cast<swift::markup::Text>(FirstParagraphChildren.front());
  if (!ParagraphText)
    return None;

  StringRef Name;
  StringRef Remainder;
  std::tie(Name, Remainder) = ParagraphText->getLiteralContent().split(':');
  Name = Name.rtrim();

  if (Name.empty())
    return None;

  ParagraphText->setLiteralContent(Remainder.ltrim());

  return swift::markup::ParamField::create(MC, Name, Children);
}

bool extractParameterOutline(
    swift::markup::MarkupContext &MC, swift::markup::List *L,
    SmallVectorImpl<swift::markup::ParamField *> &ParamFields) {
  SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems;
  auto Children = L->getChildren();
  if (Children.empty())
    return false;

  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 FirstChild = ItemChildren.front();
    auto FirstParagraph = dyn_cast<swift::markup::Paragraph>(FirstChild);
    if (!FirstParagraph) {
      NormalItems.push_back(Child);
      continue;
    }

    auto FirstParagraphChildren = FirstParagraph->getChildren();
    if (FirstParagraphChildren.empty()) {
      NormalItems.push_back(Child);
      continue;
    }

    auto HeadingText
        = dyn_cast<swift::markup::Text>(FirstParagraphChildren.front());
    if (!HeadingText) {
      NormalItems.push_back(Child);
      continue;
    }

    auto HeadingContent = HeadingText->getLiteralContent();
    if (!HeadingContent.rtrim().equals_lower("parameters:")) {
      NormalItems.push_back(Child);
      continue;
    }

    auto Rest = ArrayRef<swift::markup::MarkupASTNode *>(
        ItemChildren.begin() + 1, ItemChildren.end());
    if (Rest.empty()) {
      NormalItems.push_back(Child);
      continue;
    }

    for (auto Child : Rest) {
      auto SubList = dyn_cast<swift::markup::List>(Child);
      if (!SubList)
        continue;

      for (auto SubListChild : SubList->getChildren()) {
        auto Param = extractParamOutlineItem(MC, SubListChild);
        if (Param.hasValue()) {
          ParamFields.push_back(Param.getValue());
        }
      }
    }
  }

  if (NormalItems.size() != Children.size()) {
    L->setChildren(NormalItems);
  }

  return NormalItems.size() == 0;
}

bool extractSeparatedParams(
    swift::markup::MarkupContext &MC, swift::markup::List *L,
    SmallVectorImpl<swift::markup::ParamField *> &ParamFields) {
  SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems;
  auto Children = L->getChildren();

  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 FirstChild = ItemChildren.front();
    auto FirstParagraph = dyn_cast<swift::markup::Paragraph>(FirstChild);
    if (!FirstParagraph) {
      NormalItems.push_back(Child);
      continue;
    }

    auto FirstParagraphChildren = FirstParagraph->getChildren();
    if (FirstParagraphChildren.empty()) {
      NormalItems.push_back(Child);
      continue;
    }

    auto ParagraphText
        = dyn_cast<swift::markup::Text>(FirstParagraphChildren.front());
    if (!ParagraphText) {
      NormalItems.push_back(Child);
      continue;
    }

    StringRef ParameterPrefix("parameter ");
    auto ParagraphContent = ParagraphText->getLiteralContent();
    auto PotentialMatch = ParagraphContent.substr(0, ParameterPrefix.size());

    if (!PotentialMatch.startswith_lower(ParameterPrefix)) {
      NormalItems.push_back(Child);
      continue;
    }

    ParagraphContent = ParagraphContent.substr(ParameterPrefix.size());
    ParagraphText->setLiteralContent(ParagraphContent.ltrim());

    auto ParamField = extractParamOutlineItem(MC, I);
    if (ParamField.hasValue())
      ParamFields.push_back(ParamField.getValue());
    else
      NormalItems.push_back(Child);
  }

  if (NormalItems.size() != Children.size())
    L->setChildren(NormalItems);

  return NormalItems.size() == 0;
}

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
      BodyNodes.push_back(Field);
  }

  if (NormalItems.size() != Children.size())
    L->setChildren(NormalItems);

  return NormalItems.size() == 0;
}

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;
}

Optional<DocComment *>
swift::getSingleDocComment(swift::markup::MarkupContext &MC, const Decl *D) {
  PrettyStackTraceDecl StackTrace("parsing comment for", D);

  auto RC = D->getRawComment();
  if (RC.isEmpty())
    return None;

  swift::markup::LineList LL = MC.getLineList(RC);
  auto *Doc = swift::markup::parseDocument(MC, LL);
  auto Parts = extractCommentParts(MC, Doc);
  return new (MC) DocComment(D, Doc, Parts);
}

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 Optional<DocComment *>
getProtocolRequirementDocComment(swift::markup::MarkupContext &MC,
                                 const ProtocolDecl *ProtoExt,
                                 const Decl *D) {

  auto getSingleRequirementWithNonemptyDoc = [](const ProtocolDecl *P,
                                                const ValueDecl *VD)
    -> const ValueDecl * {
      SmallVector<ValueDecl *, 2> Members;
      P->lookupQualified(P->getType(), VD->getFullName(),
                         NLOptions::NL_ProtocolMembers,
                         /*resolver=*/nullptr, Members);
    SmallVector<const ValueDecl *, 1> ProtocolRequirements;
    for (auto Member : Members)
      if (!Member->isDefinition())
        ProtocolRequirements.push_back(Member);

    if (ProtocolRequirements.size() == 1) {
      auto Requirement = ProtocolRequirements.front();
      if (!Requirement->getRawComment().isEmpty())
        return Requirement;
    }

    return nullptr;
  };

  if (const auto *VD = dyn_cast<ValueDecl>(D)) {
    SmallVector<const ValueDecl *, 4> RequirementsWithDocs;
    if (auto Requirement = getSingleRequirementWithNonemptyDoc(ProtoExt, VD))
      RequirementsWithDocs.push_back(Requirement);

    for (auto Proto : ProtoExt->getInheritedProtocols(/*resolver=*/nullptr))
      if (auto Requirement = getSingleRequirementWithNonemptyDoc(Proto, VD))
        RequirementsWithDocs.push_back(Requirement);

    if (RequirementsWithDocs.size() == 1)
      return getSingleDocComment(MC, RequirementsWithDocs.front());
  }
  return None;
}

Optional<DocComment *>
swift::getCascadingDocComment(swift::markup::MarkupContext &MC, const Decl *D) {
  auto Doc = getSingleDocComment(MC, D);
  if (Doc.hasValue())
    return Doc;

  // If this refers to a class member, check to see if any
  // base classes have a doc comment and cascade it to here.
  if (const auto *CD = D->getDeclContext()->getAsClassOrClassExtensionContext())
    if (auto BaseClassDoc = getAnyBaseClassDocComment(MC, CD, D))
      return BaseClassDoc;

  if (const auto *PE = D->getDeclContext()->getAsProtocolExtensionContext())
    if (auto ReqDoc = getProtocolRequirementDocComment(MC, PE, D))
      return ReqDoc;

  return None;
}
