/// <summary> /// Get all the sequence points, possibly mapping them using #line/ExternalSource directives, and mapping /// file names to debug documents with the given mapping function. /// </summary> /// <param name="documentProvider">Function that maps file paths to CCI debug documents</param> /// <param name="builder">where sequence points should be deposited</param> public void GetSequencePoints( DebugDocumentProvider documentProvider, ArrayBuilder <Cci.SequencePoint> builder) { bool lastPathIsMapped = false; string lastPath = null; Cci.DebugSourceDocument lastDebugDocument = null; FileLinePositionSpan?firstReal = FindFirstRealSequencePoint(); if (!firstReal.HasValue) { return; } lastPath = firstReal.Value.Path; lastPathIsMapped = firstReal.Value.HasMappedPath; lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? this._tree.FilePath : null); SequencePointList current = this; while (current != null) { SyntaxTree currentTree = current._tree; foreach (var offsetAndSpan in current._points) { TextSpan span = offsetAndSpan.Span; // if it's a hidden sequence point, or a sequence point with syntax that points to a position that is inside // of a hidden region (can be defined with #line hidden (C#) or implicitly by #ExternalSource (VB), make it // a hidden sequence point. bool isHidden = span == RawSequencePoint.HiddenSequencePointSpan; FileLinePositionSpan fileLinePositionSpan = default; if (!isHidden) { fileLinePositionSpan = currentTree.GetMappedLineSpanAndVisibility(span, out isHidden); } if (isHidden) { if (lastPath == null) { lastPath = currentTree.FilePath; lastDebugDocument = documentProvider(lastPath, basePath: null); } if (lastDebugDocument != null) { builder.Add(new Cci.SequencePoint( lastDebugDocument, offset: offsetAndSpan.Offset, startLine: Cci.SequencePoint.HiddenLine, startColumn: 0, endLine: Cci.SequencePoint.HiddenLine, endColumn: 0)); } } else { if (lastPath != fileLinePositionSpan.Path || lastPathIsMapped != fileLinePositionSpan.HasMappedPath) { lastPath = fileLinePositionSpan.Path; lastPathIsMapped = fileLinePositionSpan.HasMappedPath; lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? currentTree.FilePath : null); } if (lastDebugDocument != null) { int startLine = (fileLinePositionSpan.StartLinePosition.Line == -1) ? 0 : fileLinePositionSpan.StartLinePosition.Line + 1; int endLine = (fileLinePositionSpan.EndLinePosition.Line == -1) ? 0 : fileLinePositionSpan.EndLinePosition.Line + 1; int startColumn = fileLinePositionSpan.StartLinePosition.Character + 1; int endColumn = fileLinePositionSpan.EndLinePosition.Character + 1; // Trim column number if necessary. // Column must be in range [0, 0xffff) and end column must be greater than start column if on the same line. // The Portable PDB specifies 0x10000, but StarkPlatform.Reflection.Metadata reader has an off-by-one error. // Windows PDBs allow the same range. const int MaxColumn = ushort.MaxValue - 1; if (startColumn > MaxColumn) { startColumn = (startLine == endLine) ? MaxColumn - 1 : MaxColumn; } if (endColumn > MaxColumn) { endColumn = MaxColumn; } builder.Add(new Cci.SequencePoint( lastDebugDocument, offset: offsetAndSpan.Offset, startLine: startLine, startColumn: (ushort)startColumn, endLine: endLine, endColumn: (ushort)endColumn )); } } } current = current._next; } }
internal int GetOrAddDocument(DebugSourceDocument document) { return(GetOrAddDocument(document, _documentIndex)); }