Skip to content

Commit

Permalink
WIP - getSignatureInformation.
Browse files Browse the repository at this point in the history
  • Loading branch information
DanTup committed Aug 12, 2017
1 parent 0055f55 commit d2d9174
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 2 deletions.
5 changes: 3 additions & 2 deletions pkg/analysis_server/lib/src/computer/computer_hover.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class DartUnitHoverComputer {
}
}
// documentation
hover.dartdoc = _computeDocumentation(element);
hover.dartdoc = computeDocumentation(element);
}
// parameter
hover.parameter = _safeToString(expression.bestParameterElement);
Expand Down Expand Up @@ -105,7 +105,8 @@ class DartUnitHoverComputer {
return null;
}

String _computeDocumentation(Element element) {
// TODO(dantup) We're reusing this in paramter information - move it somewhere shared?
static String computeDocumentation(Element element) {
if (element is FieldFormalParameterElement) {
element = (element as FieldFormalParameterElement).field;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analysis_server/protocol/protocol_generated.dart'
show
AnalysisGetSignatureInformationResult,
HoverInformation,
ParameterInfo,
ParameterKind;
import 'package:analysis_server/src/computer/computer_hover.dart';
import 'package:analysis_server/src/computer/computer_overrides.dart';
import 'package:analysis_server/src/utilities/documentation.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';

/**
* A computer for the signature information at the specified offset of a Dart [CompilationUnit].
*/
class DartUnitSignatureInformationComputer {
final CompilationUnit _unit;
final int _offset;

DartUnitSignatureInformationComputer(this._unit, this._offset);

/**
* Returns the computed signature information, maybe `null`.
*/
AnalysisGetSignatureInformationResult compute() {
AstNode node = new NodeLocator(_offset).searchWithin(_unit);
if (node == null) {
return null;
}

// Find the closest argument list.
while (node != null && !(node is ArgumentList)) {
node = node.parent;
}

if (node == null) {
return null;
}

final args = node;
// TODO(dantup) Constructor?
final method = args.parent as MethodInvocation;
final methodElement = ElementLocator.locate(method) as FunctionElement;
final parameters =
methodElement.parameters.map((p) => _convertParam(p)).toList();

return new AnalysisGetSignatureInformationResult(
method.methodName.name,
DartUnitHoverComputer.computeDocumentation(methodElement),
parameters,
0);
}

String _computeDocumentation(Element element) {
if (element is FieldFormalParameterElement) {
element = (element as FieldFormalParameterElement).field;
}
if (element is ParameterElement) {
element = element.enclosingElement;
}
if (element == null) {
// This can happen when the code is invalid, such as having a field formal
// parameter for a field that does not exist.
return null;
}
// The documentation of the element itself.
if (element.documentationComment != null) {
return removeDartDocDelimiters(element.documentationComment);
}
// Look for documentation comments of overridden members.
OverriddenElements overridden = findOverriddenElements(element);
for (Element superElement in []
..addAll(overridden.superElements)
..addAll(overridden.interfaceElements)) {
String rawDoc = superElement.documentationComment;
if (rawDoc != null) {
Element interfaceClass = superElement.enclosingElement;
return removeDartDocDelimiters(rawDoc) +
'\n\nCopied from `${interfaceClass.displayName}`.';
}
}
return null;
}

ParameterInfo _convertParam(ParameterElement param) {
// TODO(dantup) Can we reuse the existing ParamterKind rather than making our own?
todo: this cast fails
final kind = param.parameterKind as ParameterKind;
return new ParameterInfo(kind, param.displayName, param.type.displayName);
}

static _safeToString(obj) => obj?.toString();
}
22 changes: 22 additions & 0 deletions pkg/analysis_server/lib/src/domain_analysis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:analysis_server/plugin/analysis/analysis_domain.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/computer/computer_hover.dart';
import 'package:analysis_server/src/computer/computer_signature_information.dart';
import 'package:analysis_server/src/computer/imported_elements_computer.dart';
import 'package:analysis_server/src/domain_abstract.dart';
import 'package:analysis_server/src/domains/analysis/navigation.dart';
Expand Down Expand Up @@ -233,6 +234,24 @@ class AnalysisDomainHandler extends AbstractRequestHandler {
// .toResponse(request.id);
}

/**
* Implement the `analysis.getSignatureInformation` request.
*/
Future<Null> getSignatureInformation(Request request) async {
var params = new AnalysisGetSignatureInformationParams.fromRequest(request);

// Prepare the resolved units.
AnalysisResult result = await server.getAnalysisResult(params.file);
CompilationUnit unit = result?.unit;

// Prepare the signature information.
var signatureInfo =
new DartUnitSignatureInformationComputer(unit, params.offset).compute();

// Send the response.
server.sendResponse(signatureInfo.toResponse(request.id));
}

@override
Response handleRequest(Request request) {
try {
Expand All @@ -253,6 +272,9 @@ class AnalysisDomainHandler extends AbstractRequestHandler {
return Response.DELAYED_RESPONSE;
} else if (requestName == ANALYSIS_REQUEST_GET_REACHABLE_SOURCES) {
return getReachableSources(request);
} else if (requestName == ANALYSIS_REQUEST_GET_SIGNATURE_INFORMATION) {
getSignatureInformation(request);
return Response.DELAYED_RESPONSE;
} else if (requestName == ANALYSIS_REQUEST_REANALYZE) {
return reanalyze(request);
} else if (requestName == ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';

import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../analysis_abstract.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnalysisSignatureInformationTest);
});
}

@reflectiveTest
class AnalysisSignatureInformationTest extends AbstractAnalysisTest {
Future<AnalysisGetSignatureInformationResult> prepareSignatureInformation(
String search) {
int offset = findOffset(search);
return prepareSignatureInformationAt(offset);
}

Future<AnalysisGetSignatureInformationResult> prepareSignatureInformationAt(
int offset) async {
await waitForTasksFinished();
Request request =
new AnalysisGetSignatureInformationParams(testFile, offset)
.toRequest('0');
Response response = await waitResponse(request);
return new AnalysisGetSignatureInformationResult.fromResponse(response);
}

@override
void setUp() {
super.setUp();
createProject();
}

test_simple() async {
addTestFile('''
/// one doc
one(String name, int length) {}
main() {
one("Danny", /*^*/);
}
''');
var result = await prepareSignatureInformation('/*^*/');
expect(result.name, equals("one"));
expect(result.dartdoc, equals("one doc"));
expect(result.parameters, hasLength(2));
expect(result.parameters[0],
equals(new ParameterInfo(ParameterKind.NAMED, "name", "String")));
expect(result.parameters[1],
equals(new ParameterInfo(ParameterKind.NAMED, "length", "int")));
}

// TODO:
// No signature info
// named
// optional
// Not yet ready
// Constructor
// Named constructor
// Static method
// Instance method
// Anonymous function
// Content changed during response (CONTENT_MODIFIED)
// invali file (GET_SIGNATURE_INVALID_FILE)
// invalid offset (GET_SIGNATURE_INVALID_OFFSET)
// invalid function (GET_SIGNATURE_UNKNOWN_FUNCTION)
}
2 changes: 2 additions & 0 deletions pkg/analysis_server/test/analysis/test_all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'get_errors_test.dart' as get_errors_test;
import 'get_hover_test.dart' as get_hover_test;
import 'get_navigation_test.dart' as get_navigation_test;
import 'get_signature_information_test.dart' as get_signature_information_test;
import 'navigation_collector_test.dart' as navigation_collector_test;
import 'notification_analysis_options_test.dart'
as notification_analysis_options_test;
Expand Down Expand Up @@ -34,6 +35,7 @@ main() {
get_errors_test.main();
get_hover_test.main();
get_navigation_test.main();
get_signature_information_test.main();
navigation_collector_test.main();
notification_analysis_options_test.main();
notification_analyzedFiles_test.main();
Expand Down

0 comments on commit d2d9174

Please sign in to comment.