Home | History | Annotate | Line # | Download | only in AST
      1 //===--- RawCommentList.h - Classes for processing raw comments -*- 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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #ifndef LLVM_CLANG_AST_RAWCOMMENTLIST_H
     10 #define LLVM_CLANG_AST_RAWCOMMENTLIST_H
     11 
     12 #include "clang/Basic/CommentOptions.h"
     13 #include "clang/Basic/SourceLocation.h"
     14 #include "llvm/ADT/ArrayRef.h"
     15 #include "llvm/ADT/DenseMap.h"
     16 #include "llvm/Support/Allocator.h"
     17 #include <map>
     18 
     19 namespace clang {
     20 
     21 class ASTContext;
     22 class ASTReader;
     23 class Decl;
     24 class DiagnosticsEngine;
     25 class Preprocessor;
     26 class SourceManager;
     27 
     28 namespace comments {
     29   class FullComment;
     30 } // end namespace comments
     31 
     32 class RawComment {
     33 public:
     34   enum CommentKind {
     35     RCK_Invalid,      ///< Invalid comment
     36     RCK_OrdinaryBCPL, ///< Any normal BCPL comments
     37     RCK_OrdinaryC,    ///< Any normal C comment
     38     RCK_BCPLSlash,    ///< \code /// stuff \endcode
     39     RCK_BCPLExcl,     ///< \code //! stuff \endcode
     40     RCK_JavaDoc,      ///< \code /** stuff */ \endcode
     41     RCK_Qt,           ///< \code /*! stuff */ \endcode, also used by HeaderDoc
     42     RCK_Merged        ///< Two or more documentation comments merged together
     43   };
     44 
     45   RawComment() : Kind(RCK_Invalid), IsAlmostTrailingComment(false) { }
     46 
     47   RawComment(const SourceManager &SourceMgr, SourceRange SR,
     48              const CommentOptions &CommentOpts, bool Merged);
     49 
     50   CommentKind getKind() const LLVM_READONLY {
     51     return (CommentKind) Kind;
     52   }
     53 
     54   bool isInvalid() const LLVM_READONLY {
     55     return Kind == RCK_Invalid;
     56   }
     57 
     58   bool isMerged() const LLVM_READONLY {
     59     return Kind == RCK_Merged;
     60   }
     61 
     62   /// Is this comment attached to any declaration?
     63   bool isAttached() const LLVM_READONLY {
     64     return IsAttached;
     65   }
     66 
     67   void setAttached() {
     68     IsAttached = true;
     69   }
     70 
     71   /// Returns true if it is a comment that should be put after a member:
     72   /// \code ///< stuff \endcode
     73   /// \code //!< stuff \endcode
     74   /// \code /**< stuff */ \endcode
     75   /// \code /*!< stuff */ \endcode
     76   bool isTrailingComment() const LLVM_READONLY {
     77     return IsTrailingComment;
     78   }
     79 
     80   /// Returns true if it is a probable typo:
     81   /// \code //< stuff \endcode
     82   /// \code /*< stuff */ \endcode
     83   bool isAlmostTrailingComment() const LLVM_READONLY {
     84     return IsAlmostTrailingComment;
     85   }
     86 
     87   /// Returns true if this comment is not a documentation comment.
     88   bool isOrdinary() const LLVM_READONLY {
     89     return ((Kind == RCK_OrdinaryBCPL) || (Kind == RCK_OrdinaryC));
     90   }
     91 
     92   /// Returns true if this comment any kind of a documentation comment.
     93   bool isDocumentation() const LLVM_READONLY {
     94     return !isInvalid() && !isOrdinary();
     95   }
     96 
     97   /// Returns raw comment text with comment markers.
     98   StringRef getRawText(const SourceManager &SourceMgr) const {
     99     if (RawTextValid)
    100       return RawText;
    101 
    102     RawText = getRawTextSlow(SourceMgr);
    103     RawTextValid = true;
    104     return RawText;
    105   }
    106 
    107   SourceRange getSourceRange() const LLVM_READONLY { return Range; }
    108   SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); }
    109   SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); }
    110 
    111   const char *getBriefText(const ASTContext &Context) const {
    112     if (BriefTextValid)
    113       return BriefText;
    114 
    115     return extractBriefText(Context);
    116   }
    117 
    118   /// Returns sanitized comment text, suitable for presentation in editor UIs.
    119   /// E.g. will transform:
    120   ///     // This is a long multiline comment.
    121   ///     //   Parts of it  might be indented.
    122   ///     /* The comments styles might be mixed. */
    123   ///  into
    124   ///     "This is a long multiline comment.\n"
    125   ///     "  Parts of it  might be indented.\n"
    126   ///     "The comments styles might be mixed."
    127   /// Also removes leading indentation and sanitizes some common cases:
    128   ///     /* This is a first line.
    129   ///      *   This is a second line. It is indented.
    130   ///      * This is a third line. */
    131   /// and
    132   ///     /* This is a first line.
    133   ///          This is a second line. It is indented.
    134   ///     This is a third line. */
    135   /// will both turn into:
    136   ///     "This is a first line.\n"
    137   ///     "  This is a second line. It is indented.\n"
    138   ///     "This is a third line."
    139   std::string getFormattedText(const SourceManager &SourceMgr,
    140                                DiagnosticsEngine &Diags) const;
    141 
    142   /// Parse the comment, assuming it is attached to decl \c D.
    143   comments::FullComment *parse(const ASTContext &Context,
    144                                const Preprocessor *PP, const Decl *D) const;
    145 
    146 private:
    147   SourceRange Range;
    148 
    149   mutable StringRef RawText;
    150   mutable const char *BriefText;
    151 
    152   mutable bool RawTextValid : 1;   ///< True if RawText is valid
    153   mutable bool BriefTextValid : 1; ///< True if BriefText is valid
    154 
    155   unsigned Kind : 3;
    156 
    157   /// True if comment is attached to a declaration in ASTContext.
    158   bool IsAttached : 1;
    159 
    160   bool IsTrailingComment : 1;
    161   bool IsAlmostTrailingComment : 1;
    162 
    163   /// Constructor for AST deserialization.
    164   RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
    165              bool IsAlmostTrailingComment) :
    166     Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
    167     IsAttached(false), IsTrailingComment(IsTrailingComment),
    168     IsAlmostTrailingComment(IsAlmostTrailingComment)
    169   { }
    170 
    171   StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
    172 
    173   const char *extractBriefText(const ASTContext &Context) const;
    174 
    175   friend class ASTReader;
    176 };
    177 
    178 /// This class represents all comments included in the translation unit,
    179 /// sorted in order of appearance in the translation unit.
    180 class RawCommentList {
    181 public:
    182   RawCommentList(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
    183 
    184   void addComment(const RawComment &RC, const CommentOptions &CommentOpts,
    185                   llvm::BumpPtrAllocator &Allocator);
    186 
    187   /// \returns A mapping from an offset of the start of the comment to the
    188   /// comment itself, or nullptr in case there are no comments in \p File.
    189   const std::map<unsigned, RawComment *> *getCommentsInFile(FileID File) const;
    190 
    191   bool empty() const;
    192 
    193   unsigned getCommentBeginLine(RawComment *C, FileID File,
    194                                unsigned Offset) const;
    195   unsigned getCommentEndOffset(RawComment *C) const;
    196 
    197 private:
    198   SourceManager &SourceMgr;
    199   // mapping: FileId -> comment begin offset -> comment
    200   llvm::DenseMap<FileID, std::map<unsigned, RawComment *>> OrderedComments;
    201   mutable llvm::DenseMap<RawComment *, unsigned> CommentBeginLine;
    202   mutable llvm::DenseMap<RawComment *, unsigned> CommentEndOffset;
    203 
    204   friend class ASTReader;
    205   friend class ASTWriter;
    206 };
    207 
    208 } // end namespace clang
    209 
    210 #endif
    211