SymbolDocument[] ReadDocuments()
        {
            Debug.Assert(module != null);
            var docTbl     = pdbMetadata.TablesStream.DocumentTable;
            var docs       = new SymbolDocument[docTbl.Rows];
            var nameReader = new DocumentNameReader(pdbMetadata.BlobStream);
            var custInfos  = ListCache <PdbCustomDebugInfo> .AllocList();

            var gpContext = new GenericParamContext();

            for (int i = 0; i < docs.Length; i++)
            {
                bool b = pdbMetadata.TablesStream.TryReadDocumentRow((uint)i + 1, out var row);
                Debug.Assert(b);
                var url                 = nameReader.ReadDocumentName(row.Name);
                var language            = pdbMetadata.GuidStream.Read(row.Language) ?? Guid.Empty;
                var languageVendor      = GetLanguageVendor(language);
                var documentType        = PdbDocumentConstants.DocumentTypeText;
                var checkSumAlgorithmId = pdbMetadata.GuidStream.Read(row.HashAlgorithm) ?? Guid.Empty;
                var checkSum            = pdbMetadata.BlobStream.ReadNoNull(row.Hash);

                var token = new MDToken(Table.Document, i + 1).ToInt32();
                custInfos.Clear();
                GetCustomDebugInfos(token, gpContext, custInfos);
                var custInfosArray = custInfos.Count == 0 ? Array2.Empty <PdbCustomDebugInfo>() : custInfos.ToArray();

                docs[i] = new SymbolDocumentImpl(url, language, languageVendor, documentType, checkSumAlgorithmId, checkSum, custInfosArray);
            }
            ListCache <PdbCustomDebugInfo> .Free(ref custInfos);

            return(docs);
        }
        SymbolScopeImpl ReadScope(uint methodRid, GenericParamContext gpContext)
        {
            var             scopesRidList   = pdbMetadata.GetLocalScopeRidList(methodRid);
            SymbolScopeImpl rootScopeOrNull = null;

            if (scopesRidList.Count != 0)
            {
                var custInfos = ListCache <PdbCustomDebugInfo> .AllocList();

                var stack = ListCache <SymbolScopeImpl> .AllocList();

                var importScopeBlobReader = new ImportScopeBlobReader(module, pdbMetadata.BlobStream);
                for (int i = 0; i < scopesRidList.Count; i++)
                {
                    var  rid   = scopesRidList[i];
                    int  token = new MDToken(Table.LocalScope, rid).ToInt32();
                    bool b     = pdbMetadata.TablesStream.TryReadLocalScopeRow(rid, out var row);
                    Debug.Assert(b);
                    uint startOffset = row.StartOffset;
                    uint endOffset   = startOffset + row.Length;

                    SymbolScopeImpl parent = null;
                    while (stack.Count > 0)
                    {
                        var nextParent = stack[stack.Count - 1];
                        if (startOffset >= nextParent.StartOffset && endOffset <= nextParent.EndOffset)
                        {
                            parent = nextParent;
                            break;
                        }
                        stack.RemoveAt(stack.Count - 1);
                    }

                    Debug.Assert(parent != null || rootScopeOrNull == null);
                    custInfos.Clear();
                    GetCustomDebugInfos(token, gpContext, custInfos);
                    var customDebugInfos = custInfos.Count == 0 ? Array2.Empty <PdbCustomDebugInfo>() : custInfos.ToArray();
                    var scope            = new SymbolScopeImpl(this, parent, (int)startOffset, (int)endOffset, customDebugInfos);
                    if (rootScopeOrNull == null)
                    {
                        rootScopeOrNull = scope;
                    }
                    stack.Add(scope);
                    if (parent != null)
                    {
                        parent.childrenList.Add(scope);
                    }

                    scope.importScope = ReadPdbImportScope(ref importScopeBlobReader, row.ImportScope, gpContext);
                    GetEndOfLists(rid, out uint variableListEnd, out uint constantListEnd);
                    ReadVariables(scope, gpContext, row.VariableList, variableListEnd);
                    ReadConstants(scope, row.ConstantList, constantListEnd);
                }

                ListCache <SymbolScopeImpl> .Free(ref stack);

                ListCache <PdbCustomDebugInfo> .Free(ref custInfos);
            }
            return(rootScopeOrNull ?? new SymbolScopeImpl(this, null, 0, int.MaxValue, Array2.Empty <PdbCustomDebugInfo>()));
        }
        void ReadVariables(SymbolScopeImpl scope, GenericParamContext gpContext, uint variableList, uint variableListEnd)
        {
            if (variableList == 0)
            {
                return;
            }
            Debug.Assert(variableList <= variableListEnd);
            if (variableList >= variableListEnd)
            {
                return;
            }
            var table = pdbMetadata.TablesStream.LocalVariableTable;

            Debug.Assert(table.IsValidRID(variableListEnd - 1));
            if (!table.IsValidRID(variableListEnd - 1))
            {
                return;
            }
            Debug.Assert(table.IsValidRID(variableList));
            if (!table.IsValidRID(variableList))
            {
                return;
            }
            var custInfos = ListCache <PdbCustomDebugInfo> .AllocList();

            for (uint rid = variableList; rid < variableListEnd; rid++)
            {
                int token = new MDToken(Table.LocalVariable, rid).ToInt32();
                custInfos.Clear();
                GetCustomDebugInfos(token, gpContext, custInfos);
                var  customDebugInfos = custInfos.Count == 0 ? Array2.Empty <PdbCustomDebugInfo>() : custInfos.ToArray();
                bool b = pdbMetadata.TablesStream.TryReadLocalVariableRow(rid, out var row);
                Debug.Assert(b);
                var name = pdbMetadata.StringsStream.Read(row.Name);
                scope.localsList.Add(new SymbolVariableImpl(name, ToSymbolVariableAttributes(row.Attributes), row.Index, customDebugInfos));
            }
            ListCache <PdbCustomDebugInfo> .Free(ref custInfos);
        }
        SymbolSequencePoint[] ReadSequencePoints(uint methodRid)
        {
            if (!pdbMetadata.TablesStream.MethodDebugInformationTable.IsValidRID(methodRid))
            {
                return(null);
            }
            if (!pdbMetadata.TablesStream.TryReadMethodDebugInformationRow(methodRid, out var row))
            {
                return(null);
            }
            if (row.SequencePoints == 0)
            {
                return(null);
            }
            uint documentRid = row.Document;

            if (!pdbMetadata.BlobStream.TryCreateReader(row.SequencePoints, out var seqPointsReader))
            {
                return(null);
            }
            var seqPointsBuilder = ListCache <SymbolSequencePoint> .AllocList();

            uint localSig = seqPointsReader.ReadCompressedUInt32();

            if (documentRid == 0)
            {
                documentRid = seqPointsReader.ReadCompressedUInt32();
            }

            TryGetSymbolDocument(documentRid, out var document);

            uint ilOffset = uint.MaxValue;
            int  line = -1, column = 0;
            bool canReadDocumentRecord = false;

            while (seqPointsReader.Position < seqPointsReader.Length)
            {
                uint data = seqPointsReader.ReadCompressedUInt32();
                if (data == 0 && canReadDocumentRecord)
                {
                    // document-record

                    documentRid = seqPointsReader.ReadCompressedUInt32();
                    TryGetSymbolDocument(documentRid, out document);
                }
                else
                {
                    // SequencePointRecord

                    Debug.Assert(document != null);
                    if (document == null)
                    {
                        return(null);
                    }

                    var symSeqPoint = new SymbolSequencePoint {
                        Document = document,
                    };

                    if (ilOffset == uint.MaxValue)
                    {
                        ilOffset = data;
                    }
                    else
                    {
                        Debug.Assert(data != 0);
                        if (data == 0)
                        {
                            return(null);
                        }
                        ilOffset += data;
                    }
                    symSeqPoint.Offset = (int)ilOffset;

                    uint dlines   = seqPointsReader.ReadCompressedUInt32();
                    int  dcolumns = dlines == 0 ? (int)seqPointsReader.ReadCompressedUInt32() : seqPointsReader.ReadCompressedInt32();

                    if (dlines == 0 && dcolumns == 0)
                    {
                        // hidden-sequence-point-record

                        symSeqPoint.Line      = SequencePointConstants.HIDDEN_LINE;
                        symSeqPoint.EndLine   = SequencePointConstants.HIDDEN_LINE;
                        symSeqPoint.Column    = SequencePointConstants.HIDDEN_COLUMN;
                        symSeqPoint.EndColumn = SequencePointConstants.HIDDEN_COLUMN;
                    }
                    else
                    {
                        // sequence-point-record

                        if (line < 0)
                        {
                            line   = (int)seqPointsReader.ReadCompressedUInt32();
                            column = (int)seqPointsReader.ReadCompressedUInt32();
                        }
                        else
                        {
                            line   += seqPointsReader.ReadCompressedInt32();
                            column += seqPointsReader.ReadCompressedInt32();
                        }

                        symSeqPoint.Line      = line;
                        symSeqPoint.EndLine   = line + (int)dlines;
                        symSeqPoint.Column    = column;
                        symSeqPoint.EndColumn = column + dcolumns;
                    }

                    seqPointsBuilder.Add(symSeqPoint);
                }

                canReadDocumentRecord = true;
            }
            Debug.Assert(seqPointsReader.Position == seqPointsReader.Length);

            return(ListCache <SymbolSequencePoint> .FreeAndToArray(ref seqPointsBuilder));
        }