blob: 9b35b4c71c8d14e657129a78f5335e49bb421cbe [file] [log] [blame]
// Copyright (c) 2014, 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.
library search.domain;
import 'dart:async';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/computer/element.dart' as se;
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/element_references.dart';
import 'package:analysis_server/src/search/search_result.dart';
import 'package:analysis_server/src/search/type_hierarchy.dart';
import 'package:analysis_services/constants.dart';
import 'package:analysis_services/json.dart';
import 'package:analysis_services/search/search_engine.dart';
import 'package:analyzer/src/generated/element.dart';
/**
* Instances of the class [SearchDomainHandler] implement a [RequestHandler]
* that handles requests in the search domain.
*/
class SearchDomainHandler implements RequestHandler {
/**
* The analysis server that is using this handler to process requests.
*/
final AnalysisServer server;
/**
* The [SearchEngine] for this server.
*/
SearchEngine searchEngine;
/**
* The next searc response id.
*/
int _nextSearchId = 0;
/**
* Initialize a newly created handler to handle requests for the given [server].
*/
SearchDomainHandler(this.server) {
searchEngine = server.searchEngine;
}
Response findElementReferences(Request request) {
String file = request.getRequiredParameter(FILE).asString();
int offset = request.getRequiredParameter(OFFSET).asInt();
bool includePotential =
request.getRequiredParameter(INCLUDE_POTENTIAL).asBool();
// prepare elements
List<Element> elements = server.getElementsAtOffset(file, offset);
elements = elements.map((Element element) {
if (element is FieldFormalParameterElement) {
return element.field;
}
if (element is PropertyAccessorElement) {
return element.variable;
}
return element;
}).toList();
// schedule search
String searchId = (_nextSearchId++).toString();
elements.forEach((Element element) {
var computer = new ElementReferencesComputer(searchEngine);
var future = computer.compute(element, includePotential);
future.then((List<SearchResult> results) {
bool isLast = identical(element, elements.last);
_sendSearchNotification(searchId, isLast, results);
});
});
if (elements.isEmpty) {
new Future.microtask(() {
_sendSearchNotification(searchId, true, []);
});
}
// respond
Response response = new Response(request.id);
response.setResult(ID, searchId);
if (elements.isNotEmpty) {
var serverElement = new se.Element.fromEngine(elements[0]);
response.setResult(ELEMENT, serverElement);
}
return response;
}
Response findMemberDeclarations(Request request) {
String name = request.getRequiredParameter(NAME).asString();
// schedule search
String searchId = (_nextSearchId++).toString();
{
var matchesFuture = searchEngine.searchMemberDeclarations(name);
matchesFuture.then((List<SearchMatch> matches) {
_sendSearchNotification(searchId, true, matches.map(toResult));
});
}
// respond
return new Response(request.id)..setResult(ID, searchId);
}
Response findMemberReferences(Request request) {
String name = request.getRequiredParameter(NAME).asString();
// schedule search
String searchId = (_nextSearchId++).toString();
{
var matchesFuture = searchEngine.searchMemberReferences(name);
matchesFuture.then((List<SearchMatch> matches) {
_sendSearchNotification(searchId, true, matches.map(toResult));
});
}
// respond
return new Response(request.id)..setResult(ID, searchId);
}
Response findTopLevelDeclarations(Request request) {
String pattern = request.getRequiredParameter(PATTERN).asString();
// schedule search
String searchId = (_nextSearchId++).toString();
{
var matchesFuture = searchEngine.searchTopLevelDeclarations(pattern);
matchesFuture.then((List<SearchMatch> matches) {
_sendSearchNotification(searchId, true, matches.map(toResult));
});
}
// respond
return new Response(request.id)..setResult(ID, searchId);
}
/**
* Implement the `search.getTypeHierarchy` request.
*/
Response getTypeHierarchy(Request request) {
// prepare parameters
String file = request.getRequiredParameter(FILE).asString();
int offset = request.getRequiredParameter(OFFSET).asInt();
// prepare Element
List<Element> elements = server.getElementsAtOffset(file, offset);
if (elements.isEmpty) {
return new Response(request.id);
}
Element element = elements.first;
// prepare type hierarchy
TypeHierarchyComputer computer = new TypeHierarchyComputer(searchEngine);
computer.compute(element).then((List<TypeHierarchyItem> items) {
Response response = new Response(request.id);
response.setResult(HIERARCHY_ITEMS, objectToJson(items));
server.sendResponse(response);
});
// delay response
return Response.DELAYED_RESPONSE;
}
@override
Response handleRequest(Request request) {
try {
String requestName = request.method;
if (requestName == SEARCH_FIND_ELEMENT_REFERENCES) {
return findElementReferences(request);
} else if (requestName == SEARCH_FIND_MEMBER_DECLARATIONS) {
return findMemberDeclarations(request);
} else if (requestName == SEARCH_FIND_MEMBER_REFERENCES) {
return findMemberReferences(request);
} else if (requestName == SEARCH_FIND_TOP_LEVEL_DECLARATIONS) {
return findTopLevelDeclarations(request);
} else if (requestName == SEARCH_GET_TYPE_HIERARCHY) {
return getTypeHierarchy(request);
}
} on RequestFailure catch (exception) {
return exception.response;
}
return null;
}
void _sendSearchNotification(String searchId, bool isLast,
Iterable<SearchResult> results) {
Notification notification = new Notification(SEARCH_RESULTS);
notification.setParameter(ID, searchId);
notification.setParameter(LAST, isLast);
notification.setParameter(RESULTS, results);
server.sendNotification(notification);
}
static SearchResult toResult(SearchMatch match) {
return new SearchResult.fromMatch(match);
}
}