| File: CommandLine\CommandLineDiagnosticFormatter.vb | Web Access |
| Project: src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic) |
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports System.Text Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic Friend NotInheritable Class CommandLineDiagnosticFormatter Inherits VisualBasicDiagnosticFormatter Private ReadOnly _baseDirectory As String Private ReadOnly _getAdditionalTextFiles As Func(Of ImmutableArray(Of AdditionalTextFile)) Friend Sub New(baseDirectory As String, getAdditionalTextFiles As Func(Of ImmutableArray(Of AdditionalTextFile))) _baseDirectory = baseDirectory _getAdditionalTextFiles = getAdditionalTextFiles End Sub ' Returns a diagnostic message in string. ' VB has a special implementation that prints out a squiggle under the error span as well as a diagnostic message. ' e.g., ' c:\Roslyn\Temp\a.vb(5) : warning BC42024: Unused local variable: 'x'. ' ' Dim x As Integer ' ~ ' Public Overrides Function Format(diagnostic As Diagnostic, Optional formatter As IFormatProvider = Nothing) As String ' Builds a diagnostic message ' Dev12 vbc prints raw paths -- relative and not normalized, so we don't need to customize the base implementation. Dim text As SourceText = Nothing Dim diagnosticSpanOpt = GetDiagnosticSpanAndFileText(diagnostic, text) If Not diagnosticSpanOpt.HasValue OrElse text Is Nothing OrElse text.Length < diagnosticSpanOpt.Value.End Then ' Diagnostic either has Location.None OR an invalid location OR invalid file contents. ' For all these cases, format the diagnostic as a no-location project level diagnostic. ' Strip location, if required. If diagnostic.Location <> Location.None Then diagnostic = diagnostic.WithLocation(Location.None) End If ' Add "vbc : " command line prefix to the start of the command line diagnostics which do not have a location to match the ' behavior of native compiler. This allows MSBuild output to be consistent whether Roslyn is installed or not. Return VisualBasicCompiler.VbcCommandLinePrefix & MyBase.Format(diagnostic, formatter) End If Dim baseMessage = MyBase.Format(diagnostic, formatter) Dim sb As New StringBuilder() sb.AppendLine(baseMessage) ' the squiggles are displayed for the original (unmapped) location Dim sourceSpan = diagnosticSpanOpt.Value Dim sourceSpanStart = sourceSpan.Start Dim sourceSpanEnd = sourceSpan.End Dim linenumber = text.Lines.IndexOf(sourceSpanStart) Dim line = text.Lines(linenumber) If sourceSpan.IsEmpty AndAlso line.Start = sourceSpanEnd AndAlso linenumber > 0 Then ' Sometimes there is something missing at the end of the line, then the error is reported with an empty span ' beyond the end of the line, which makes it appear that the span starts at the beginning of the next line. ' Let's go back to the previous line in this case. linenumber -= 1 line = text.Lines(linenumber) End If While (line.Start < sourceSpanEnd) ' Builds the original text line sb.AppendLine() sb.AppendLine(line.ToString().Replace(vbTab, " ")) ' normalize tabs with 4 spaces ' Builds leading spaces up to the error span For position = Math.Min(sourceSpanStart, line.Start) To Math.Min(line.End, sourceSpanStart) - 1 If (text(position) = vbTab) Then ' normalize tabs with 4 spaces sb.Append(" "c, 4) Else sb.Append(" ") End If Next ' Builds squiggles If sourceSpan.IsEmpty Then sb.Append("~") Else For position = Math.Max(sourceSpanStart, line.Start) To Math.Min(If(sourceSpanEnd = sourceSpanStart, sourceSpanEnd, sourceSpanEnd - 1), line.End - 1) If (text(position) = vbTab) Then ' normalize tabs with 4 spaces sb.Append("~"c, 4) Else sb.Append("~") End If Next End If ' Builds trailing spaces up to the end of this line For position = Math.Min(sourceSpanEnd, line.End) To line.End - 1 If (text(position) = vbTab) Then ' normalize tabs with 4 spaces sb.Append(" "c, 4) Else sb.Append(" ") End If Next ' The error span can continue over multiple lines linenumber = linenumber + 1 If linenumber >= text.Lines.Count Then ' Exit the loop when we reach the end line (0-based) Exit While End If line = text.Lines(linenumber) End While Return sb.ToString() End Function Friend Overrides Function FormatSourcePath(path As String, basePath As String, formatter As IFormatProvider) As String Return If(FileUtilities.NormalizeRelativePath(path, basePath, _baseDirectory), path) End Function Private Function GetDiagnosticSpanAndFileText(diagnostic As Diagnostic, <Out> ByRef text As SourceText) As TextSpan? If diagnostic.Location.IsInSource Then text = diagnostic.Location.SourceTree.GetText() Return diagnostic.Location.SourceSpan End If If diagnostic.Location.Kind = LocationKind.ExternalFile Then Dim path = diagnostic.Location.GetLineSpan().Path If path IsNot Nothing Then For Each additionalTextFile In _getAdditionalTextFiles() If path.Equals(additionalTextFile.Path) Then Try text = additionalTextFile.GetText() Catch text = Nothing End Try Return diagnostic.Location.SourceSpan End If Next End If End If text = Nothing Return Nothing End Function End Class End Namespace