Skip to content

Commit e1ecc28

Browse files
committed
Implementation for 'analysis.updateContent' API.
[email protected] BUG= Review URL: https://codereview.chromium.org//300553014 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@36766 260f80e4-7a28-3924-810f-c04153c831b5
1 parent 37a3ab9 commit e1ecc28

File tree

3 files changed

+153
-22
lines changed

3 files changed

+153
-22
lines changed

pkg/analysis_server/lib/src/analysis_server.dart

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ class AnalysisServer {
274274
}
275275

276276
/**
277-
* Implementation for `server.setAnalysisRoots`.
277+
* Implementation for `analysis.setAnalysisRoots`.
278278
*
279279
* TODO(scheglov) implement complete projects/contexts semantics.
280280
*
@@ -329,11 +329,30 @@ class AnalysisServer {
329329
}
330330
}
331331

332+
/**
333+
* Implementation for `analysis.updateContent`.
334+
*/
335+
void updateContent(Map<String, ContentChange> changes) {
336+
changes.forEach((file, change) {
337+
AnalysisContext analysisContext = _getAnalysisContext(file);
338+
if (analysisContext != null) {
339+
Source source = _getSource(file);
340+
if (change.offset == null) {
341+
analysisContext.setContents(source, change.content);
342+
} else {
343+
analysisContext.setChangedContents(source, change.content,
344+
change.offset, change.oldLength, change.newLength);
345+
}
346+
addContextToWorkQueue(analysisContext);
347+
}
348+
});
349+
}
350+
332351
/**
333352
* Return the [AnalysisContext] that is used to analyze the given [path].
334353
* Return `null` if there is no such context.
335354
*/
336-
AnalysisContext test_getAnalysisContext(String path) {
355+
AnalysisContext _getAnalysisContext(String path) {
337356
for (Folder folder in folderMap.keys) {
338357
if (path.startsWith(folder.fullName)) {
339358
return folderMap[folder].context;
@@ -342,19 +361,26 @@ class AnalysisServer {
342361
return null;
343362
}
344363

364+
/**
365+
* Return the [Source] of the Dart file with the given [path].
366+
*/
367+
Source _getSource(String path) {
368+
File file = resourceProvider.getResource(path);
369+
return file.createSource(UriKind.FILE_URI);
370+
}
371+
345372
/**
346373
* Return the [CompilationUnit] of the Dart file with the given [path].
347374
* Return `null` if the file is not a part of any context.
348375
*/
349376
CompilationUnit test_getResolvedCompilationUnit(String path) {
350377
// prepare AnalysisContext
351-
AnalysisContext context = test_getAnalysisContext(path);
378+
AnalysisContext context = _getAnalysisContext(path);
352379
if (context == null) {
353380
return null;
354381
}
355382
// prepare sources
356-
File file = resourceProvider.getResource(path);
357-
Source unitSource = file.createSource(UriKind.FILE_URI);
383+
Source unitSource = _getSource(path);
358384
List<Source> librarySources = context.getLibrariesContaining(unitSource);
359385
if (librarySources.isEmpty) {
360386
return null;

pkg/analysis_server/lib/src/domain_analysis.dart

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ class AnalysisDomainHandler implements RequestHandler {
7777
*/
7878
static const String ADDED_PARAM = 'added';
7979

80+
/**
81+
* The name of the `content` parameter.
82+
*/
83+
static const String CONTENT_PARAM = 'content';
84+
8085
/**
8186
* The name of the `default` parameter.
8287
*/
@@ -117,11 +122,21 @@ class AnalysisDomainHandler implements RequestHandler {
117122
*/
118123
static const String LENGTH_PARAM = 'length';
119124

125+
/**
126+
* The name of the `newLength` parameter.
127+
*/
128+
static const String NEW_LENGTH_PARAM = 'newLength';
129+
120130
/**
121131
* The name of the `offset` parameter.
122132
*/
123133
static const String OFFSET_PARAM = 'offset';
124134

135+
/**
136+
* The name of the `oldLength` parameter.
137+
*/
138+
static const String OLD_LENGTH_PARAM = 'oldLength';
139+
125140
/**
126141
* The name of the `options` parameter.
127142
*/
@@ -222,8 +237,20 @@ class AnalysisDomainHandler implements RequestHandler {
222237
}
223238

224239
Response updateContent(Request request) {
225-
// TODO(scheglov) implement
226-
return null;
240+
var changes = new Map<String, ContentChange>();
241+
RequestDatum filesDatum = request.getRequiredParameter(FILES_PARAM);
242+
filesDatum.forEachMap((file, changeDatum) {
243+
var change = new ContentChange();
244+
change.content = changeDatum[CONTENT_PARAM].asString();
245+
if (changeDatum.hasKey(OFFSET_PARAM)) {
246+
change.offset = changeDatum[OFFSET_PARAM].asInt();
247+
change.oldLength = changeDatum[OLD_LENGTH_PARAM].asInt();
248+
change.newLength = changeDatum[NEW_LENGTH_PARAM].asInt();
249+
}
250+
changes[file] = change;
251+
});
252+
server.updateContent(changes);
253+
return new Response(request.id);
227254
}
228255

229256
Response updateOptions(Request request) {
@@ -236,3 +263,14 @@ class AnalysisDomainHandler implements RequestHandler {
236263
return null;
237264
}
238265
}
266+
267+
268+
/**
269+
* A description of the change to the content of a file.
270+
*/
271+
class ContentChange {
272+
String content;
273+
int offset;
274+
int oldLength;
275+
int newLength;
276+
}

pkg/analysis_server/test/domain_analysis_test.dart

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ main() {
3030
});
3131

3232
group('notification.errors', testNotificationErrors);
33+
group('updateContent', testUpdateContent);
3334

3435
group('AnalysisDomainHandler', () {
3536
test('getFixes', () {
@@ -110,16 +111,6 @@ main() {
110111
expect(response, isNull);
111112
});
112113

113-
test('updateContent', () {
114-
var request = new Request('0', AnalysisDomainHandler.UPDATE_CONTENT_METHOD);
115-
// request.setParameter(
116-
// AnalysisDomainHandler.FILES_PARAM,
117-
// {'project/test.dart' : null});
118-
var response = handler.handleRequest(request);
119-
// TODO(scheglov) implement
120-
expect(response, isNull);
121-
});
122-
123114
test('updateOptions', () {
124115
var request = new Request('0', AnalysisDomainHandler.UPDATE_OPTIONS_METHOD);
125116
request.setParameter(
@@ -213,20 +204,38 @@ class AnalysisTestHelper {
213204
* Creates a project with a single Dart file `/project/bin/test.dart` with
214205
* the given [code].
215206
*/
216-
createSingleFileProject(code) {
217-
if (code is List<String>) {
218-
code = code.join('\n');
219-
}
220-
this.testCode = code;
207+
void createSingleFileProject(code) {
208+
this.testCode = _getCodeString(code);
221209
resourceProvider.newFolder('/project');
222210
resourceProvider.newFile('/project/pubspec.yaml', 'name: project');
223211
resourceProvider.newFile(testFile, testCode);
224212
Request request = new Request('0', AnalysisDomainHandler.SET_ANALYSIS_ROOTS_METHOD);
225213
request.setParameter(AnalysisDomainHandler.INCLUDED_PARAM, ['/project']);
226214
request.setParameter(AnalysisDomainHandler.EXCLUDED_PARAM, []);
215+
handleSuccessfulRequest(request);
216+
}
217+
218+
/**
219+
* Validates that the given [request] is handled successfully.
220+
*/
221+
void handleSuccessfulRequest(Request request) {
227222
Response response = handler.handleRequest(request);
228223
expect(response, isResponseSuccess('0'));
229224
}
225+
226+
/**
227+
* Stops the associated server.
228+
*/
229+
void stopServer() {
230+
server.done();
231+
}
232+
233+
static String _getCodeString(code) {
234+
if (code is List<String>) {
235+
code = code.join('\n');
236+
}
237+
return code as String;
238+
}
230239
}
231240

232241

@@ -266,6 +275,64 @@ testNotificationErrors() {
266275
}
267276

268277

278+
testUpdateContent() {
279+
test('full content', () {
280+
AnalysisTestHelper helper = new AnalysisTestHelper();
281+
helper.createSingleFileProject('// empty');
282+
return helper.waitForTasksFinished().then((_) {
283+
// no errors initially
284+
List<AnalysisError> errors = helper.getTestErrors();
285+
expect(errors, isEmpty);
286+
// update code
287+
{
288+
Request request = new Request('0', AnalysisDomainHandler.UPDATE_CONTENT_METHOD);
289+
request.setParameter('files',
290+
{
291+
helper.testFile : {
292+
AnalysisDomainHandler.CONTENT_PARAM : 'library lib'
293+
}
294+
});
295+
helper.handleSuccessfulRequest(request);
296+
}
297+
// wait, there is an error
298+
helper.waitForTasksFinished().then((_) {
299+
List<AnalysisError> errors = helper.getTestErrors();
300+
expect(errors, hasLength(1));
301+
});
302+
});
303+
});
304+
305+
test('incremental', () {
306+
AnalysisTestHelper helper = new AnalysisTestHelper();
307+
helper.createSingleFileProject('library A;');
308+
return helper.waitForTasksFinished().then((_) {
309+
// no errors initially
310+
List<AnalysisError> errors = helper.getTestErrors();
311+
expect(errors, isEmpty);
312+
// update code
313+
{
314+
Request request = new Request('0', AnalysisDomainHandler.UPDATE_CONTENT_METHOD);
315+
request.setParameter('files',
316+
{
317+
helper.testFile : {
318+
AnalysisDomainHandler.CONTENT_PARAM : 'library lib',
319+
AnalysisDomainHandler.OFFSET_PARAM : 'library '.length,
320+
AnalysisDomainHandler.OLD_LENGTH_PARAM : 'A;'.length,
321+
AnalysisDomainHandler.NEW_LENGTH_PARAM : 'lib'.length,
322+
}
323+
});
324+
helper.handleSuccessfulRequest(request);
325+
}
326+
// wait, there is an error
327+
helper.waitForTasksFinished().then((_) {
328+
List<AnalysisError> errors = helper.getTestErrors();
329+
expect(errors, hasLength(1));
330+
});
331+
});
332+
});
333+
}
334+
335+
269336
class AnalysisError {
270337
final String file;
271338
final String errorCode;

0 commit comments

Comments
 (0)