Skip to content

Commit a934ec2

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
If possible, reuse the last completion result.
Also rename "character" to "column". [email protected], [email protected] Change-Id: I6167de6e1fd5aede2a619603635e96f16bfbcc8d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144352 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 64b8ded commit a934ec2

File tree

4 files changed

+141
-79
lines changed

4 files changed

+141
-79
lines changed

pkg/analysis_server/lib/src/cider/completion.dart

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'package:analysis_server/src/services/completion/completion_performance.d
1010
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
1111
import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
1212
import 'package:analyzer/dart/element/element.dart' show LibraryElement;
13-
import 'package:analyzer/source/line_info.dart';
1413
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
1514
import 'package:analyzer/src/dart/micro/resolve_file.dart';
1615
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
@@ -23,6 +22,7 @@ import 'package:meta/meta.dart';
2322
/// example types and elements.
2423
class CiderCompletionCache {
2524
final Map<String, _CiderImportedLibrarySuggestions> _importedLibraries = {};
25+
_LastCompletionResult _lastResult;
2626
}
2727

2828
class CiderCompletionComputer {
@@ -31,22 +31,26 @@ class CiderCompletionComputer {
3131
final FileResolver _fileResolver;
3232

3333
DartCompletionRequestImpl _dartCompletionRequest;
34-
final List<String> _computedImportedLibraries = [];
34+
35+
/// Paths of imported libraries for which suggestions were (re)computed
36+
/// during processing of this request. Does not include libraries that were
37+
/// processed during previous requests, and reused from the cache now.
38+
@visibleForTesting
39+
final List<String> computedImportedLibraries = [];
3540

3641
CiderCompletionComputer(this._logger, this._cache, this._fileResolver);
3742

3843
@deprecated
3944
Future<List<CompletionSuggestion>> compute(String path, int offset) async {
40-
var file = _fileResolver.resourceProvider.getFile(path);
41-
var content = file.readAsStringSync();
45+
var fileContext = _fileResolver.getFileContext(path);
46+
var file = fileContext.file;
4247

43-
var lineInfo = LineInfo.fromContent(content);
44-
var location = lineInfo.getLocation(offset);
48+
var location = file.lineInfo.getLocation(offset);
4549

4650
var result = await compute2(
4751
path: path,
4852
line: location.lineNumber - 1,
49-
character: location.columnNumber - 1,
53+
column: location.columnNumber - 1,
5054
);
5155

5256
return result.suggestions;
@@ -58,19 +62,36 @@ class CiderCompletionComputer {
5862
///
5963
/// The content of the file has already been updated.
6064
///
61-
/// The [line] and [character] are zero based.
65+
/// The [line] and [column] are zero based.
6266
Future<CiderCompletionResult> compute2({
6367
@required String path,
6468
@required int line,
65-
@required int character,
69+
@required int column,
6670
}) async {
67-
var file = _fileResolver.resourceProvider.getFile(path);
68-
var content = file.readAsStringSync();
71+
var fileContext = _logger.run('Get file $path', () {
72+
return _fileResolver.getFileContext(path);
73+
});
6974

70-
var resolvedUnit = _fileResolver.resolve(path);
75+
var file = fileContext.file;
7176

72-
var lineInfo = LineInfo.fromContent(content);
73-
var offset = lineInfo.getOffsetOfLine(line) + character;
77+
var resolvedSignature = _logger.run('Get signature', () {
78+
return file.resolvedSignature;
79+
});
80+
81+
var lineInfo = file.lineInfo;
82+
var offset = lineInfo.getOffsetOfLine(line) + column;
83+
84+
// If the same file, in the same state as the last time, reuse the result.
85+
var lastResult = _cache._lastResult;
86+
if (lastResult != null &&
87+
lastResult.path == path &&
88+
lastResult.signature == resolvedSignature &&
89+
lastResult.offset == offset) {
90+
_logger.writeln('Use the last completion result.');
91+
return lastResult.result;
92+
}
93+
94+
var resolvedUnit = _fileResolver.resolve(path);
7495

7596
var completionRequest = CompletionRequestImpl(
7697
resolvedUnit,
@@ -100,18 +121,22 @@ class CiderCompletionComputer {
100121
dartdocDirectiveInfo,
101122
);
102123

103-
_logger.run('Add imported suggestions', () {
104-
suggestions.addAll(
105-
_importedLibrariesSuggestions(
106-
resolvedUnit.libraryElement,
107-
),
108-
);
109-
});
124+
if (_dartCompletionRequest.includeIdentifiers) {
125+
_logger.run('Add imported suggestions', () {
126+
suggestions.addAll(
127+
_importedLibrariesSuggestions(
128+
resolvedUnit.libraryElement,
129+
),
130+
);
131+
});
132+
}
110133

111-
return CiderCompletionResult._(
112-
suggestions,
113-
_computedImportedLibraries,
114-
);
134+
var result = CiderCompletionResult._(suggestions);
135+
136+
_cache._lastResult =
137+
_LastCompletionResult(path, resolvedSignature, offset, result);
138+
139+
return result;
115140
}
116141

117142
/// Return suggestions from libraries imported into the [target].
@@ -139,7 +164,7 @@ class CiderCompletionComputer {
139164

140165
var cacheEntry = _cache._importedLibraries[path];
141166
if (cacheEntry == null || cacheEntry.signature != signature) {
142-
_computedImportedLibraries.add(path);
167+
computedImportedLibraries.add(path);
143168
var suggestions = _librarySuggestions(element);
144169
cacheEntry = _CiderImportedLibrarySuggestions(
145170
signature,
@@ -165,16 +190,7 @@ class CiderCompletionComputer {
165190
class CiderCompletionResult {
166191
final List<CompletionSuggestion> suggestions;
167192

168-
/// Paths of imported libraries for which suggestions were (re)computed
169-
/// during processing of this request. Does not include libraries that were
170-
/// processed during previous requests, and reused from the cache now.
171-
@visibleForTesting
172-
final List<String> computedImportedLibraries;
173-
174-
CiderCompletionResult._(
175-
this.suggestions,
176-
this.computedImportedLibraries,
177-
);
193+
CiderCompletionResult._(this.suggestions);
178194
}
179195

180196
class _CiderImportedLibrarySuggestions {
@@ -183,3 +199,12 @@ class _CiderImportedLibrarySuggestions {
183199

184200
_CiderImportedLibrarySuggestions(this.signature, this.suggestions);
185201
}
202+
203+
class _LastCompletionResult {
204+
final String path;
205+
final String signature;
206+
final int offset;
207+
final CiderCompletionResult result;
208+
209+
_LastCompletionResult(this.path, this.signature, this.offset, this.result);
210+
}

pkg/analysis_server/test/src/cider/completion_test.dart

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void main() {
2222
class CiderCompletionComputerTest extends CiderServiceTest {
2323
final CiderCompletionCache _completionCache = CiderCompletionCache();
2424

25+
CiderCompletionComputer _computer;
2526
CiderCompletionResult _completionResult;
2627
List<CompletionSuggestion> _suggestions;
2728

@@ -78,6 +79,22 @@ main(int b) {
7879
_assertNoClass(text: 'Random');
7980
}
8081

82+
Future<void> test_compute2_sameSignature_sameResult() async {
83+
_createFileResolver();
84+
await _compute2(r'''
85+
var a = ^;
86+
''');
87+
var lastResult = _completionResult;
88+
89+
// Ask for completion using new resolver and computer.
90+
// But the file signature is the same, so the same result.
91+
_createFileResolver();
92+
await _compute2(r'''
93+
var a = ^;
94+
''');
95+
expect(_completionResult, same(lastResult));
96+
}
97+
8198
Future<void> test_compute2_updateImportedLibrary() async {
8299
var corePath = convertPath('/sdk/lib/core/core.dart');
83100

@@ -142,7 +159,7 @@ var a = ^;
142159
void _assertComputedImportedLibraries(List<String> expected) {
143160
expected = expected.map(convertPath).toList();
144161
expect(
145-
_completionResult.computedImportedLibraries,
162+
_computer.computedImportedLibraries,
146163
unorderedEquals(expected),
147164
);
148165
}
@@ -174,7 +191,7 @@ var a = ^;
174191
_completionResult = await _newComputer().compute2(
175192
path: testPath,
176193
line: context.line,
177-
character: context.character,
194+
column: context.character,
178195
);
179196
_suggestions = _completionResult.suggestions;
180197
}
@@ -202,7 +219,11 @@ var a = ^;
202219
}
203220

204221
CiderCompletionComputer _newComputer() {
205-
return CiderCompletionComputer(logger, _completionCache, fileResolver);
222+
return _computer = CiderCompletionComputer(
223+
logger,
224+
_completionCache,
225+
fileResolver,
226+
);
206227
}
207228

208229
_CompletionContext _updateFile(String content) {

pkg/analyzer/lib/src/dart/micro/library_graph.dart

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,32 @@ class FileState {
8787

8888
LineInfo get lineInfo => LineInfo(unlinked2.lineStarts);
8989

90+
/// The resolved signature of the file, that depends on the [libraryCycle]
91+
/// signature, and the content of the file.
92+
String get resolvedSignature {
93+
var signatureBuilder = ApiSignature();
94+
signatureBuilder.addString(path);
95+
signatureBuilder.addBytes(libraryCycle.signature);
96+
97+
var content = getContent();
98+
signatureBuilder.addString(content);
99+
100+
return signatureBuilder.toHex();
101+
}
102+
90103
/// Return the [uri] string.
91104
String get uriStr => uri.toString();
92105

106+
/// Return the content of the file, the empty string if cannot be read.
107+
String getContent() {
108+
try {
109+
var resource = _fsState._resourceProvider.getFile(path);
110+
return resource.readAsStringSync();
111+
} catch (_) {
112+
return '';
113+
}
114+
}
115+
93116
void internal_setLibraryCycle(LibraryCycle cycle, String signature) {
94117
_libraryCycle = cycle;
95118
}
@@ -148,12 +171,7 @@ class FileState {
148171
}
149172

150173
if (bytes == null || bytes.isEmpty) {
151-
String content;
152-
try {
153-
content = _fsState._resourceProvider.getFile(path).readAsStringSync();
154-
} catch (_) {
155-
content = '';
156-
}
174+
var content = getContent();
157175
var unit = parse(AnalysisErrorListener.NULL_LISTENER, content);
158176
_fsState._logger.run('Create unlinked for $path', () {
159177
var unlinkedBuilder = serializeAstCiderUnlinked(_digest, unit);

pkg/analyzer/lib/src/dart/micro/resolve_file.dart

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ import 'package:collection/collection.dart';
4141
import 'package:meta/meta.dart';
4242
import 'package:yaml/yaml.dart';
4343

44+
class FileContext {
45+
final AnalysisOptionsImpl analysisOptions;
46+
final FileState file;
47+
48+
FileContext(this.analysisOptions, this.file);
49+
}
50+
4451
class FileResolver {
4552
final PerformanceLog logger;
4653
final ResourceProvider resourceProvider;
@@ -83,7 +90,7 @@ class FileResolver {
8390

8491
return logger.run('Get errors for $path', () {
8592
var fileContext = logger.run('Get file $path', () {
86-
return _createFileContext(path);
93+
return getFileContext(path);
8794
});
8895
var file = fileContext.file;
8996

@@ -127,10 +134,19 @@ class FileResolver {
127134
});
128135
}
129136

137+
FileContext getFileContext(String path) {
138+
var analysisOptions = _getAnalysisOptions(path);
139+
140+
_createContext(analysisOptions);
141+
142+
var file = fsState.getFileForPath(path);
143+
return FileContext(analysisOptions, file);
144+
}
145+
130146
String getLibraryLinkedSignature(String path) {
131147
_throwIfNotAbsoluteNormalizedPath(path);
132148

133-
var fileContext = _createFileContext(path);
149+
var fileContext = getFileContext(path);
134150
var file = fileContext.file;
135151
return file.libraryCycle.signatureStr;
136152
}
@@ -140,7 +156,7 @@ class FileResolver {
140156

141157
return logger.run('Resolve $path', () {
142158
var fileContext = logger.run('Get file $path', () {
143-
return _createFileContext(path);
159+
return getFileContext(path);
144160
});
145161
var file = fileContext.file;
146162

@@ -234,22 +250,20 @@ class FileResolver {
234250
}
235251

236252
if (analysisContext == null) {
237-
logger.run('Create AnalysisContext', () {
238-
var root = ContextRootImpl(
239-
resourceProvider,
240-
resourceProvider.getFolder(workspace.root),
241-
);
253+
var root = ContextRootImpl(
254+
resourceProvider,
255+
resourceProvider.getFolder(workspace.root),
256+
);
242257

243-
analysisContext = MicroAnalysisContextImpl(
244-
this,
245-
root,
246-
analysisOptions,
247-
DeclaredVariables(),
248-
sourceFactory,
249-
resourceProvider,
250-
workspace: workspace,
251-
);
252-
});
258+
analysisContext = MicroAnalysisContextImpl(
259+
this,
260+
root,
261+
analysisOptions,
262+
DeclaredVariables(),
263+
sourceFactory,
264+
resourceProvider,
265+
workspace: workspace,
266+
);
253267
}
254268

255269
if (libraryContext == null) {
@@ -265,15 +279,6 @@ class FileResolver {
265279
}
266280
}
267281

268-
_FileContext _createFileContext(String path) {
269-
var analysisOptions = _getAnalysisOptions(path);
270-
271-
_createContext(analysisOptions);
272-
273-
var file = fsState.getFileForPath(path);
274-
return _FileContext(analysisOptions, file);
275-
}
276-
277282
File _findOptionsFile(Folder folder) {
278283
while (folder != null) {
279284
File packagesFile =
@@ -359,13 +364,6 @@ class FileResolverTestView {
359364
}
360365
}
361366

362-
class _FileContext {
363-
final AnalysisOptionsImpl analysisOptions;
364-
final FileState file;
365-
366-
_FileContext(this.analysisOptions, this.file);
367-
}
368-
369367
class _LibraryContext {
370368
final PerformanceLog logger;
371369
final ResourceProvider resourceProvider;

0 commit comments

Comments
 (0)