Add documentation to completion metrics and clean up a bit of code

Change-Id: I612b5f5953bc0f8d94ad9976e55590097389c62e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210740
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Brian Wilkerson 2021-08-23 18:26:57 +00:00 committed by commit-bot@chromium.org
parent d6f4640c0d
commit 804109b3c6
2 changed files with 45 additions and 22 deletions

View file

@ -58,6 +58,32 @@ import 'output_utilities.dart';
import 'relevance_table_generator.dart';
import 'visitors.dart';
/// Completion metrics are computed by taking a single package and iterating
/// over the compilation units in the package. For each unit we visit the AST
/// structure to find all of the places where completion suggestions should be
/// offered (essentially, everywhere that there's a keyword or identifier). At
/// each location we compute the completion suggestions using the same code path
/// used by the analysis server. We then compare the suggestions against the
/// token that was actually at that location in the file.
///
/// This approach has several drawbacks:
///
/// - The AST is always complete and correct, and that's rarely the case for
/// real completion requests. Usually the tree is incomplete and often has a
/// completely different structure because of the way recovery works. We
/// currently have no way of measuring completions under realistic conditions.
///
/// - We can't measure completions for several keywords because the presence of
/// the keyword in the AST causes it to not be suggested.
///
/// - The time it takes to compute the suggestions doesn't include the time
/// required to finish analyzing the file if the analysis hasn't been
/// completed before suggestions are requested. While the times are accurate
/// (within the accuracy of the `Stopwatch` class) they are the minimum
/// possible time. This doesn't give us a measure of how completion will
/// perform in production, but does give us an optimistic approximation.
///
/// The first is arguably the worst of the limitations of our current approach.
Future<void> main(List<String> args) async {
var parser = createArgParser();
var result = parser.parse(args);
@ -1318,7 +1344,7 @@ class CompletionMetricsComputer {
var filePath = result.path;
// Use the ExpectedCompletionsVisitor to compute the set of expected
// completions for this CompilationUnit.
final visitor = ExpectedCompletionsVisitor(filePath);
final visitor = ExpectedCompletionsVisitor(result);
_resolvedUnitResult.unit.accept(visitor);
for (var expectedCompletion in visitor.expectedCompletions) {

View file

@ -5,11 +5,13 @@
import 'package:analysis_server/src/protocol/protocol_internal.dart';
import 'package:analysis_server/src/protocol_server.dart' as protocol;
import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart' as element;
import 'package:analyzer/source/line_info.dart';
class ExpectedCompletion {
final String _filePath;
@ -122,11 +124,12 @@ class ExpectedCompletion {
}
class ExpectedCompletionsVisitor extends RecursiveAstVisitor<void> {
final List<ExpectedCompletion> expectedCompletions;
/// The result of resolving the file being visited.
final ResolvedUnitResult result;
final String filePath;
late CompilationUnit _enclosingCompilationUnit;
/// The completions that are expected to be produced in the file being
/// visited.
final List<ExpectedCompletion> expectedCompletions = [];
/// This boolean is set to enable whether or not we should assert that some
/// found keyword in Dart syntax should be in the completion set returned from
@ -141,22 +144,22 @@ class ExpectedCompletionsVisitor extends RecursiveAstVisitor<void> {
/// comment don't yield an error like Dart syntax mistakes would yield.
final bool _doExpectCommentRefs = false;
ExpectedCompletionsVisitor(this.filePath)
: expectedCompletions = <ExpectedCompletion>[];
ExpectedCompletionsVisitor(this.result);
/// Return the path of the file that is being visited.
String get filePath => result.path;
/// Return the line info for the file that is being visited.
LineInfo get lineInfo => result.lineInfo;
void safelyRecordEntity(SyntacticEntity? entity,
{protocol.CompletionSuggestionKind? kind,
protocol.ElementKind? elementKind}) {
// Only record if this entity is not null, has a length, etc.
if (entity != null && entity.offset > 0 && entity.length > 0) {
// Compute the line number at this offset
var lineNumber = _enclosingCompilationUnit.lineInfo!
.getLocation(entity.offset)
.lineNumber;
var columnNumber = _enclosingCompilationUnit.lineInfo!
.getLocation(entity.offset)
.columnNumber;
if (entity != null && entity.offset >= 0 && entity.length > 0) {
var location = lineInfo.getLocation(entity.offset);
var lineNumber = location.lineNumber;
var columnNumber = location.columnNumber;
bool isKeyword() => kind == protocol.CompletionSuggestionKind.KEYWORD;
@ -314,12 +317,6 @@ class ExpectedCompletionsVisitor extends RecursiveAstVisitor<void> {
super.visitClassTypeAlias(node);
}
@override
void visitCompilationUnit(CompilationUnit node) {
_enclosingCompilationUnit = node;
super.visitCompilationUnit(node);
}
@override
void visitConfiguration(Configuration node) {
safelyRecordKeywordCompletion(node.ifKeyword);