Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add V2 version of GotoDefinitionService #2168

Merged
merged 7 commits into from May 31, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -6,5 +6,16 @@ namespace OmniSharp.Models.V2.CodeActions
public class GetCodeActionsRequest : Request, ICodeActionRequest
{
public Range Selection { get; set; }

public ICodeActionRequest WithSelection(Range newSelection) => new GetCodeActionsRequest
{
Line = this.Line,
Column = this.Column,
Buffer = this.Buffer,
ApplyChangesTogether = this.ApplyChangesTogether,
Changes = this.Changes,
FileName = this.FileName,
Selection = newSelection
};
}
}
Expand Up @@ -11,5 +11,7 @@ public interface ICodeActionRequest
string Buffer { get; }
string FileName { get; }
Range Selection { get; }

ICodeActionRequest WithSelection(Range newSelection);
}
}
Expand Up @@ -10,5 +10,20 @@ public class RunCodeActionRequest : Request, ICodeActionRequest
public bool WantsTextChanges { get; set; }
public bool ApplyTextChanges { get; set; } = true;
public bool WantsAllCodeActionOperations { get; set; }

public ICodeActionRequest WithSelection(Range newSelection) => new RunCodeActionRequest
{
Line = this.Line,
Column = this.Column,
Buffer = this.Buffer,
ApplyChangesTogether = this.ApplyChangesTogether,
Changes = this.Changes,
FileName = this.FileName,
Identifier = this.Identifier,
WantsTextChanges = this.WantsTextChanges,
ApplyTextChanges = this.ApplyTextChanges,
WantsAllCodeActionOperations = this.WantsAllCodeActionOperations,
Selection = newSelection
};
}
}
@@ -0,0 +1,11 @@
using OmniSharp.Mef;

namespace OmniSharp.Models.V2.GotoDefinition
{
[OmniSharpEndpoint(OmniSharpEndpoints.V2.GotoDefinition, typeof(GotoDefinitionRequest), typeof(GotoDefinitionResponse))]
public class GotoDefinitionRequest : Request
{
public int Timeout { get; init; } = 10000;
public bool WantMetadata { get; init; }
}
}
@@ -0,0 +1,18 @@
#nullable enable

using OmniSharp.Models.Metadata;
using System.Collections.Generic;

namespace OmniSharp.Models.V2.GotoDefinition
{
public record GotoDefinitionResponse
{
public List<Definition>? Definitions { get; init; }
}

public record Definition
{
public Location Location { get; init; } = null!;
public MetadataSource? MetadataSource { get; init; }
}
}
10 changes: 10 additions & 0 deletions src/OmniSharp.Abstractions/Models/v2/Location.cs
@@ -0,0 +1,10 @@
#nullable enable

namespace OmniSharp.Models.V2
{
public record Location
{
public string FileName { get; init; } = null!;
public Range Range { get; init; } = null!;
}
}
32 changes: 3 additions & 29 deletions src/OmniSharp.Abstractions/Models/v2/Point.cs
@@ -1,39 +1,13 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace OmniSharp.Models.V2
{
public class Point : IEquatable<Point>
public record Point : IEquatable<Point>
{
[JsonConverter(typeof(ZeroBasedIndexConverter))]
public int Line { get; set; }
public int Line { get; init; }
[JsonConverter(typeof(ZeroBasedIndexConverter))]
public int Column { get; set; }

public override bool Equals(object obj)
=> Equals(obj as Point);

public bool Equals(Point other)
=> other != null
&& Line == other.Line
&& Column == other.Column;

public override int GetHashCode()
{
var hashCode = -1456208474;
hashCode = hashCode * -1521134295 + Line.GetHashCode();
hashCode = hashCode * -1521134295 + Column.GetHashCode();
return hashCode;
}

public override string ToString()
=> $"Line = {Line}, Column = {Column}";

public static bool operator ==(Point point1, Point point2)
=> EqualityComparer<Point>.Default.Equals(point1, point2);

public static bool operator !=(Point point1, Point point2)
=> !(point1 == point2);
public int Column { get; init; }
}
}
34 changes: 3 additions & 31 deletions src/OmniSharp.Abstractions/Models/v2/Range.cs
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;

namespace OmniSharp.Models.V2
{
public class Range : IEquatable<Range>
public record Range
{
public Point Start { get; set; }
public Point End { get; set; }
public Point Start { get; init; }
public Point End { get; init; }

public bool Contains(int line, int column)
{
Expand All @@ -29,30 +26,5 @@ public bool Contains(int line, int column)
}

public bool IsValid() => Start != null && Start.Line > -1 && Start.Column > -1 && End != null && End.Line > -1 && End.Column > -1;

public override bool Equals(object obj)
=> Equals(obj as Range);

public bool Equals(Range other)
=> other != null
&& EqualityComparer<Point>.Default.Equals(Start, other.Start)
&& EqualityComparer<Point>.Default.Equals(End, other.End);

public override int GetHashCode()
333fred marked this conversation as resolved.
Show resolved Hide resolved
{
var hashCode = -1676728671;
hashCode = hashCode * -1521134295 + EqualityComparer<Point>.Default.GetHashCode(Start);
hashCode = hashCode * -1521134295 + EqualityComparer<Point>.Default.GetHashCode(End);
return hashCode;
}

public override string ToString()
=> $"Start = {{{Start}}}, End = {{{End}}}";

public static bool operator ==(Range range1, Range range2)
=> EqualityComparer<Range>.Default.Equals(range1, range2);

public static bool operator !=(Range range1, Range range2)
=> !(range1 == range2);
}
}
1 change: 1 addition & 0 deletions src/OmniSharp.Abstractions/OmniSharpEndpoints.cs
Expand Up @@ -72,6 +72,7 @@ public static class V2

