| Index: pkg/analysis_server/lib/src/edit/edit_domain.dart
|
| diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
|
| index 2507981e742151e06e7914102034a36c88097531..b6773f9dda559a2ff08e8d6c63a5027a149847a7 100644
|
| --- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
|
| +++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
|
| @@ -4,16 +4,24 @@
|
|
|
| library edit.domain;
|
|
|
| +import 'dart:async';
|
| +
|
| import 'package:analysis_server/src/analysis_server.dart';
|
| import 'package:analysis_server/src/constants.dart';
|
| import 'package:analysis_server/src/edit/fix.dart';
|
| import 'package:analysis_server/src/protocol.dart';
|
| +import 'package:analysis_server/src/protocol2.dart' as protocol show
|
| + LinkedEditGroup;
|
| import 'package:analysis_server/src/protocol2.dart' show AnalysisError,
|
| EditGetAssistsParams, EditGetAvailableRefactoringsParams,
|
| - EditGetAvailableRefactoringsResult, EditGetFixesParams, RefactoringKind;
|
| + EditGetAvailableRefactoringsResult, EditGetFixesParams,
|
| + EditGetRefactoringParams, EditGetRefactoringResult, LinkedEditGroup, Location,
|
| + RefactoringKind, RefactoringProblem, RefactoringProblemSeverity, RenameOptions,
|
| + SourceChange;
|
| import 'package:analysis_server/src/services/correction/assist.dart';
|
| import 'package:analysis_server/src/services/correction/change.dart';
|
| import 'package:analysis_server/src/services/correction/fix.dart';
|
| +import 'package:analysis_server/src/services/correction/status.dart';
|
| import 'package:analysis_server/src/services/json.dart';
|
| import 'package:analysis_server/src/services/refactoring/refactoring.dart';
|
| import 'package:analysis_server/src/services/search/search_engine.dart';
|
| @@ -39,11 +47,14 @@ class EditDomainHandler implements RequestHandler {
|
| */
|
| SearchEngine searchEngine;
|
|
|
| + _RefactoringManager refactoringManager;
|
| +
|
| /**
|
| * Initialize a newly created handler to handle requests for the given [server].
|
| */
|
| EditDomainHandler(this.server) {
|
| searchEngine = server.searchEngine;
|
| + refactoringManager = new _RefactoringManager(server, searchEngine);
|
| }
|
|
|
| Response getAssists(Request request) {
|
| @@ -130,12 +141,15 @@ class EditDomainHandler implements RequestHandler {
|
| Response handleRequest(Request request) {
|
| try {
|
| String requestName = request.method;
|
| - if (requestName == EDIT_GET_AVAILABLE_REFACTORINGS) {
|
| - return getAvailableRefactorings(request);
|
| - } else if (requestName == EDIT_GET_ASSISTS) {
|
| + if (requestName == EDIT_GET_ASSISTS) {
|
| return getAssists(request);
|
| + } else if (requestName == EDIT_GET_AVAILABLE_REFACTORINGS) {
|
| + return getAvailableRefactorings(request);
|
| } else if (requestName == EDIT_GET_FIXES) {
|
| return getFixes(request);
|
| + } else if (requestName == EDIT_GET_REFACTORING) {
|
| + refactoringManager.getRefactoring(request);
|
| + return Response.DELAYED_RESPONSE;
|
| }
|
| } on RequestFailure catch (exception) {
|
| return exception.response;
|
| @@ -143,3 +157,153 @@ class EditDomainHandler implements RequestHandler {
|
| return null;
|
| }
|
| }
|
| +
|
| +
|
| +/**
|
| + * An object managing a single [Refactoring] instance.
|
| + *
|
| + * The instance is identified by its kind, file, offset and length.
|
| + * It is initialized when the a set of parameters is given for the first time.
|
| + * All subsequent requests are performed on this [Refactoring] instance.
|
| + *
|
| + * Once new set of parameters is received, the previous [Refactoring] instance
|
| + * is invalidated and a new one is created and initialized.
|
| + */
|
| +class _RefactoringManager {
|
| + final AnalysisServer server;
|
| + final SearchEngine searchEngine;
|
| +
|
| + RefactoringKind kind;
|
| + String file;
|
| + int offset;
|
| + int length;
|
| + Refactoring refactoring;
|
| + RefactoringStatus initStatus;
|
| + RefactoringStatus optionsStatus;
|
| + RefactoringStatus finalStatus;
|
| +
|
| + String requestId;
|
| + EditGetRefactoringResult result;
|
| +
|
| + _RefactoringManager(this.server, this.searchEngine) {
|
| + _reset();
|
| + }
|
| +
|
| + bool get _hasFatalError {
|
| + return initStatus.hasFatalError ||
|
| + optionsStatus.hasFatalError ||
|
| + finalStatus.hasFatalError;
|
| + }
|
| +
|
| + void getRefactoring(Request request) {
|
| + // prepare for processing the request
|
| + requestId = request.id;
|
| + result = new EditGetRefactoringResult(<RefactoringProblem>[]);
|
| + // process the request
|
| + var params = new EditGetRefactoringParams.fromRequest(request);
|
| + _init(params.kind, params.file, params.offset, params.length).then((_) {
|
| + if (_hasFatalError) {
|
| + return _sendResultResponse();
|
| + }
|
| + // set options
|
| + if (params.options == null) {
|
| + return _sendResultResponse();
|
| + }
|
| + optionsStatus = _setOptions(params.options);
|
| + if (_hasFatalError) {
|
| + return _sendResultResponse();
|
| + }
|
| + // done if just validation
|
| + if (params.validateOnly) {
|
| + return _sendResultResponse();
|
| + }
|
| + // validation and create change
|
| + refactoring.checkFinalConditions().then((_finalStatus) {
|
| + finalStatus = _finalStatus;
|
| + if (_hasFatalError) {
|
| + return _sendResultResponse();
|
| + }
|
| + return refactoring.createChange().then((change) {
|
| + result.change = new SourceChange(
|
| + change.message,
|
| + change.fileEdits,
|
| + <protocol.LinkedEditGroup>[]);
|
| + return _sendResultResponse();
|
| + });
|
| + });
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * Initializes this context to perform a refactoring with the specified
|
| + * parameters. The existing [Refactoring] is reused or created as needed.
|
| + */
|
| + Future<RefactoringStatus> _init(RefactoringKind kind, String file, int offset,
|
| + int length) {
|
| + List<RefactoringProblem> problems = <RefactoringProblem>[];
|
| + // check if we can continue with the existing Refactoring instance
|
| + if (this.kind == kind &&
|
| + this.file == file &&
|
| + this.offset == offset &&
|
| + this.length == length) {
|
| + return new Future.value(initStatus);
|
| + }
|
| + _reset();
|
| + this.kind = kind;
|
| + this.file = file;
|
| + this.offset = offset;
|
| + this.length = length;
|
| + // create a new Refactoring instance
|
| + if (kind == RefactoringKind.RENAME) {
|
| + List<Element> elements = server.getElementsAtOffset(file, offset);
|
| + if (elements.isNotEmpty) {
|
| + Element element = elements[0];
|
| + refactoring = new RenameRefactoring(searchEngine, element);
|
| + }
|
| + }
|
| + if (refactoring == null) {
|
| + initStatus =
|
| + new RefactoringStatus.fatal('Unable to create a refactoring');
|
| + return new Future.value(initStatus);
|
| + }
|
| + // check initial conditions
|
| + return refactoring.checkInitialConditions().then((status) {
|
| + initStatus = status;
|
| + return initStatus;
|
| + });
|
| + }
|
| +
|
| + void _reset() {
|
| + refactoring = null;
|
| + initStatus = new RefactoringStatus();
|
| + optionsStatus = new RefactoringStatus();
|
| + finalStatus = new RefactoringStatus();
|
| + }
|
| +
|
| + void _sendResultResponse() {
|
| + // set problems
|
| + {
|
| + RefactoringStatus status = new RefactoringStatus();
|
| + status.addStatus(initStatus);
|
| + status.addStatus(optionsStatus);
|
| + status.addStatus(finalStatus);
|
| + result.problems = status.problems;
|
| + }
|
| + // send the response
|
| + server.sendResponse(result.toResponse(requestId));
|
| + // done with this request
|
| + requestId = null;
|
| + result = null;
|
| + }
|
| +
|
| + RefactoringStatus _setOptions(Object options) {
|
| + if (refactoring is RenameRefactoring) {
|
| + RenameRefactoring renameRefactoring = refactoring;
|
| + RenameOptions renameOptions = options;
|
| + String newName = renameOptions.newName;
|
| + renameRefactoring.newName = newName;
|
| + return renameRefactoring.checkNewName();
|
| + }
|
| + return new RefactoringStatus();
|
| + }
|
| +}
|
|
|