Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Microsoft.Python.LanguageServer {
public interface IDocumentationSource {
InsertTextFormat DocumentationFormat { get; }
MarkupContent GetHover(string name, IMember member, IPythonType self = null);
string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0);
string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0, string name = null);
MarkupContent FormatParameterDocumentation(IParameterInfo parameter);
MarkupContent FormatDocumentation(string documentation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ public MarkupContent FormatDocumentation(string documentation) {
return new MarkupContent { kind = MarkupKind.Markdown, value = DocstringConverter.ToMarkdown(documentation) };
}

public string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0) {
public string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0, string name = null) {
var o = ft.Overloads[overloadIndex];

var parms = GetFunctionParameters(ft);
var parmString = string.Join(", ", parms);
var returnDoc = o.GetReturnDocumentation(self);
var annString = string.IsNullOrEmpty(returnDoc) ? string.Empty : $" -> {returnDoc}";

return $"{ft.Name}({parmString}){annString}";
return $"{name ?? ft.Name}({parmString}){annString}";
}

public MarkupContent FormatParameterDocumentation(IParameterInfo parameter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ public MarkupContent FormatDocumentation(string documentation) {
return new MarkupContent { kind = MarkupKind.PlainText, value = documentation };
}

public string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0) {
public string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0, string name = null) {
var o = ft.Overloads[overloadIndex];

var parms = GetFunctionParameters(ft);
var parmString = string.Join(", ", parms);
var returnDoc = o.GetReturnDocumentation(self);
var annString = string.IsNullOrEmpty(returnDoc) ? string.Empty : $" -> {returnDoc}";

return $"{ft.Name}({parmString}){annString}";
return $"{name ?? ft.Name}({parmString}){annString}";
}

public MarkupContent FormatParameterDocumentation(IParameterInfo parameter) {
Expand Down
25 changes: 20 additions & 5 deletions src/LanguageServer/Impl/Sources/SignatureSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,33 @@ public SignatureHelp GetSignature(IDocumentAnalysis analysis, SourceLocation loc

IMember value = null;
IPythonType selfType = null;
string name = null;
var call = node as CallExpression;
if (call != null) {
using (analysis.ExpressionEvaluator.OpenScope(analysis.Document, scope)) {
if (call.Target is MemberExpression mex) {
var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target);
selfType = v?.GetPythonType();
switch (call.Target) {
case MemberExpression mex:
var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target);
selfType = v?.GetPythonType();
name = mex.Name;
break;
case NameExpression ne:
name = ne.Name;
break;
}

value = analysis.ExpressionEvaluator.GetValueFromExpression(call.Target);
}
}

var ft = value?.GetPythonType<IPythonFunctionType>();
IPythonFunctionType ft;

if (value is IPythonClassType cls) {
ft = cls.GetMember<IPythonFunctionType>("__init__");
} else {
ft = value?.GetPythonType<IPythonFunctionType>();
}

if (ft == null) {
return null;
}
Expand All @@ -70,7 +85,7 @@ public SignatureHelp GetSignature(IDocumentAnalysis analysis, SourceLocation loc
}).ToArray();

signatures[i] = new SignatureInformation {
label = _docSource.GetSignatureString(ft, selfType, i),
label = _docSource.GetSignatureString(ft, selfType, i, name),
documentation = _docSource.FormatDocumentation(ft.Documentation),
parameters = parameters
};
Expand Down
58 changes: 58 additions & 0 deletions src/LanguageServer/Test/SignatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.

using System.IO;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Python.Analysis.Analyzer;
using Microsoft.Python.Analysis.Documents;
using Microsoft.Python.Core.Text;
using Microsoft.Python.LanguageServer.Sources;
using Microsoft.Python.Parsing.Tests;
Expand Down Expand Up @@ -52,6 +55,61 @@ def method(self, a:int, b) -> float:
sig.signatures[0].label.Should().Be("method(a: int, b) -> float");
}

[TestMethod, Priority(0)]
public async Task ClassInitializer() {
const string code = @"
class C:
def __init__(self, a:int, b):
pass

C()
";
var analysis = await GetAnalysisAsync(code);
var src = new SignatureSource(new PlainTextDocumentationSource());

var sig = src.GetSignature(analysis, new SourceLocation(6, 3));
sig.activeSignature.Should().Be(0);
sig.activeParameter.Should().Be(0);
sig.signatures.Length.Should().Be(1);
sig.signatures[0].label.Should().Be("C(a: int, b)");
}

[TestMethod, Priority(0)]
public async Task ImportedClassInitializer() {
const string module1Code = @"
class C:
def __init__(self, a:int, b):
pass
";

const string appCode = @"
import module1

module1.C()
";
var module1Uri = TestData.GetTestSpecificUri("module1.py");
var appUri = TestData.GetTestSpecificUri("app.py");

var root = Path.GetDirectoryName(appUri.AbsolutePath);
await CreateServicesAsync(root, PythonVersions.LatestAvailable3X);
var rdt = Services.GetService<IRunningDocumentTable>();
var analyzer = Services.GetService<IPythonAnalyzer>();

rdt.OpenDocument(module1Uri, module1Code);

var app = rdt.OpenDocument(appUri, appCode);
await analyzer.WaitForCompleteAnalysisAsync();
var analysis = await app.GetAnalysisAsync(-1);

var src = new SignatureSource(new PlainTextDocumentationSource());

var sig = src.GetSignature(analysis, new SourceLocation(4, 11));
sig.activeSignature.Should().Be(0);
sig.activeParameter.Should().Be(0);
sig.signatures.Length.Should().Be(1);
sig.signatures[0].label.Should().Be("C(a: int, b)");
}

[TestMethod, Priority(0)]
public async Task GenericClassMethod() {
const string code = @"
Expand Down