Exemplo n.º 1
0
        public GotoDefinitionResponse GetGotoDefinitionResponse(GotoDefinitionRequest request)
        {
            var res = _bufferParser.ParsedContent(request.Buffer, request.FileName);
            
            var loc = new TextLocation(request.Line, request.Column);

            ResolveResult resolveResult = ResolveAtLocation.Resolve(res.Compilation, res.UnresolvedFile, res.SyntaxTree, loc);
            var response = new GotoDefinitionResponse();
            if (resolveResult != null)
            {
                var region = resolveResult.GetDefinitionRegion();
                response.FileName = region.FileName == null ? null : region.FileName.LowerCaseDriveLetter().ApplyPathReplacementsForClient();
                response.Line = region.BeginLine;
                response.Column = region.BeginColumn;
            }

            return response;
        }
        public async Task ReturnsDefinitionInMetadata_FromMetadata_WhenSymbolIsType(string filename)
        {
            var testFile = new TestFile(filename, @"
using System;
class Bar {
    public void Baz() {
        var number = in$$t.MaxValue;
    }
}");

            using (var host = CreateOmniSharpHost(testFile))
            {
                var point = testFile.Content.GetPointFromPosition();

                // 1. start by asking for definition of "int"
                var gotoDefinitionRequest = new GotoDefinitionRequest
                {
                    FileName     = testFile.FileName,
                    Line         = point.Line,
                    Column       = point.Offset,
                    WantMetadata = true,
                    Timeout      = 60000
                };
                var gotoDefinitionRequestHandler = GetRequestHandler(host);
                var gotoDefinitionResponse       = await gotoDefinitionRequestHandler.Handle(gotoDefinitionRequest);

                // 2. now, based on the response information
                // go to the metadata endpoint, and ask for "int" specific metadata
                var metadataRequest = new MetadataRequest
                {
                    AssemblyName = gotoDefinitionResponse.MetadataSource.AssemblyName,
                    TypeName     = gotoDefinitionResponse.MetadataSource.TypeName,
                    ProjectName  = gotoDefinitionResponse.MetadataSource.ProjectName,
                    Language     = gotoDefinitionResponse.MetadataSource.Language
                };
                var metadataRequestHandler = host.GetRequestHandler <MetadataService>(OmniSharpEndpoints.Metadata);
                var metadataResponse       = await metadataRequestHandler.Handle(metadataRequest);

                // 3. the metadata response contains SourceName (metadata "file") and SourceText (syntax tree)
                // use the source to locate "IComparable" which is an interface implemented by Int32 struct
                var metadataTree = CSharpSyntaxTree.ParseText(metadataResponse.Source);

                var iComparable = metadataTree.GetCompilationUnitRoot().
                                  DescendantNodesAndSelf().
                                  OfType <BaseTypeDeclarationSyntax>().First().
                                  BaseList.Types.FirstOrDefault(x => x.Type.ToString() == "IComparable");
                var relevantLineSpan = iComparable.GetLocation().GetLineSpan();

                // 4. now ask for the definition of "IComparable"
                // pass in the SourceName (metadata "file") as FileName - since it's not a regular file in our workspace
                var metadataNavigationRequest = new GotoDefinitionRequest
                {
                    FileName     = metadataResponse.SourceName,
                    Line         = relevantLineSpan.StartLinePosition.Line,
                    Column       = relevantLineSpan.StartLinePosition.Character,
                    WantMetadata = true
                };
                var metadataNavigationResponse = await gotoDefinitionRequestHandler.Handle(metadataNavigationRequest);

                // 5. validate the response to be matching the expected IComparable meta info
                Assert.NotNull(metadataNavigationResponse.MetadataSource);
                Assert.Equal(AssemblyHelpers.CorLibName, metadataNavigationResponse.MetadataSource.AssemblyName);
                Assert.Equal("System.IComparable", metadataNavigationResponse.MetadataSource.TypeName);

                Assert.NotEqual(0, metadataNavigationResponse.Line);
                Assert.NotEqual(0, metadataNavigationResponse.Column);
            }
        }
        public async Task ReturnsDecompiledDefinition_FromMetadata_WhenSymbolIsType(string filename)
        {
            var testFile = new TestFile(filename, @"
using System;
class Bar {
    public void Baz() {
        var number = in$$t.MaxValue;
    }
}");

            using var host = CreateOmniSharpHost(new[] { testFile }, new Dictionary <string, string>
            {
                ["RoslynExtensionsOptions:EnableDecompilationSupport"] = "true"
            });

            var point = testFile.Content.GetPointFromPosition();

            // 1. start by asking for definition of "int"
            var gotoDefinitionRequest = new GotoDefinitionRequest
            {
                FileName     = testFile.FileName,
                Line         = point.Line,
                Column       = point.Offset,
                WantMetadata = true,
                Timeout      = 60000
            };
            var gotoDefinitionRequestHandler = GetRequestHandler(host);
            var gotoDefinitionResponse       = await gotoDefinitionRequestHandler.Handle(gotoDefinitionRequest);

            // 2. now, based on the response information
            // go to the metadata endpoint, and ask for "int" specific decompiled source
            var metadataRequest = new MetadataRequest
            {
                AssemblyName = gotoDefinitionResponse.MetadataSource.AssemblyName,
                TypeName     = gotoDefinitionResponse.MetadataSource.TypeName,
                ProjectName  = gotoDefinitionResponse.MetadataSource.ProjectName,
                Language     = gotoDefinitionResponse.MetadataSource.Language,
                Timeout      = 60000
            };
            var metadataRequestHandler = host.GetRequestHandler <MetadataService>(OmniSharpEndpoints.Metadata);
            var metadataResponse       = await metadataRequestHandler.Handle(metadataRequest);

            // 3. the response contains SourceName ("file") and SourceText (syntax tree)
            // use the source to locate "IComparable" which is an interface implemented by Int32 struct
            var decompiledTree  = CSharpSyntaxTree.ParseText(metadataResponse.Source);
            var compilationUnit = decompiledTree.GetCompilationUnitRoot();

            // second comment should indicate we have decompiled
            var comments = compilationUnit.DescendantTrivia().Where(t => t.Kind() == SyntaxKind.SingleLineCommentTrivia).ToArray();

            Assert.NotNull(comments);
            Assert.Equal("// Decompiled with ICSharpCode.Decompiler 5.0.2.5153", comments[1].ToString());

            // contrary to regular metadata, we should have methods with full bodies
            // this condition would fail if decompilation wouldn't work
            var methods = compilationUnit.
                          DescendantNodesAndSelf().
                          OfType <MethodDeclarationSyntax>().
                          Where(m => m.Body != null);

            Assert.NotEmpty(methods);

            var iComparable = compilationUnit.
                              DescendantNodesAndSelf().
                              OfType <BaseTypeDeclarationSyntax>().First().
                              BaseList.Types.FirstOrDefault(x => x.Type.ToString() == "IComparable");
            var relevantLineSpan = iComparable.GetLocation().GetLineSpan();

            // 4. now ask for the definition of "IComparable"
            // pass in the SourceName (metadata "file") as FileName - since it's not a regular file in our workspace
            var metadataNavigationRequest = new GotoDefinitionRequest
            {
                FileName     = metadataResponse.SourceName,
                Line         = relevantLineSpan.StartLinePosition.Line,
                Column       = relevantLineSpan.StartLinePosition.Character,
                WantMetadata = true
            };
            var metadataNavigationResponse = await gotoDefinitionRequestHandler.Handle(metadataNavigationRequest);

            // 5. validate the response to be matching the expected IComparable meta info
            Assert.NotNull(metadataNavigationResponse.MetadataSource);
            Assert.Equal(AssemblyHelpers.CorLibName, metadataNavigationResponse.MetadataSource.AssemblyName);
            Assert.Equal("System.IComparable", metadataNavigationResponse.MetadataSource.TypeName);

            Assert.NotEqual(0, metadataNavigationResponse.Line);
            Assert.NotEqual(0, metadataNavigationResponse.Column);
        }
        public async Task UpdateReturnsChanges()
        {
            const string Code      = @"
_ = GeneratedCode.$$S;
_ = ""Hello world!""";
            const string Path      = @"Test.cs";
            var          reference = new TestGeneratorReference(context =>
            {
                // NOTE: Don't actually do this in a real generator. This is just for test
                // code. Do not use this as an example of what to do in production.

                var syntax = context.Compilation.SyntaxTrees.Single().GetRoot().DescendantNodes().OfType <LiteralExpressionSyntax>().SingleOrDefault();
                if (syntax != null)
                {
                    context.AddSource("GeneratedSource", @"
class GeneratedCode
{
    public static string S = " + syntax.ToString() + @";
}");
                }
            });

            TestFile testFile = new TestFile(Path, Code);

            TestHelpers.AddProjectToWorkspace(SharedOmniSharpTestHost.Workspace,
                                              "project.csproj",
                                              new[] { "netcoreapp3.1" },
                                              new[] { testFile },
                                              ImmutableArray.Create <AnalyzerReference>(reference));

            var point = testFile.Content.GetPointFromPosition();

            var gotoDefRequest = new GotoDefinitionRequest {
                FileName = Path, Line = point.Line, Column = point.Offset
            };
            var gotoDefResponse = (await SharedOmniSharpTestHost
                                   .GetRequestHandler <GotoDefinitionServiceV2>(OmniSharpEndpoints.V2.GotoDefinition)
                                   .Handle(gotoDefRequest)).Definitions.Single();

            var initialContent = await SharedOmniSharpTestHost
                                 .GetRequestHandler <SourceGeneratedFileService>(OmniSharpEndpoints.SourceGeneratedFile)
                                 .Handle(new SourceGeneratedFileRequest()
            {
                ProjectGuid  = gotoDefResponse.SourceGeneratedFileInfo.ProjectGuid,
                DocumentGuid = gotoDefResponse.SourceGeneratedFileInfo.DocumentGuid
            });

            Assert.Contains("Hello world!", initialContent.Source);

            var updateRequest = new UpdateSourceGeneratedFileRequest
            {
                DocumentGuid = gotoDefResponse.SourceGeneratedFileInfo.DocumentGuid,
                ProjectGuid  = gotoDefResponse.SourceGeneratedFileInfo.ProjectGuid
            };
            var updateHandler   = SharedOmniSharpTestHost.GetRequestHandler <SourceGeneratedFileService>(OmniSharpEndpoints.UpdateSourceGeneratedFile);
            var updatedResponse = await updateHandler.Handle(updateRequest);

            Assert.Null(updatedResponse.Source);
            Assert.Equal(UpdateType.Unchanged, updatedResponse.UpdateType);

            var updateBufferHandler = SharedOmniSharpTestHost.GetRequestHandler <UpdateBufferService>(OmniSharpEndpoints.UpdateBuffer);

            _ = await updateBufferHandler.Handle(new()
            {
                FileName = Path,
                Buffer   = Code.Replace("Hello world!", "Goodbye!")
            });

            updatedResponse = await updateHandler.Handle(updateRequest);

            Assert.Equal(UpdateType.Modified, updatedResponse.UpdateType);
            Assert.Contains("Goodbye!", updatedResponse.Source);
            Assert.DoesNotContain("Hello world!", updatedResponse.Source);

            _ = await updateBufferHandler.Handle(new()
            {
                FileName = Path,
                Buffer   = @"_ = GeneratedCode.S;"
            });

            updatedResponse = await updateHandler.Handle(updateRequest);

            Assert.Equal(UpdateType.Deleted, updatedResponse.UpdateType);
            Assert.Null(updatedResponse.Source);
        }