mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:40:07 +00:00
Cache documentation comments to improve completion performance
I'm not convinced that this is the right way to cache comments, so feedback is welcome. Change-Id: I2bd393b80e05c26199020e19daf0eadeb99d8c2b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/199303 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
04fb485fd5
commit
b42c5c77d4
|
@ -685,6 +685,7 @@ class ServerContextManagerCallbacks extends ContextManagerCallbacks {
|
|||
_notificationManager.recordAnalysisErrors(NotificationManager.serverId,
|
||||
path, server.doAnalysisError_listFromEngine(result));
|
||||
}
|
||||
analysisServer.getDocumentationCacheFor(result)?.cacheFromResult(result);
|
||||
var unit = result.unit;
|
||||
if (unit != null) {
|
||||
if (analysisServer._hasAnalysisServiceSubscription(
|
||||
|
|
|
@ -15,6 +15,7 @@ import 'package:analysis_server/src/plugin/plugin_manager.dart';
|
|||
import 'package:analysis_server/src/plugin/plugin_watcher.dart';
|
||||
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
|
||||
import 'package:analysis_server/src/server/diagnostic_server.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
|
||||
import 'package:analysis_server/src/services/correction/namespace.dart';
|
||||
import 'package:analysis_server/src/services/pub/pub_api.dart';
|
||||
import 'package:analysis_server/src/services/pub/pub_package_service.dart';
|
||||
|
@ -25,6 +26,7 @@ import 'package:analysis_server/src/utilities/file_string_sink.dart';
|
|||
import 'package:analysis_server/src/utilities/null_string_sink.dart';
|
||||
import 'package:analysis_server/src/utilities/request_statistics.dart';
|
||||
import 'package:analysis_server/src/utilities/tee_string_sink.dart';
|
||||
import 'package:analyzer/dart/analysis/analysis_context.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
|
@ -83,6 +85,10 @@ abstract class AbstractAnalysisServer {
|
|||
DeclarationsTracker? declarationsTracker;
|
||||
DeclarationsTrackerData? declarationsTrackerData;
|
||||
|
||||
/// A map from analysis contexts to the documentation cache associated with
|
||||
/// each context.
|
||||
Map<AnalysisContext, DocumentationCache> documentationForContext = {};
|
||||
|
||||
/// The DiagnosticServer for this AnalysisServer. If available, it can be used
|
||||
/// to start an http diagnostics server or return the port for an existing
|
||||
/// server.
|
||||
|
@ -217,6 +223,7 @@ abstract class AbstractAnalysisServer {
|
|||
|
||||
void addContextsToDeclarationsTracker() {
|
||||
declarationsTracker?.discardContexts();
|
||||
documentationForContext.clear();
|
||||
for (var driver in driverMap.values) {
|
||||
declarationsTracker?.addContext(driver.analysisContext!);
|
||||
driver.resetUriResolution();
|
||||
|
@ -275,6 +282,19 @@ abstract class AbstractAnalysisServer {
|
|||
DartdocDirectiveInfo();
|
||||
}
|
||||
|
||||
/// Return the object used to cache the documentation for elements in the
|
||||
/// context that produced the [result], or `null` if there is no cache for the
|
||||
/// context.
|
||||
DocumentationCache? getDocumentationCacheFor(ResolvedUnitResult result) {
|
||||
var context = result.session.analysisContext;
|
||||
var tracker = declarationsTracker?.getContext(context);
|
||||
if (tracker == null) {
|
||||
return null;
|
||||
}
|
||||
return documentationForContext.putIfAbsent(
|
||||
context, () => DocumentationCache(tracker.dartdocDirectiveInfo));
|
||||
}
|
||||
|
||||
/// Return a [Future] that completes with the [Element] at the given
|
||||
/// [offset] of the given [file], or with `null` if there is no node at the
|
||||
/// [offset] or the node does not have an element.
|
||||
|
|
|
@ -108,7 +108,9 @@ class CompletionDomainHandler extends AbstractRequestHandler {
|
|||
await perf.runAsync(contributorTag, (performance) async {
|
||||
try {
|
||||
suggestions.addAll(
|
||||
await manager.computeSuggestions(performance, request),
|
||||
await manager.computeSuggestions(performance, request,
|
||||
documentationCache:
|
||||
server.getDocumentationCacheFor(request.result)),
|
||||
);
|
||||
} on AbortCompletion {
|
||||
suggestions.clear();
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:analysis_server/src/services/completion/completion_core.dart';
|
|||
import 'package:analysis_server/src/services/completion/completion_performance.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/arglist_contributor.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/combinator_contributor.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/extension_member_contributor.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/field_formal_contributor.dart';
|
||||
|
@ -93,6 +94,7 @@ class DartCompletionManager {
|
|||
bool enableOverrideContributor = true,
|
||||
bool enableUriContributor = true,
|
||||
CompletionPreference? completionPreference,
|
||||
DocumentationCache? documentationCache,
|
||||
}) async {
|
||||
request.checkAborted();
|
||||
var pathContext = request.resourceProvider.pathContext;
|
||||
|
@ -105,6 +107,7 @@ class DartCompletionManager {
|
|||
request,
|
||||
dartdocDirectiveInfo,
|
||||
completionPreference: completionPreference,
|
||||
documentationCache: documentationCache,
|
||||
);
|
||||
|
||||
// Don't suggest in comments.
|
||||
|
@ -297,6 +300,8 @@ class DartCompletionRequestImpl implements DartCompletionRequest {
|
|||
@override
|
||||
final CompletionPreference completionPreference;
|
||||
|
||||
final DocumentationCache? documentationCache;
|
||||
|
||||
DartCompletionRequestImpl._(
|
||||
this.result,
|
||||
this.resourceProvider,
|
||||
|
@ -308,7 +313,8 @@ class DartCompletionRequestImpl implements DartCompletionRequest {
|
|||
this.dartdocDirectiveInfo,
|
||||
this._originalRequest,
|
||||
this.performance,
|
||||
{CompletionPreference? completionPreference})
|
||||
{CompletionPreference? completionPreference,
|
||||
this.documentationCache})
|
||||
: featureComputer =
|
||||
FeatureComputer(result.typeSystem, result.typeProvider),
|
||||
completionPreference =
|
||||
|
@ -431,7 +437,8 @@ class DartCompletionRequestImpl implements DartCompletionRequest {
|
|||
OperationPerformanceImpl performance,
|
||||
CompletionRequest request,
|
||||
DartdocDirectiveInfo? dartdocDirectiveInfo,
|
||||
{CompletionPreference? completionPreference}) async {
|
||||
{CompletionPreference? completionPreference,
|
||||
DocumentationCache? documentationCache}) async {
|
||||
request.checkAborted();
|
||||
|
||||
return performance.run(
|
||||
|
@ -453,6 +460,7 @@ class DartCompletionRequestImpl implements DartCompletionRequest {
|
|||
request,
|
||||
(request as CompletionRequestImpl).performance,
|
||||
completionPreference: completionPreference,
|
||||
documentationCache: documentationCache,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
// Copyright (c) 2021, 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/src/computer/computer_hover.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
|
||||
|
||||
/// Cached data about the documentation associated with the elements declared in
|
||||
/// a single analysis context.
|
||||
class DocumentationCache {
|
||||
/// A shared instance for elements that have no documentation.
|
||||
static final DocumentationWithSummary _emptyDocs =
|
||||
DocumentationWithSummary(full: '', summary: '');
|
||||
|
||||
/// The object used to compute the documentation associated with a single
|
||||
/// element.
|
||||
final DartdocDirectiveInfo dartdocDirectiveInfo;
|
||||
|
||||
/// The documentation associated with the elements that have been cached. The
|
||||
/// cache is keyed by the path of the file containing the declaration of the
|
||||
/// element and the qualified name of the element.
|
||||
final Map<String, Map<String, DocumentationWithSummary>> documentationCache =
|
||||
{};
|
||||
|
||||
/// Initialize a newly created cache.
|
||||
DocumentationCache(this.dartdocDirectiveInfo);
|
||||
|
||||
/// Fill the cache with data from the [result].
|
||||
void cacheFromResult(ResolvedUnitResult result) {
|
||||
var element = result.unit?.declaredElement;
|
||||
if (element != null) {
|
||||
_cacheFromElement(element);
|
||||
for (var library in result.libraryElement.importedLibraries) {
|
||||
_cacheLibrary(library);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the data cached for the given [element], or `null` if there is no
|
||||
/// cached data.
|
||||
DocumentationWithSummary? dataFor(Element element) {
|
||||
var parent = element.enclosingElement;
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
var key = element.name;
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
if (parent is! CompilationUnitElement) {
|
||||
var parentName = parent.name;
|
||||
if (parentName == null) {
|
||||
return null;
|
||||
}
|
||||
key = '$parentName.$key';
|
||||
parent = parent.enclosingElement;
|
||||
}
|
||||
if (parent is CompilationUnitElement) {
|
||||
var elementMap = documentationCache[_keyForUnit(parent)];
|
||||
return elementMap?[key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Fill the cache with data from the [compilationUnit].
|
||||
void _cacheFromElement(CompilationUnitElement compilationUnit) {
|
||||
var elementMap =
|
||||
documentationCache.putIfAbsent(_keyForUnit(compilationUnit), () => {});
|
||||
for (var element in compilationUnit.accessors) {
|
||||
if (!element.isSynthetic) {
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
}
|
||||
}
|
||||
for (var element in compilationUnit.enums) {
|
||||
var parentKey =
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
if (parentKey != null) {
|
||||
for (var member in element.fields) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var element in compilationUnit.extensions) {
|
||||
var parentKey =
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
if (parentKey != null) {
|
||||
for (var member in element.accessors) {
|
||||
if (!element.isSynthetic) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
for (var member in element.fields) {
|
||||
if (!element.isSynthetic) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
for (var member in element.methods) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var element in compilationUnit.functions) {
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
}
|
||||
for (var element in [...compilationUnit.mixins, ...compilationUnit.types]) {
|
||||
var parentKey =
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
if (parentKey != null) {
|
||||
for (var member in element.accessors) {
|
||||
if (!element.isSynthetic) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
for (var member in element.fields) {
|
||||
if (!element.isSynthetic) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
for (var member in element.methods) {
|
||||
elementMap.cacheMember(dartdocDirectiveInfo, parentKey, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var element in compilationUnit.topLevelVariables) {
|
||||
if (!element.isSynthetic) {
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
}
|
||||
}
|
||||
for (var element in compilationUnit.typeAliases) {
|
||||
elementMap.cacheTopLevelElement(dartdocDirectiveInfo, element);
|
||||
}
|
||||
}
|
||||
|
||||
/// Cache the data for the given [library] and every library exported from it
|
||||
/// if it hasn't already been cached.
|
||||
void _cacheLibrary(LibraryElement library) {
|
||||
if (_hasDataFor(library.definingCompilationUnit)) {
|
||||
return;
|
||||
}
|
||||
for (var unit in library.units) {
|
||||
_cacheFromElement(unit);
|
||||
}
|
||||
for (var exported in library.exportedLibraries) {
|
||||
_cacheLibrary(exported);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the cache contains data for the [compilationUnit].
|
||||
bool _hasDataFor(CompilationUnitElement compilationUnit) {
|
||||
return documentationCache.containsKey(_keyForUnit(compilationUnit));
|
||||
}
|
||||
|
||||
/// Return the key used in the [documentationCache] for the [compilationUnit].
|
||||
String _keyForUnit(CompilationUnitElement compilationUnit) =>
|
||||
compilationUnit.source.fullName;
|
||||
}
|
||||
|
||||
extension on Map<String, DocumentationWithSummary> {
|
||||
/// Cache the data associated with the top-level [element], and return the
|
||||
/// [key] used for the element. This does not cache any data associated with
|
||||
/// any other elements, including children of the [element].
|
||||
String? cacheTopLevelElement(
|
||||
DartdocDirectiveInfo dartdocDirectiveInfo, Element element) {
|
||||
var key = element.name;
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
cacheElement(dartdocDirectiveInfo, key, element);
|
||||
return key;
|
||||
}
|
||||
|
||||
/// Cache the data associated with the [member] element given that the key
|
||||
/// associated with the member's parent is [parentKey].
|
||||
void cacheMember(DartdocDirectiveInfo dartdocDirectiveInfo, String parentKey,
|
||||
Element member) {
|
||||
var name = member.name;
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
cacheElement(dartdocDirectiveInfo, '$parentKey.$name', member);
|
||||
}
|
||||
|
||||
/// Cache the data associated with the [element], using the given [key].
|
||||
DocumentationWithSummary? cacheElement(
|
||||
DartdocDirectiveInfo dartdocDirectiveInfo, String key, Element element) {
|
||||
var documentation = DartUnitHoverComputer.computeDocumentation(
|
||||
dartdocDirectiveInfo, element,
|
||||
includeSummary: true);
|
||||
if (documentation is DocumentationWithSummary) {
|
||||
return this[key] = documentation;
|
||||
}
|
||||
return this[key] = DocumentationCache._emptyDocs;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import 'package:analysis_server/src/protocol_server.dart' as protocol;
|
|||
import 'package:analysis_server/src/protocol_server.dart'
|
||||
hide Element, ElementKind;
|
||||
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
|
||||
import 'package:analysis_server/src/utilities/extensions/ast.dart';
|
||||
|
@ -1110,6 +1111,16 @@ class SuggestionBuilder {
|
|||
/// If the [element] has a documentation comment, fill the [suggestion]'s
|
||||
/// documentation fields.
|
||||
void _setDocumentation(CompletionSuggestion suggestion, Element element) {
|
||||
final request = this.request;
|
||||
if (request is DartCompletionRequestImpl) {
|
||||
var documentationCache = request.documentationCache;
|
||||
var data = documentationCache?.dataFor(element);
|
||||
if (data != null) {
|
||||
suggestion.docComplete = data.full;
|
||||
suggestion.docSummary = data.summary;
|
||||
return;
|
||||
}
|
||||
}
|
||||
var doc = DartUnitHoverComputer.computeDocumentation(
|
||||
request.dartdocDirectiveInfo, element,
|
||||
includeSummary: true);
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:analysis_server/src/protocol_server.dart' as protocol;
|
|||
import 'package:analysis_server/src/services/completion/completion_core.dart';
|
||||
import 'package:analysis_server/src/services/completion/completion_performance.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/probability_range.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/relevance_tables.g.dart';
|
||||
|
@ -1034,6 +1035,8 @@ class CompletionMetricsComputer {
|
|||
MetricsSuggestionListener listener,
|
||||
OperationPerformanceImpl performance,
|
||||
CompletionRequestImpl request,
|
||||
DartdocDirectiveInfo dartdocDirectiveInfo,
|
||||
DocumentationCache? documentationCache,
|
||||
[DeclarationsTracker? declarationsTracker,
|
||||
protocol.CompletionAvailableSuggestionsParams?
|
||||
availableSuggestionsParams]) async {
|
||||
|
@ -1042,9 +1045,10 @@ class CompletionMetricsComputer {
|
|||
if (declarationsTracker == null) {
|
||||
// available suggestions == false
|
||||
suggestions = await DartCompletionManager(
|
||||
dartdocDirectiveInfo: DartdocDirectiveInfo(),
|
||||
dartdocDirectiveInfo: dartdocDirectiveInfo,
|
||||
listener: listener,
|
||||
).computeSuggestions(performance, request);
|
||||
).computeSuggestions(performance, request,
|
||||
documentationCache: documentationCache);
|
||||
} else {
|
||||
// available suggestions == true
|
||||
var includedElementKinds = <protocol.ElementKind>{};
|
||||
|
@ -1053,12 +1057,13 @@ class CompletionMetricsComputer {
|
|||
<protocol.IncludedSuggestionRelevanceTag>[];
|
||||
var includedSuggestionSetList = <protocol.IncludedSuggestionSet>[];
|
||||
suggestions = await DartCompletionManager(
|
||||
dartdocDirectiveInfo: DartdocDirectiveInfo(),
|
||||
dartdocDirectiveInfo: dartdocDirectiveInfo,
|
||||
includedElementKinds: includedElementKinds,
|
||||
includedElementNames: includedElementNames,
|
||||
includedSuggestionRelevanceTags: includedSuggestionRelevanceTagList,
|
||||
listener: listener,
|
||||
).computeSuggestions(performance, request);
|
||||
).computeSuggestions(performance, request,
|
||||
documentationCache: documentationCache);
|
||||
|
||||
computeIncludedSetList(declarationsTracker, request.result,
|
||||
includedSuggestionSetList, includedElementNames);
|
||||
|
@ -1141,118 +1146,26 @@ class CompletionMetricsComputer {
|
|||
|
||||
// Loop through each file, resolve the file and call
|
||||
// forEachExpectedCompletion
|
||||
|
||||
var dartdocDirectiveInfo = DartdocDirectiveInfo();
|
||||
var documentationCache = DocumentationCache(dartdocDirectiveInfo);
|
||||
var results = <ResolvedUnitResult>[];
|
||||
var pathContext = context.contextRoot.resourceProvider.pathContext;
|
||||
for (var filePath in context.contextRoot.analyzedFiles()) {
|
||||
if (file_paths.isDart(pathContext, filePath)) {
|
||||
try {
|
||||
_resolvedUnitResult = await context.currentSession
|
||||
.getResolvedUnit2(filePath) as ResolvedUnitResult;
|
||||
var result = await context.currentSession.getResolvedUnit2(filePath)
|
||||
as ResolvedUnitResult;
|
||||
|
||||
var analysisError = getFirstErrorOrNull(_resolvedUnitResult);
|
||||
var analysisError = getFirstErrorOrNull(result);
|
||||
if (analysisError != null) {
|
||||
print('File $filePath skipped due to errors such as:');
|
||||
print(' ${analysisError.toString()}');
|
||||
print('');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use the ExpectedCompletionsVisitor to compute the set of expected
|
||||
// completions for this CompilationUnit.
|
||||
final visitor = ExpectedCompletionsVisitor(filePath);
|
||||
_resolvedUnitResult.unit!.accept(visitor);
|
||||
|
||||
for (var expectedCompletion in visitor.expectedCompletions) {
|
||||
var resolvedUnitResult = _resolvedUnitResult;
|
||||
|
||||
// If an overlay option is being used, compute the overlay file, and
|
||||
// have the context reanalyze the file
|
||||
if (options.overlay != CompletionMetricsOptions.OVERLAY_NONE) {
|
||||
var overlayContents = _getOverlayContents(
|
||||
_resolvedUnitResult.content!, expectedCompletion);
|
||||
|
||||
_provider.setOverlay(filePath,
|
||||
content: overlayContents,
|
||||
modificationStamp: overlayModificationStamp++);
|
||||
context.driver.changeFile(filePath);
|
||||
resolvedUnitResult = await context.currentSession
|
||||
.getResolvedUnit2(filePath) as ResolvedUnitResult;
|
||||
}
|
||||
|
||||
// As this point the completion suggestions are computed,
|
||||
// and results are collected with varying settings for
|
||||
// comparison:
|
||||
|
||||
Future<int> handleExpectedCompletion(
|
||||
{required MetricsSuggestionListener listener,
|
||||
required CompletionMetrics metrics}) async {
|
||||
var stopwatch = Stopwatch()..start();
|
||||
var request = CompletionRequestImpl(
|
||||
resolvedUnitResult,
|
||||
expectedCompletion.offset,
|
||||
CompletionPerformance(),
|
||||
);
|
||||
var directiveInfo = DartdocDirectiveInfo();
|
||||
|
||||
late OpType opType;
|
||||
late List<protocol.CompletionSuggestion> suggestions;
|
||||
await request.performance.runRequestOperation(
|
||||
(performance) async {
|
||||
var dartRequest = await DartCompletionRequestImpl.from(
|
||||
performance, request, directiveInfo);
|
||||
opType =
|
||||
OpType.forCompletion(dartRequest.target, request.offset);
|
||||
suggestions = await _computeCompletionSuggestions(
|
||||
listener,
|
||||
performance,
|
||||
request,
|
||||
metrics.availableSuggestions ? declarationsTracker : null,
|
||||
metrics.availableSuggestions
|
||||
? availableSuggestionsParams
|
||||
: null,
|
||||
);
|
||||
},
|
||||
);
|
||||
stopwatch.stop();
|
||||
|
||||
return forEachExpectedCompletion(
|
||||
request,
|
||||
listener,
|
||||
expectedCompletion,
|
||||
opType.completionLocation,
|
||||
suggestions,
|
||||
metrics,
|
||||
stopwatch.elapsedMilliseconds);
|
||||
}
|
||||
|
||||
var bestRank = -1;
|
||||
var bestName = '';
|
||||
var defaultTag = getCurrentTag();
|
||||
for (var metrics in targetMetrics) {
|
||||
// Compute the completions.
|
||||
metrics.enable();
|
||||
metrics.userTag.makeCurrent();
|
||||
// if (FeatureComputer.noDisabledFeatures) {
|
||||
// var line = expectedCompletion.lineNumber;
|
||||
// var column = expectedCompletion.columnNumber;
|
||||
// print('$filePath:$line:$column');
|
||||
// }
|
||||
var listener = MetricsSuggestionListener();
|
||||
var rank = await handleExpectedCompletion(
|
||||
listener: listener, metrics: metrics);
|
||||
if (bestRank < 0 || rank < bestRank) {
|
||||
bestRank = rank;
|
||||
bestName = metrics.name;
|
||||
}
|
||||
defaultTag.makeCurrent();
|
||||
metrics.disable();
|
||||
}
|
||||
rankComparison.count(bestName);
|
||||
|
||||
// If an overlay option is being used, remove the overlay applied
|
||||
// earlier
|
||||
if (options.overlay != CompletionMetricsOptions.OVERLAY_NONE) {
|
||||
_provider.removeOverlay(filePath);
|
||||
}
|
||||
} else {
|
||||
results.add(result);
|
||||
documentationCache.cacheFromResult(result);
|
||||
}
|
||||
} catch (exception, stackTrace) {
|
||||
print('Exception caught analyzing: $filePath');
|
||||
|
@ -1261,6 +1174,104 @@ class CompletionMetricsComputer {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (var result in results) {
|
||||
_resolvedUnitResult = result;
|
||||
var filePath = result.path!;
|
||||
// Use the ExpectedCompletionsVisitor to compute the set of expected
|
||||
// completions for this CompilationUnit.
|
||||
final visitor = ExpectedCompletionsVisitor(filePath);
|
||||
_resolvedUnitResult.unit!.accept(visitor);
|
||||
|
||||
for (var expectedCompletion in visitor.expectedCompletions) {
|
||||
var resolvedUnitResult = _resolvedUnitResult;
|
||||
|
||||
// If an overlay option is being used, compute the overlay file, and
|
||||
// have the context reanalyze the file
|
||||
if (options.overlay != CompletionMetricsOptions.OVERLAY_NONE) {
|
||||
var overlayContents = _getOverlayContents(
|
||||
_resolvedUnitResult.content!, expectedCompletion);
|
||||
|
||||
_provider.setOverlay(filePath,
|
||||
content: overlayContents,
|
||||
modificationStamp: overlayModificationStamp++);
|
||||
context.driver.changeFile(filePath);
|
||||
resolvedUnitResult = await context.currentSession
|
||||
.getResolvedUnit2(filePath) as ResolvedUnitResult;
|
||||
}
|
||||
|
||||
// As this point the completion suggestions are computed,
|
||||
// and results are collected with varying settings for
|
||||
// comparison:
|
||||
|
||||
Future<int> handleExpectedCompletion(
|
||||
{required MetricsSuggestionListener listener,
|
||||
required CompletionMetrics metrics}) async {
|
||||
var stopwatch = Stopwatch()..start();
|
||||
var request = CompletionRequestImpl(
|
||||
resolvedUnitResult,
|
||||
expectedCompletion.offset,
|
||||
CompletionPerformance(),
|
||||
);
|
||||
var directiveInfo = DartdocDirectiveInfo();
|
||||
|
||||
late OpType opType;
|
||||
late List<protocol.CompletionSuggestion> suggestions;
|
||||
await request.performance.runRequestOperation(
|
||||
(performance) async {
|
||||
var dartRequest = await DartCompletionRequestImpl.from(
|
||||
performance, request, directiveInfo);
|
||||
opType = OpType.forCompletion(dartRequest.target, request.offset);
|
||||
suggestions = await _computeCompletionSuggestions(
|
||||
listener,
|
||||
performance,
|
||||
request,
|
||||
dartdocDirectiveInfo,
|
||||
documentationCache,
|
||||
metrics.availableSuggestions ? declarationsTracker : null,
|
||||
metrics.availableSuggestions
|
||||
? availableSuggestionsParams
|
||||
: null,
|
||||
);
|
||||
},
|
||||
);
|
||||
stopwatch.stop();
|
||||
|
||||
return forEachExpectedCompletion(
|
||||
request,
|
||||
listener,
|
||||
expectedCompletion,
|
||||
opType.completionLocation,
|
||||
suggestions,
|
||||
metrics,
|
||||
stopwatch.elapsedMilliseconds);
|
||||
}
|
||||
|
||||
var bestRank = -1;
|
||||
var bestName = '';
|
||||
var defaultTag = getCurrentTag();
|
||||
for (var metrics in targetMetrics) {
|
||||
// Compute the completions.
|
||||
metrics.enable();
|
||||
metrics.userTag.makeCurrent();
|
||||
var listener = MetricsSuggestionListener();
|
||||
var rank = await handleExpectedCompletion(
|
||||
listener: listener, metrics: metrics);
|
||||
if (bestRank < 0 || rank < bestRank) {
|
||||
bestRank = rank;
|
||||
bestName = metrics.name;
|
||||
}
|
||||
defaultTag.makeCurrent();
|
||||
metrics.disable();
|
||||
}
|
||||
rankComparison.count(bestName);
|
||||
|
||||
// If an overlay option is being used, remove the overlay applied
|
||||
// earlier.
|
||||
if (options.overlay != CompletionMetricsOptions.OVERLAY_NONE) {
|
||||
_provider.removeOverlay(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<protocol.CompletionSuggestion> _filterSuggestions(
|
||||
|
|
|
@ -177,7 +177,7 @@ class DartdocDirectiveInfo {
|
|||
}
|
||||
start = eolIndex + 1;
|
||||
}
|
||||
if (lastNonEmpty < firstNonEmpty) {
|
||||
if (firstNonEmpty < 0 || lastNonEmpty < firstNonEmpty) {
|
||||
// All of the lines are empty.
|
||||
return const <String>[];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue