brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 88c7ade Raw
206 lines · c
1//===--- SymbolDocumentation.h ==---------------------------------*- C++-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Class to parse doxygen comments into a flat structure for consumption10// in e.g. Hover and Code Completion11//12//===----------------------------------------------------------------------===//13 14#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H15#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H16 17#include "support/Markup.h"18#include "clang/AST/Comment.h"19#include "clang/AST/CommentLexer.h"20#include "clang/AST/CommentParser.h"21#include "clang/AST/CommentSema.h"22#include "clang/AST/CommentVisitor.h"23#include "clang/Basic/SourceManager.h"24#include "llvm/ADT/StringRef.h"25#include "llvm/Support/raw_ostream.h"26#include <string>27 28namespace clang {29namespace clangd {30 31class SymbolDocCommentVisitor32    : public comments::ConstCommentVisitor<SymbolDocCommentVisitor> {33public:34  SymbolDocCommentVisitor(comments::FullComment *FC,35                          const CommentOptions &CommentOpts)36      : Traits(Allocator, CommentOpts), Allocator() {37    if (!FC)38      return;39 40    for (auto *Block : FC->getBlocks()) {41      visit(Block);42    }43  }44 45  SymbolDocCommentVisitor(llvm::StringRef Documentation,46                          const CommentOptions &CommentOpts)47      : Traits(Allocator, CommentOpts), Allocator() {48 49    if (Documentation.empty())50      return;51 52    CommentWithMarkers.reserve(Documentation.size() +53                               Documentation.count('\n') * 3);54 55    preprocessDocumentation(Documentation);56 57    SourceManagerForFile SourceMgrForFile("mock_file.cpp", CommentWithMarkers);58 59    SourceManager &SourceMgr = SourceMgrForFile.get();60    // The doxygen Sema requires a Diagostics consumer, since it reports61    // warnings e.g. when parameters are not documented correctly. These62    // warnings are not relevant for us, so we can ignore them.63    SourceMgr.getDiagnostics().setClient(new IgnoringDiagConsumer);64 65    comments::Sema S(Allocator, SourceMgr, SourceMgr.getDiagnostics(), Traits,66                     /*PP=*/nullptr);67    comments::Lexer L(Allocator, SourceMgr.getDiagnostics(), Traits,68                      SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()),69                      CommentWithMarkers.data(),70                      CommentWithMarkers.data() + CommentWithMarkers.size());71    comments::Parser P(L, S, Allocator, SourceMgr, SourceMgr.getDiagnostics(),72                       Traits);73    comments::FullComment *FC = P.parseFullComment();74 75    if (!FC)76      return;77 78    for (auto *Block : FC->getBlocks()) {79      visit(Block);80    }81 82    // If we have not seen a brief command, use the very first free paragraph as83    // the brief.84    if (!BriefParagraph && !FreeParagraphs.empty() &&85        FreeParagraphs.contains(0)) {86      BriefParagraph = FreeParagraphs.lookup(0);87      FreeParagraphs.erase(0);88    }89  }90 91  bool isParameterDocumented(StringRef ParamName) const {92    return Parameters.contains(ParamName);93  }94 95  bool isTemplateTypeParmDocumented(StringRef ParamName) const {96    return TemplateParameters.contains(ParamName);97  }98 99  bool hasBriefCommand() const { return BriefParagraph; }100 101  bool hasReturnCommand() const { return ReturnParagraph; }102 103  bool hasDetailedDoc() const {104    return !FreeParagraphs.empty() || !BlockCommands.empty();105  }106 107  /// Converts all unhandled comment commands to a markup document.108  void detailedDocToMarkup(markup::Document &Out) const;109  /// Converts the "brief" command(s) to a markup document.110  void briefToMarkup(markup::Paragraph &Out) const;111  /// Converts the "return" command(s) to a markup document.112  void returnToMarkup(markup::Paragraph &Out) const;113  /// Converts the "retval" command(s) to a markup document.114  void retvalsToMarkup(markup::Document &Out) const;115 116  void visitBlockCommandComment(const comments::BlockCommandComment *B);117 118  void templateTypeParmDocToMarkup(StringRef TemplateParamName,119                                   markup::Paragraph &Out) const;120 121  void templateTypeParmDocToString(StringRef TemplateParamName,122                                   llvm::raw_string_ostream &Out) const;123 124  void parameterDocToMarkup(StringRef ParamName, markup::Paragraph &Out) const;125 126  void parameterDocToString(StringRef ParamName,127                            llvm::raw_string_ostream &Out) const;128 129  void visitParagraphComment(const comments::ParagraphComment *P) {130    if (!P->isWhitespace()) {131      FreeParagraphs[CommentPartIndex] = P;132      CommentPartIndex++;133    }134  }135 136  void visitParamCommandComment(const comments::ParamCommandComment *P) {137    Parameters[P->getParamNameAsWritten()] = P;138  }139 140  void visitTParamCommandComment(const comments::TParamCommandComment *TP) {141    TemplateParameters[TP->getParamNameAsWritten()] = std::move(TP);142  }143 144  /// \brief Preprocesses the raw documentation string to prepare it for doxygen145  /// parsing.146  ///147  /// This is a workaround to provide better support for markdown in148  /// doxygen. Clang's doxygen parser e.g. does not handle markdown code blocks.149  ///150  /// The documentation string is preprocessed to replace some markdown151  /// constructs with parsable doxygen commands. E.g. markdown code blocks are152  /// replaced with doxygen \\code{.lang} ...153  /// \\endcode blocks.154  ///155  /// Additionally, potential doxygen commands inside markdown156  /// inline code spans are escaped to avoid that doxygen tries to interpret157  /// them as commands.158  ///159  /// \note Although this is a workaround, it is very similar to what160  /// doxygen itself does for markdown. In doxygen, the first parsing step is161  /// also a markdown preprocessing step.162  /// See https://www.doxygen.nl/manual/markdown.html163  void preprocessDocumentation(StringRef Doc);164 165private:166  comments::CommandTraits Traits;167  llvm::BumpPtrAllocator Allocator;168  std::string CommentWithMarkers;169 170  /// Index to keep track of the order of the comments.171  /// We want to rearange some commands like \\param.172  /// This index allows us to keep the order of the other comment parts.173  unsigned CommentPartIndex = 0;174 175  /// Paragraph of the "brief" command.176  const comments::ParagraphComment *BriefParagraph = nullptr;177 178  /// Paragraph of the "return" command.179  const comments::ParagraphComment *ReturnParagraph = nullptr;180 181  /// All the "retval" command(s)182  llvm::SmallVector<const comments::BlockCommandComment *> RetvalCommands;183 184  /// All the parsed doxygen block commands.185  /// They might have special handling internally like \\note or \\warning186  llvm::SmallDenseMap<unsigned, const comments::BlockCommandComment *>187      BlockCommands;188 189  /// Parsed paragaph(s) of the "param" comamnd(s)190  llvm::SmallDenseMap<StringRef, const comments::ParamCommandComment *>191      Parameters;192 193  /// Parsed paragaph(s) of the "tparam" comamnd(s)194  llvm::SmallDenseMap<StringRef, const comments::TParamCommandComment *>195      TemplateParameters;196 197  /// All "free" text paragraphs.198  llvm::SmallDenseMap<unsigned, const comments::ParagraphComment *>199      FreeParagraphs;200};201 202} // namespace clangd203} // namespace clang204 205#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H206