/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Syntax/Diagnostics/LocationsTests.cs
607 строк
25 KB
Manish Vasani
Add a new Location.Create overload for external file location with a different mappedLineSpan (#64240)
06 окт 2022, 04:57
Не верифицирован
06 окт 2022, 04:57
80277a5
Код
Авторство
О чём код?
// 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. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class LocationsTests : TestBase { private static readonly TestSourceResolver s_resolver = new TestSourceResolver(); private class TestSourceResolver : SourceFileResolver { public TestSourceResolver() : base(ImmutableArray<string>.Empty, null) { } public override string NormalizePath(string path, string baseFilePath) { return string.Format("[{0};{1}]", path, baseFilePath); } } private void AssertMappedSpanEqual( SyntaxTree syntaxTree, string sourceText, string expectedPath, int expectedStartLine, int expectedStartOffset, int expectedEndLine, int expectedEndOffset, bool hasMappedPath) { var span = GetSpanIn(syntaxTree, sourceText); var mappedSpan = syntaxTree.GetMappedLineSpan(span); var actualDisplayPath = syntaxTree.GetDisplayPath(span, s_resolver); Assert.Equal(hasMappedPath, mappedSpan.HasMappedPath); Assert.Equal(expectedPath, mappedSpan.Path); if (expectedPath == "") { Assert.Equal("", actualDisplayPath); } else { Assert.Equal(string.Format("[{0};{1}]", expectedPath, hasMappedPath ? syntaxTree.FilePath : null), actualDisplayPath); } Assert.Equal(expectedStartLine, mappedSpan.StartLinePosition.Line); Assert.Equal(expectedStartOffset, mappedSpan.StartLinePosition.Character); Assert.Equal(expectedEndLine, mappedSpan.EndLinePosition.Line); Assert.Equal(expectedEndOffset, mappedSpan.EndLinePosition.Character); } private TextSpan GetSpanIn(SyntaxTree syntaxTree, string textToFind) { string s = syntaxTree.GetText().ToString(); int index = s.IndexOf(textToFind, StringComparison.Ordinal); Assert.True(index >= 0, "textToFind not found in the tree"); return new TextSpan(index, textToFind.Length); } private static IEnumerable<string> InspectLineMapping(SyntaxTree tree) { var text = tree.GetText(); return tree.GetLineMappings().Select(mapping => $"[|{text.GetSubText(text.Lines.GetTextSpan(mapping.Span))}|] -> {(mapping.IsHidden ? "<hidden>" : mapping.MappedSpan)}"); } [ClrOnlyFact] public void TestGetSourceLocationInFile() { string sampleProgram = @"class X { #line 20 ""d:\banana.cs"" int x; }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); TextSpan xSpan = new TextSpan(sampleProgram.IndexOf("x;", StringComparison.Ordinal), 2); TextSpan xToCloseBraceSpan = new TextSpan(xSpan.Start, sampleProgram.IndexOf('}') - xSpan.Start + 1); Location locX = new SourceLocation(syntaxTree, xSpan); Location locXToCloseBrace = new SourceLocation(syntaxTree, xToCloseBraceSpan); FileLinePositionSpan flpsX = locX.GetLineSpan(); Assert.Equal("c:\\goo.cs", flpsX.Path); Assert.Equal(2, flpsX.StartLinePosition.Line); Assert.Equal(4, flpsX.StartLinePosition.Character); Assert.Equal(2, flpsX.EndLinePosition.Line); Assert.Equal(6, flpsX.EndLinePosition.Character); flpsX = locX.GetMappedLineSpan(); Assert.Equal("d:\\banana.cs", flpsX.Path); Assert.Equal(19, flpsX.StartLinePosition.Line); Assert.Equal(4, flpsX.StartLinePosition.Character); Assert.Equal(19, flpsX.EndLinePosition.Line); Assert.Equal(6, flpsX.EndLinePosition.Character); FileLinePositionSpan flpsXToCloseBrace = locXToCloseBrace.GetLineSpan(); Assert.Equal("c:\\goo.cs", flpsXToCloseBrace.Path); Assert.Equal(2, flpsXToCloseBrace.StartLinePosition.Line); Assert.Equal(4, flpsXToCloseBrace.StartLinePosition.Character); Assert.Equal(3, flpsXToCloseBrace.EndLinePosition.Line); Assert.Equal(1, flpsXToCloseBrace.EndLinePosition.Character); flpsXToCloseBrace = locXToCloseBrace.GetMappedLineSpan(); Assert.Equal("d:\\banana.cs", flpsXToCloseBrace.Path); Assert.Equal(19, flpsXToCloseBrace.StartLinePosition.Line); Assert.Equal(4, flpsXToCloseBrace.StartLinePosition.Character); Assert.Equal(20, flpsXToCloseBrace.EndLinePosition.Line); Assert.Equal(1, flpsXToCloseBrace.EndLinePosition.Character); } [ClrOnlyFact] public void TestLineMapping1() { string sampleProgram = @"using System; class X { #line 20 ""banana.cs"" int x; int y; #line 44 int z; #line default int w; #line hidden int q; int f; #if false #line 17 ""d:\twing.cs"" #endif int a; }".NormalizeLineEndings(); SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "goo.cs"); AssertMappedSpanEqual(syntaxTree, "ing Sy", "goo.cs", 0, 2, 0, 8, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "class X", "goo.cs", 1, 0, 1, 7, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, $"System;\r\nclass X", "goo.cs", 0, 6, 1, 7, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "x;", "banana.cs", 19, 4, 19, 6, hasMappedPath: true); AssertMappedSpanEqual(syntaxTree, "y;", "banana.cs", 20, 4, 20, 6, hasMappedPath: true); AssertMappedSpanEqual(syntaxTree, "z;", "banana.cs", 43, 4, 43, 6, hasMappedPath: true); AssertMappedSpanEqual(syntaxTree, "w;", "goo.cs", 8, 4, 8, 6, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "q;\r\nin", "goo.cs", 10, 4, 11, 2, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "a;", "goo.cs", 15, 4, 15, 6, hasMappedPath: false); AssertEx.Equal(new[] { "[|using System;\r\nclass X {\r\n|] -> : (0,0)-(1,11)", "[|int x;\r\nint y;\r\n|] -> banana.cs: (19,0)-(20,8)", "[|int z;\r\n|] -> banana.cs: (43,0)-(43,8)", "[|int w;\r\n|] -> : (8,0)-(8,8)", "[|int q;\r\nint f;\r\n#if false\r\n#line 17 \"d:\\twing.cs\"\r\n#endif\r\nint a;\r\n}|] -> <hidden>" }, InspectLineMapping(syntaxTree)); } [Fact] public void TestLineMapping2() { string sampleProgram = @"using System; class X { #line 20 int x; #line hidden int y; #line 30 ""baz"" int z; #line hidden int w; #line 40 int v; }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); AssertMappedSpanEqual(syntaxTree, "int x;", "c:\\goo.cs", 19, 0, 19, 6, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "int y;", "c:\\goo.cs", 21, 0, 21, 6, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "int z;", "baz", 29, 0, 29, 6, hasMappedPath: true); AssertMappedSpanEqual(syntaxTree, "int w;", "baz", 31, 0, 31, 6, hasMappedPath: true); AssertMappedSpanEqual(syntaxTree, "int v;", "baz", 39, 0, 39, 6, hasMappedPath: true); } [Fact] public void TestLineMapping_NoSyntaxTreePath() { string sampleProgram = @"using System; #line 20 class X {} "; AssertMappedSpanEqual(SyntaxFactory.ParseSyntaxTree(sampleProgram, path: ""), "class X {}", "", 19, 0, 19, 10, hasMappedPath: false); AssertMappedSpanEqual(SyntaxFactory.ParseSyntaxTree(sampleProgram, path: " "), "class X {}", " ", 19, 0, 19, 10, hasMappedPath: false); } [Fact] public void TestInvalidLineMapping() { string sampleProgram = @"using System; class X { int q; #line 0 ""firstdirective"" int r; #line 20 ""seconddirective"" int s; }".NormalizeLineEndings(); SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "filename.cs"); AssertMappedSpanEqual(syntaxTree, "int q", "filename.cs", 2, 4, 2, 9, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "int r", "filename.cs", 4, 4, 4, 9, hasMappedPath: false); // invalid #line args AssertMappedSpanEqual(syntaxTree, "int s", "seconddirective", 19, 4, 19, 9, hasMappedPath: true); AssertEx.Equal(new[] { "[|using System;\r\nclass X {\r\n int q;\r\n|] -> : (0,0)-(2,12)", "[| int r;\r\n|] -> : (4,0)-(4,12)", "[| int s;\r\n}|] -> seconddirective: (19,0)-(20,1)" }, InspectLineMapping(syntaxTree)); } [Fact] public void TestLineMappingNoDirectives() { string sampleProgram = @"using System; class X { int x; }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); AssertMappedSpanEqual(syntaxTree, "ing Sy", "c:\\goo.cs", 0, 2, 0, 8, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "class X", "c:\\goo.cs", 1, 0, 1, 7, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, $"System;{Environment.NewLine}class X", "c:\\goo.cs", 0, 6, 1, 7, hasMappedPath: false); AssertMappedSpanEqual(syntaxTree, "x;", "c:\\goo.cs", 2, 4, 2, 6, hasMappedPath: false); Assert.Empty(InspectLineMapping(syntaxTree)); } [Fact] public void TestLineMappingFirstAndLastLineDirectives() { string sampleProgram = @"#line 20 class X {} #line 30".NormalizeLineEndings(); var syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); AssertEx.Equal(new[] { "[|class X {}\r\n|] -> : (19,0)-(19,12)", }, InspectLineMapping(syntaxTree)); } [Fact] public void TestLineMappingLastLineDirectiveFollowedByEmptyLine() { string sampleProgram = @"#line 30 ".NormalizeLineEndings(); var syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); AssertEx.Equal(new[] { "[||] -> : (29,0)-(29,0)", }, InspectLineMapping(syntaxTree)); } [Fact] public void TestLineMappingConsecutiveDirectives() { string sampleProgram = @"#line hidden #line default class C {} #line 5 #line 10 class D {} ".NormalizeLineEndings(); var syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); AssertEx.Equal(new[] { "[|class C {}\r\n|] -> : (2,0)-(2,12)", "[|class D {}\r\n|] -> : (9,0)-(10,0)", }, InspectLineMapping(syntaxTree)); } [WorkItem(537005, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537005")] [Fact] public void TestMissingTokenAtEndOfLine() { string sampleProgram = @"using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { int x } }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); // verify missing semicolon diagnostic is on the same line var diags = syntaxTree.GetDiagnostics(); Assert.Equal(1, diags.Count()); var diag = diags.First(); FileLinePositionSpan flps = diag.Location.GetLineSpan(); // verify the diagnostic is positioned at the end of the line "int x" and has zero width Assert.Equal(flps, new FileLinePositionSpan("c:\\goo.cs", new LinePosition(8, 13), new LinePosition(8, 13))); sampleProgram = @"using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { int x // dummy comment } }"; syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); diags = syntaxTree.GetDiagnostics(); diag = diags.First(); flps = diag.Location.GetLineSpan(); // verify missing semicolon diagnostic is on the same line and before the comment Assert.Equal(flps, new FileLinePositionSpan("c:\\goo.cs", new LinePosition(8, 13), new LinePosition(8, 13))); sampleProgram = @"using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { int x /* dummy multiline comment*/ } }"; syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); diags = syntaxTree.GetDiagnostics(); diag = diags.First(); flps = diag.Location.GetLineSpan(); // verify missing semicolon diagnostic is on the same line and before the comment Assert.Equal(flps, new FileLinePositionSpan("c:\\goo.cs", new LinePosition(8, 13), new LinePosition(8, 13))); } [WorkItem(537537, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537537")] [Fact] public void TestDiagnosticSpanForIdentifierExpectedError() { string sampleProgram = @"using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { string 2131; } }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); var diags = syntaxTree.GetDiagnostics(); // verify missing identifier diagnostic has the correct span Assert.NotEmpty(diags); var diag = diags.First(); FileLinePositionSpan flps = diag.Location.GetLineSpan(); // verify the diagnostic width spans the entire token "2131" Assert.Equal(flps, new FileLinePositionSpan("c:\\goo.cs", new LinePosition(8, 15), new LinePosition(8, 19))); } [WorkItem(540077, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540077")] [Fact] public void TestDiagnosticSpanForErrorAtLastToken() { string sampleProgram = @"using System; using System.Collections.Generic; using System.Linq; class C { int[] array = new int[ }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); var diags = syntaxTree.GetDiagnostics(); Assert.NotEmpty(diags); foreach (var diag in diags) { // verify the diagnostic span doesn't go past the text span Assert.InRange(diag.Location.SourceSpan.End, diag.Location.SourceSpan.Start, syntaxTree.GetText().Length); } } [WorkItem(537215, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537215")] [Fact] public void TestLineMappingForErrors() { string sampleProgram = @"class end class"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram); // The below commented lines work fine. Please uncomment once bug is fixed. // Expected(tree.GetDiagnostics()[0].Location.GetLineSpan("", false), "", 1, 4, 1, 5); // Expected(tree.GetDiagnostics()[1].Location.GetLineSpan("", false), "", 1, 4, 1, 5); // Expected(tree.GetDiagnostics()[2].Location.GetLineSpan("", false), "", 1, 9, 1, 9); // This line throws ArgumentOutOfRangeException. var span = syntaxTree.GetDiagnostics().ElementAt(3).Location.GetLineSpan(); Assert.Equal(span, new FileLinePositionSpan("", new LinePosition(1, 9), new LinePosition(1, 9))); } [Fact] public void TestEqualSourceLocations() { string sampleProgram = @"class end class"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram); SyntaxTree tree2 = SyntaxFactory.ParseSyntaxTree(sampleProgram); SourceLocation loc1 = new SourceLocation(syntaxTree, new TextSpan(3, 4)); SourceLocation loc2 = new SourceLocation(syntaxTree, new TextSpan(3, 4)); SourceLocation loc3 = new SourceLocation(syntaxTree, new TextSpan(3, 7)); SourceLocation loc4 = new SourceLocation(tree2, new TextSpan(3, 4)); Assert.Equal(loc1, loc2); Assert.Equal(loc1.GetHashCode(), loc2.GetHashCode()); Assert.NotEqual(loc1, loc3); Assert.NotEqual(loc3, loc4); } [WorkItem(541612, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541612")] [Fact] public void DiagnosticsGetLineSpanForErrorinTryCatch() { string sampleProgram = @" class Program { static void Main(string[] args) { try { } ct } }"; SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram, path: "c:\\goo.cs"); var token = syntaxTree.GetCompilationUnitRoot().FindToken(sampleProgram.IndexOf("ct", StringComparison.Ordinal)); // Get the diagnostics from the ExpressionStatement Syntax node which is the current token's Parent's Parent var expressionDiags = syntaxTree.GetDiagnostics(token.Parent.Parent); expressionDiags.First().Location.GetLineSpan(); foreach (var diag in expressionDiags) { // verify the diagnostic span doesn't go past the text span Assert.InRange(diag.Location.SourceSpan.Start, 0, syntaxTree.GetText().Length); Assert.InRange(diag.Location.SourceSpan.End, 0, syntaxTree.GetText().Length); } } [WorkItem(537926, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537926")] [ClrOnlyFact] public void TestSourceLocationToString() { string sampleProgram = @"using System; class MainClass { static void Main() { #line 200 int i; // CS0168 on line 200 #line default char c; // CS0168 on line 9 } } ".NormalizeLineEndings(); SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sampleProgram); TextSpan span1 = new TextSpan(sampleProgram.IndexOf("i;", StringComparison.Ordinal), 2); TextSpan span2 = new TextSpan(sampleProgram.IndexOf("c;", StringComparison.Ordinal), 2); SourceLocation loc1 = new SourceLocation(syntaxTree, span1); SourceLocation loc2 = new SourceLocation(syntaxTree, span2); // GetDebuggerDisplay() is private // Assert.Equal("SourceLocation(@8:13)\"i;\"", loc1.GetDebuggerDisplay()); Assert.Equal("SourceFile([91..93))", loc1.ToString()); // Assert.Equal("SourceLocation(@10:14)\"c;\"", loc2.GetDebuggerDisplay()); Assert.Equal("SourceFile([148..150))", loc2.ToString()); } [Fact] public void TestExternalLocationFormatting() { Location location = Location.Create("test.txt", new TextSpan(), new LinePositionSpan(new LinePosition(2, 1), new LinePosition(3, 1))); var diagnostic = CodeAnalysis.Diagnostic.Create("CS0000", "", "msg", DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 1, location: location); Assert.Equal("test.txt(3,2): warning CS0000: msg", CSharpDiagnosticFormatter.Instance.Format(diagnostic, EnsureEnglishUICulture.PreferredOrNull)); } [Fact, WorkItem(64236, "https://github.com/dotnet/roslyn/issues/64236")] public void TestExternalLocationWithMappedPathAndSpan() { var filePath = "test.txt"; var sourceSpan = new TextSpan(); var lineSpan = new LinePositionSpan(new LinePosition(2, 1), new LinePosition(3, 1)); var mappedFilePath = "test2.txt"; var mappedLineSpan = new LinePositionSpan(new LinePosition(3, 2), new LinePosition(4, 2)); Location locationWithoutMapping = Location.Create(filePath, sourceSpan, lineSpan); Location locationWithMapping = Location.Create(filePath, sourceSpan, lineSpan, mappedFilePath, mappedLineSpan); Assert.NotEqual(locationWithMapping, locationWithoutMapping); var diagnosticWithoutMapping = CodeAnalysis.Diagnostic.Create("CS0000", "", "msg", DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 1, location: locationWithoutMapping); Assert.Equal("test.txt(3,2): warning CS0000: msg", CSharpDiagnosticFormatter.Instance.Format(diagnosticWithoutMapping, EnsureEnglishUICulture.PreferredOrNull)); var diagnosticWithMapping = CodeAnalysis.Diagnostic.Create("CS0000", "", "msg", DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 1, location: locationWithMapping); Assert.Equal("test2.txt(4,3): warning CS0000: msg", CSharpDiagnosticFormatter.Instance.Format(diagnosticWithMapping, EnsureEnglishUICulture.PreferredOrNull)); var lineInfo = locationWithoutMapping.GetLineSpan(); Assert.Equal(filePath, lineInfo.Path); Assert.Equal(lineSpan, lineInfo.Span); Assert.False(lineInfo.HasMappedPath); var mappedLineInfo = locationWithoutMapping.GetMappedLineSpan(); Assert.Equal(filePath, mappedLineInfo.Path); Assert.Equal(lineSpan, mappedLineInfo.Span); Assert.False(mappedLineInfo.HasMappedPath); lineInfo = locationWithMapping.GetLineSpan(); Assert.Equal(filePath, lineInfo.Path); Assert.Equal(lineSpan, lineInfo.Span); Assert.False(lineInfo.HasMappedPath); mappedLineInfo = locationWithMapping.GetMappedLineSpan(); Assert.Equal(mappedFilePath, mappedLineInfo.Path); Assert.Equal(mappedLineSpan, mappedLineInfo.Span); Assert.True(mappedLineInfo.HasMappedPath); } [WorkItem(1097381, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097381")] [Fact] public void TestDiagnosticsLocationsExistInsideTreeSpan() { var node = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(SyntaxFactory.TriviaList(SyntaxFactory.Whitespace(" ")), "x", default(SyntaxTriviaList))); // create node with error that would place itself outside the tree. var nodeWithBadError = node.Green.WithDiagnosticsGreen(new DiagnosticInfo[] { new SyntaxDiagnosticInfo(10, 10, ErrorCode.ERR_NoBaseClass) }).CreateRed(); var tree = SyntaxFactory.SyntaxTree(nodeWithBadError); var treeSpan = tree.GetRoot().FullSpan; Assert.Equal(5, treeSpan.Length); var diagnostics = tree.GetDiagnostics().ToList(); Assert.Equal(1, diagnostics.Count); Assert.Equal(5, diagnostics[0].Location.SourceSpan.Start); Assert.Equal(0, diagnostics[0].Location.SourceSpan.Length); Assert.True(treeSpan.Contains(diagnostics[0].Location.SourceSpan)); var lineSpan = diagnostics[0].Location.GetLineSpan(); Assert.Equal(0, lineSpan.StartLinePosition.Line); Assert.Equal(5, lineSpan.StartLinePosition.Character); Assert.Equal(0, lineSpan.EndLinePosition.Line); Assert.Equal(5, lineSpan.EndLinePosition.Character); } [WorkItem(1097381, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097381")] [Fact] public void TestDiagnosticsLocationsExistInsideTreeSpan_ZeroWidthTree() { var node = SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken); // create node with error that would place itself outside the tree. var nodeWithBadError = SyntaxFactory.IdentifierName(new SyntaxToken(node.Node.WithDiagnosticsGreen(new DiagnosticInfo[] { new SyntaxDiagnosticInfo(10, 10, ErrorCode.ERR_NoBaseClass) }))); var tree = SyntaxFactory.SyntaxTree(nodeWithBadError); var treeSpan = tree.GetRoot().FullSpan; Assert.Equal(0, treeSpan.Length); var diagnostics = tree.GetDiagnostics().ToList(); Assert.Equal(1, diagnostics.Count); Assert.Equal(0, diagnostics[0].Location.SourceSpan.Start); Assert.Equal(0, diagnostics[0].Location.SourceSpan.Length); Assert.True(treeSpan.Contains(diagnostics[0].Location.SourceSpan)); var lineSpan = diagnostics[0].Location.GetLineSpan(); Assert.Equal(0, lineSpan.StartLinePosition.Line); Assert.Equal(0, lineSpan.StartLinePosition.Character); Assert.Equal(0, lineSpan.EndLinePosition.Line); Assert.Equal(0, lineSpan.EndLinePosition.Character); } } }