public const string Highlight = "/v2/highlight";

public const string GotoDefinition = "/v2/gotodefinition";
}
}
}
19 changes: 11 additions & 8 deletions src/OmniSharp.Cake/Extensions/ResponseExtensions.cs
Expand Up @@ -272,16 +272,19 @@ private static async Task<Range> TranslateAsync(this Range range, OmniSharpWorks

if (range.Start.Line == range.End.Line)
{
range.Start.Line = line;
range.End.Line = line;
return range;
return range with
{
Start = range.Start with { Line = line },
End = range.End with { Line = line }
};
}

range.Start.Line = line;
(line, _) = await LineIndexHelper.TranslateFromGenerated(request.FileName, range.End.Line, workspace, true);
range.End.Line = line;

return range;
var (endLine, _) = await LineIndexHelper.TranslateFromGenerated(request.FileName, range.End.Line, workspace, true);
return range with
{
Start = range.Start with { Line = line },
End = range.End with { Line = endLine }
};
}

private static async Task<FileMemberElement> TranslateAsync(this FileMemberElement element, OmniSharpWorkspace workspace, Request request)
Expand Down
Expand Up @@ -18,10 +18,15 @@ protected override async Task<TRequest> TranslateRequestAsync(TRequest request)
if (request.Selection != null)
{
var startLine = await LineIndexHelper.TranslateToGenerated(request.FileName, request.Selection.Start.Line, Workspace);
request.Selection.End.Line = request.Selection.Start.Line != request.Selection.End.Line
var endLine = request.Selection.Start.Line != request.Selection.End.Line
? await LineIndexHelper.TranslateToGenerated(request.FileName, request.Selection.End.Line, Workspace)
: startLine;
request.Selection.Start.Line = startLine;
request = (TRequest)request.WithSelection(
request.Selection with
{
Start = request.Selection.Start with { Line = startLine },
End = request.Selection.End with { Line = endLine }
});
}

return await base.TranslateRequestAsync(request);
Expand Down
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Models.GotoDefinition;
using OmniSharp.Models.V2.GotoDefinition;
using static OmniSharp.LanguageServerProtocol.Helpers;

namespace OmniSharp.LanguageServerProtocol.Handlers
Expand Down Expand Up @@ -41,16 +41,16 @@ public override async Task<LocationOrLocationLinks> Handle(DefinitionParams requ

var omnisharpResponse = await _definitionHandler.Handle(omnisharpRequest);

if (string.IsNullOrWhiteSpace(omnisharpResponse.FileName))
if (omnisharpResponse.Definitions == null)
{
return new LocationOrLocationLinks();
}

return new LocationOrLocationLinks(new Location()
return new LocationOrLocationLinks(omnisharpResponse.Definitions.Select<Definition, LocationOrLocationLink>(definition => new Location()
{
Uri = ToUri(omnisharpResponse.FileName),
Range = ToRange((omnisharpResponse.Column, omnisharpResponse.Line))
});
Uri = definition.Location.FileName,
Range = ToRange(definition.Location.Range)
}));
}

protected override DefinitionRegistrationOptions CreateRegistrationOptions(DefinitionCapability capability, ClientCapabilities clientCapabilities)
Expand Down
@@ -0,0 +1,46 @@
#nullable enable

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using OmniSharp.Extensions;
using System.Threading;
using System.Threading.Tasks;

namespace OmniSharp.Roslyn.CSharp.Services.Navigation
{
internal static class GoToDefinitionHelpers
{
internal static async Task<ISymbol?> GetDefinitionSymbol(Document document, int line, int column, CancellationToken cancellationToken)
{
var sourceText = await document.GetTextAsync(cancellationToken);
var position = sourceText.GetPositionFromLineAndOffset(line, column);
333fred marked this conversation as resolved.
Show resolved Hide resolved
var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken);

return symbol switch
{
INamespaceSymbol => null,
// Always prefer the partial implementation over the definition
IMethodSymbol { IsPartialDefinition: true, PartialImplementationPart: var impl } => impl,
// Don't return property getters/settings/initers
IMethodSymbol { AssociatedSymbol: IPropertySymbol } => null,
_ => symbol
};
}

internal static async Task<FileLinePositionSpan?> GetMetadataMappedSpan(
Document document,
ISymbol symbol,
IExternalSourceService externalSourceService,
CancellationToken cancellationToken)
{
var (metadataDocument, _) = await externalSourceService.GetAndAddExternalSymbolDocument(document.Project, symbol, cancellationToken);
if (metadataDocument != null)
{
var metadataLocation = await externalSourceService.GetExternalSymbolLocation(symbol, metadataDocument, cancellationToken);
return metadataLocation.GetMappedLineSpan();
}

return null;
}
}
}