1 //===--  BitcodeWriter.h - ClangDoc Bitcode Writer --------------*- 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 // This file implements a writer for serializing the clang-doc internal
10 // representation to LLVM bitcode. The writer takes in a stream and emits the
11 // generated bitcode to that stream.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
16 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
17 
18 #include "Representation.h"
19 #include "clang/AST/AST.h"
20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Bitstream/BitstreamWriter.h"
24 #include <initializer_list>
25 #include <vector>
26 
27 namespace clang {
28 namespace doc {
29 
30 // Current version number of clang-doc bitcode.
31 // Should be bumped when removing or changing BlockIds, RecordIds, or
32 // BitCodeConstants, though they can be added without breaking it.
33 static const unsigned VersionNumber = 3;
34 
35 struct BitCodeConstants {
36   static constexpr unsigned RecordSize = 32U;
37   static constexpr unsigned SignatureBitSize = 8U;
38   static constexpr unsigned SubblockIDSize = 4U;
39   static constexpr unsigned BoolSize = 1U;
40   static constexpr unsigned IntSize = 16U;
41   static constexpr unsigned StringLengthSize = 16U;
42   static constexpr unsigned FilenameLengthSize = 16U;
43   static constexpr unsigned LineNumberSize = 32U;
44   static constexpr unsigned ReferenceTypeSize = 8U;
45   static constexpr unsigned USRLengthSize = 6U;
46   static constexpr unsigned USRBitLengthSize = 8U;
47   static constexpr unsigned char Signature[4] = {'D', 'O', 'C', 'S'};
48   static constexpr int USRHashSize = 20;
49 };
50 
51 // New Ids need to be added to both the enum here and the relevant IdNameMap in
52 // the implementation file.
53 enum BlockId {
54   BI_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
55   BI_NAMESPACE_BLOCK_ID,
56   BI_ENUM_BLOCK_ID,
57   BI_TYPE_BLOCK_ID,
58   BI_FIELD_TYPE_BLOCK_ID,
59   BI_MEMBER_TYPE_BLOCK_ID,
60   BI_RECORD_BLOCK_ID,
61   BI_BASE_RECORD_BLOCK_ID,
62   BI_FUNCTION_BLOCK_ID,
63   BI_COMMENT_BLOCK_ID,
64   BI_REFERENCE_BLOCK_ID,
65   BI_LAST,
66   BI_FIRST = BI_VERSION_BLOCK_ID
67 };
68 
69 // New Ids need to be added to the enum here, and to the relevant IdNameMap and
70 // initialization list in the implementation file.
71 enum RecordId {
72   VERSION = 1,
73   FUNCTION_USR,
74   FUNCTION_NAME,
75   FUNCTION_DEFLOCATION,
76   FUNCTION_LOCATION,
77   FUNCTION_ACCESS,
78   FUNCTION_IS_METHOD,
79   COMMENT_KIND,
80   COMMENT_TEXT,
81   COMMENT_NAME,
82   COMMENT_DIRECTION,
83   COMMENT_PARAMNAME,
84   COMMENT_CLOSENAME,
85   COMMENT_SELFCLOSING,
86   COMMENT_EXPLICIT,
87   COMMENT_ATTRKEY,
88   COMMENT_ATTRVAL,
89   COMMENT_ARG,
90   FIELD_TYPE_NAME,
91   MEMBER_TYPE_NAME,
92   MEMBER_TYPE_ACCESS,
93   NAMESPACE_USR,
94   NAMESPACE_NAME,
95   NAMESPACE_PATH,
96   ENUM_USR,
97   ENUM_NAME,
98   ENUM_DEFLOCATION,
99   ENUM_LOCATION,
100   ENUM_MEMBER,
101   ENUM_SCOPED,
102   RECORD_USR,
103   RECORD_NAME,
104   RECORD_PATH,
105   RECORD_DEFLOCATION,
106   RECORD_LOCATION,
107   RECORD_TAG_TYPE,
108   RECORD_IS_TYPE_DEF,
109   BASE_RECORD_USR,
110   BASE_RECORD_NAME,
111   BASE_RECORD_PATH,
112   BASE_RECORD_TAG_TYPE,
113   BASE_RECORD_IS_VIRTUAL,
114   BASE_RECORD_ACCESS,
115   BASE_RECORD_IS_PARENT,
116   REFERENCE_USR,
117   REFERENCE_NAME,
118   REFERENCE_TYPE,
119   REFERENCE_PATH,
120   REFERENCE_IS_IN_GLOBAL_NAMESPACE,
121   REFERENCE_FIELD,
122   RI_LAST,
123   RI_FIRST = VERSION
124 };
125 
126 static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST;
127 static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST;
128 
129 // Identifiers for differentiating between subblocks
130 enum class FieldId {
131   F_default,
132   F_namespace,
133   F_parent,
134   F_vparent,
135   F_type,
136   F_child_namespace,
137   F_child_record
138 };
139 
140 class ClangDocBitcodeWriter {
141 public:
ClangDocBitcodeWriter(llvm::BitstreamWriter & Stream)142   ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) {
143     emitHeader();
144     emitBlockInfoBlock();
145     emitVersionBlock();
146   }
147 
148   // Write a specific info to a bitcode stream.
149   bool dispatchInfoForWrite(Info *I);
150 
151   // Block emission of different info types.
152   void emitBlock(const NamespaceInfo &I);
153   void emitBlock(const RecordInfo &I);
154   void emitBlock(const BaseRecordInfo &I);
155   void emitBlock(const FunctionInfo &I);
156   void emitBlock(const EnumInfo &I);
157   void emitBlock(const TypeInfo &B);
158   void emitBlock(const FieldTypeInfo &B);
159   void emitBlock(const MemberTypeInfo &B);
160   void emitBlock(const CommentInfo &B);
161   void emitBlock(const Reference &B, FieldId F);
162 
163 private:
164   class AbbreviationMap {
165     llvm::DenseMap<unsigned, unsigned> Abbrevs;
166 
167   public:
AbbreviationMap()168     AbbreviationMap() : Abbrevs(RecordIdCount) {}
169 
170     void add(RecordId RID, unsigned AbbrevID);
171     unsigned get(RecordId RID) const;
172   };
173 
174   class StreamSubBlockGuard {
175     llvm::BitstreamWriter &Stream;
176 
177   public:
StreamSubBlockGuard(llvm::BitstreamWriter & Stream_,BlockId ID)178     StreamSubBlockGuard(llvm::BitstreamWriter &Stream_, BlockId ID)
179         : Stream(Stream_) {
180       // NOTE: SubBlockIDSize could theoretically be calculated on the fly,
181       // based on the initialization list of records in each block.
182       Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize);
183     }
184 
185     StreamSubBlockGuard(const StreamSubBlockGuard &) = delete;
186     StreamSubBlockGuard &operator=(const StreamSubBlockGuard &) = delete;
187 
~StreamSubBlockGuard()188     ~StreamSubBlockGuard() { Stream.ExitBlock(); }
189   };
190 
191   // Emission of validation and overview blocks.
192   void emitHeader();
193   void emitVersionBlock();
194   void emitRecordID(RecordId ID);
195   void emitBlockID(BlockId ID);
196   void emitBlockInfoBlock();
197   void emitBlockInfo(BlockId BID, const std::vector<RecordId> &RIDs);
198 
199   // Emission of individual record types.
200   void emitRecord(StringRef Str, RecordId ID);
201   void emitRecord(const SymbolID &Str, RecordId ID);
202   void emitRecord(const Location &Loc, RecordId ID);
203   void emitRecord(const Reference &Ref, RecordId ID);
204   void emitRecord(bool Value, RecordId ID);
205   void emitRecord(int Value, RecordId ID);
206   void emitRecord(unsigned Value, RecordId ID);
207   bool prepRecordData(RecordId ID, bool ShouldEmit = true);
208 
209   // Emission of appropriate abbreviation type.
210   void emitAbbrev(RecordId ID, BlockId Block);
211 
212   // Static size is the maximum length of the block/record names we're pushing
213   // to this + 1. Longest is currently `MemberTypeBlock` at 15 chars.
214   SmallVector<uint32_t, BitCodeConstants::RecordSize> Record;
215   llvm::BitstreamWriter &Stream;
216   AbbreviationMap Abbrevs;
217 };
218 
219 } // namespace doc
220 } // namespace clang
221 
222 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
223