Migrate the first round of completion support

Change-Id: I64ca0b7b6d3040b6e37d328ed62e75059c48ef07
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194212
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Brian Wilkerson
2021-04-07 20:44:58 +00:00
committed by commit-bot@chromium.org
parent f4a9cad199
commit a0f7ff92a1
17 changed files with 190 additions and 212 deletions
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -52,7 +50,7 @@ abstract class CompletionRequest {
/// Return the content of the [source] in which the completion is being
/// requested, or `null` if the content could not be accessed.
String get sourceContents;
String? get sourceContents;
/// Throw [AbortCompletion] if the completion request has been aborted.
void checkAborted();
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analyzer/dart/analysis/results.dart';
@@ -46,10 +44,10 @@ class CompletionRequestImpl implements CompletionRequest {
ResourceProvider get resourceProvider => result.session.resourceProvider;
@override
Source get source => result.unit.declaredElement.source;
Source get source => result.unit!.declaredElement!.source;
@override
String get sourceContents => result?.content;
String? get sourceContents => result.content;
/// Abort the current completion request.
void abort() {
@@ -2,19 +2,14 @@
// 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.
// @dart = 2.9
import 'package:analyzer/src/util/performance/operation_performance.dart';
/// Compute a string representing a code completion operation at the
/// given source and location.
///
/// This string is useful for displaying to users in a diagnostic context.
String computeCompletionSnippet(String contents, int offset) {
if (contents == null ||
offset == null ||
offset < 0 ||
contents.length < offset) {
String _computeCompletionSnippet(String contents, int offset) {
if (offset < 0 || contents.length < offset) {
return '???';
}
var start = offset;
@@ -40,13 +35,17 @@ String computeCompletionSnippet(String contents, int offset) {
/// Overall performance of a code completion operation.
class CompletionPerformance {
String path;
String? path;
String snippet = '';
int suggestionCount = -1;
OperationPerformanceImpl _operation;
OperationPerformance? _operation;
int get elapsedInMilliseconds {
return _operation.elapsed.inMilliseconds;
var operation = _operation;
if (operation == null) {
throw StateError('Access of elapsed time before the operation is run');
}
return operation.elapsed.inMilliseconds;
}
String get suggestionCountStr {
@@ -68,6 +67,6 @@ class CompletionPerformance {
}
void setContentsAndOffset(String contents, int offset) {
snippet = computeCompletionSnippet(contents, offset);
snippet = _computeCompletionSnippet(contents, offset);
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
/// Utility methods to compute the value of the features used for code
/// completion.
import 'dart:math' as math;
@@ -46,27 +44,6 @@ const List<String> stringNames = [
'string'
];
DartType impliedDartTypeWithName(TypeProvider typeProvider, String name) {
if (typeProvider == null || name == null || name.isEmpty) {
return null;
}
if (intNames.contains(name)) {
return typeProvider.intType;
} else if (numNames.contains(name)) {
return typeProvider.numType;
} else if (listNames.contains(name)) {
return typeProvider.listType(typeProvider.dynamicType);
} else if (stringNames.contains(name)) {
return typeProvider.stringType;
} else if (name == 'iterator') {
return typeProvider.iterableDynamicType;
} else if (name == 'map') {
return typeProvider.mapType(
typeProvider.dynamicType, typeProvider.dynamicType);
}
return null;
}
/// Convert a relevance score (assumed to be between `0.0` and `1.0` inclusive)
/// to a relevance value between `0` and `1000`.
int toRelevance(double score) {
@@ -106,6 +83,27 @@ double weightedAverage(
return (average + 1.0) / 2.0;
}
DartType? _impliedDartTypeWithName(TypeProvider typeProvider, String name) {
if (name.isEmpty) {
return null;
}
if (intNames.contains(name)) {
return typeProvider.intType;
} else if (numNames.contains(name)) {
return typeProvider.numType;
} else if (listNames.contains(name)) {
return typeProvider.listType(typeProvider.dynamicType);
} else if (stringNames.contains(name)) {
return typeProvider.stringType;
} else if (name == 'iterator') {
return typeProvider.iterableDynamicType;
} else if (name == 'map') {
return typeProvider.mapType(
typeProvider.dynamicType, typeProvider.dynamicType);
}
return null;
}
/// Return the weighted average of the given [values], applying the given
/// [weights]. The number of weights must be equal to the number of values.
double _weightedAverage(List<double> values, List<double> weights) {
@@ -165,7 +163,7 @@ class FeatureComputer {
/// Return the type imposed when completing at the given [offset], where the
/// offset is within the given [node], or `null` if the context does not
/// impose any type.
DartType computeContextType(AstNode node, int offset) {
DartType? computeContextType(AstNode node, int offset) {
var type = node
.accept(_ContextTypeVisitor(typeProvider, offset))
?.resolveToBound(typeProvider.objectType);
@@ -193,7 +191,7 @@ class FeatureComputer {
} else if (element is FieldElement && element.isEnumConstant) {
return protocol.ElementKind.ENUM_CONSTANT;
} else if (element is PropertyAccessorElement) {
element = (element as PropertyAccessorElement).variable;
element = element.variable;
}
var kind = element.kind;
if (kind == ElementKind.CONSTRUCTOR) {
@@ -229,7 +227,7 @@ class FeatureComputer {
/// Return the value of the _context type_ feature for an element with the
/// given [elementType] when completing in a location with the given
/// [contextType].
double contextTypeFeature(DartType contextType, DartType elementType) {
double contextTypeFeature(DartType? contextType, DartType? elementType) {
if (contextType == null || elementType == null) {
// Disable the feature if we don't have both types.
return 0.0;
@@ -252,8 +250,8 @@ class FeatureComputer {
/// Return the value of the _element kind_ feature for the [element] when
/// completing at the given [completionLocation]. If a [distance] is given it
/// will be used to provide finer-grained relevance scores.
double elementKindFeature(Element element, String completionLocation,
{double distance}) {
double elementKindFeature(Element element, String? completionLocation,
{double? distance}) {
if (completionLocation == null) {
return 0.0;
}
@@ -327,7 +325,7 @@ class FeatureComputer {
/// Return the value of the _keyword_ feature for the [keyword] when
/// completing at the given [completionLocation].
double keywordFeature(String keyword, String completionLocation) {
double keywordFeature(String keyword, String? completionLocation) {
if (completionLocation == null) {
return 0.0;
}
@@ -357,7 +355,7 @@ class FeatureComputer {
/// declarations between the local variable and the reference.
int localVariableDistance(AstNode reference, LocalVariableElement variable) {
var distance = 0;
var node = reference;
AstNode? node = reference;
while (node != null) {
if (node is ForStatement || node is ForElement) {
var loopParts = node is ForStatement
@@ -440,7 +438,7 @@ class FeatureComputer {
/// Return the value of the _super matches_ feature.
double superMatchesFeature(
String containingMethodName, String proposedMemberName) =>
String? containingMethodName, String proposedMemberName) =>
containingMethodName == null
? 0.0
: (proposedMemberName == containingMethodName ? 1.0 : 0.0);
@@ -451,7 +449,7 @@ class FeatureComputer {
if (distance < 0) {
return 0.0;
}
return math.pow(0.9, distance);
return math.pow(0.9, distance) as double;
}
/// Return the inheritance distance between the [subclass] and the
@@ -459,7 +457,7 @@ class FeatureComputer {
/// cycles in the type graph.
///
/// This is the implementation of [inheritanceDistance].
int _inheritanceDistance(ClassElement subclass, ClassElement superclass,
int _inheritanceDistance(ClassElement? subclass, ClassElement superclass,
Set<ClassElement> visited) {
if (subclass == null) {
return -1;
@@ -504,7 +502,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
_ContextTypeVisitor(this.typeProvider, this.offset);
@override
DartType visitAdjacentStrings(AdjacentStrings node) {
DartType? visitAdjacentStrings(AdjacentStrings node) {
if (offset == node.offset) {
return _visitParent(node);
}
@@ -512,7 +510,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitArgumentList(ArgumentList node) {
DartType? visitArgumentList(ArgumentList node) {
if (range
.endStart(node.leftParenthesis, node.rightParenthesis)
.contains(offset)) {
@@ -523,7 +521,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
var index = 0;
DartType typeOfIndexPositionalParameter() {
DartType? typeOfIndexPositionalParameter() {
if (index < parameters.length) {
var parameter = parameters[index];
if (parameter.isPositional) {
@@ -533,7 +531,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
return null;
}
Expression previousArgument;
Expression? previousArgument;
for (var argument in node.arguments) {
if (argument is NamedExpression) {
if (offset <= argument.offset) {
@@ -560,7 +558,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitAsExpression(AsExpression node) {
DartType? visitAsExpression(AsExpression node) {
if (node.asOperator.end < offset) {
return node.expression.staticType;
}
@@ -568,10 +566,10 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitAssertInitializer(AssertInitializer node) {
DartType? visitAssertInitializer(AssertInitializer node) {
if (range
.endStart(node.leftParenthesis,
node.message?.beginToken?.previous ?? node.rightParenthesis)
node.message?.beginToken.previous ?? node.rightParenthesis)
.contains(offset)) {
return typeProvider.boolType;
}
@@ -579,10 +577,10 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitAssertStatement(AssertStatement node) {
DartType? visitAssertStatement(AssertStatement node) {
if (range
.endStart(node.leftParenthesis,
node.message?.beginToken?.previous ?? node.rightParenthesis)
node.message?.beginToken.previous ?? node.rightParenthesis)
.contains(offset)) {
return typeProvider.boolType;
}
@@ -590,7 +588,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitAssignmentExpression(AssignmentExpression node) {
DartType? visitAssignmentExpression(AssignmentExpression node) {
if (node.operator.end <= offset) {
// RHS
if (node.operator.type == TokenType.EQ) {
@@ -599,7 +597,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
var method = node.staticElement;
if (method != null) {
var parameters = method.parameters;
if (parameters != null && parameters.isNotEmpty) {
if (parameters.isNotEmpty) {
return parameters[0].type;
}
}
@@ -608,12 +606,12 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitAwaitExpression(AwaitExpression node) {
DartType? visitAwaitExpression(AwaitExpression node) {
return _visitParent(node);
}
@override
DartType visitBinaryExpression(BinaryExpression node) {
DartType? visitBinaryExpression(BinaryExpression node) {
if (node.operator.end <= offset) {
return node.rightOperand.staticParameterElement?.type;
}
@@ -621,15 +619,15 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitCascadeExpression(CascadeExpression node) {
if (node.target != null && offset == node.target.offset) {
DartType? visitCascadeExpression(CascadeExpression node) {
if (offset == node.target.offset) {
return _visitParent(node);
}
return null;
}
@override
DartType visitConditionalExpression(ConditionalExpression node) {
DartType? visitConditionalExpression(ConditionalExpression node) {
if (offset <= node.question.offset) {
return typeProvider.boolType;
} else {
@@ -638,8 +636,8 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
if (node.equals != null && node.equals.end <= offset) {
DartType? visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
if (node.equals.end <= offset) {
var element = node.fieldName.staticElement;
if (element is FieldElement) {
return element.type;
@@ -649,15 +647,16 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitDefaultFormalParameter(DefaultFormalParameter node) {
if (node.separator != null && node.separator.end <= offset) {
return node.parameter.declaredElement.type;
DartType? visitDefaultFormalParameter(DefaultFormalParameter node) {
var separator = node.separator;
if (separator != null && separator.end <= offset) {
return node.parameter.declaredElement?.type;
}
return null;
}
@override
DartType visitDoStatement(DoStatement node) {
DartType? visitDoStatement(DoStatement node) {
if (range
.endStart(node.leftParenthesis, node.rightParenthesis)
.contains(offset)) {
@@ -667,7 +666,7 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
}
@override
DartType visitExpressionFunctionBody(ExpressionFunctionBody node) {
DartType? visitExpressionFunctionBody(ExpressionFunctionBody node) {
if (range.endEnd(node.functionDefinition, node).contains(offset)) {
var parent = node.parent;
if (parent is MethodDeclaration) {
@@ -684,7 +683,7 @@ Class: ${parent.parent}
} else if (parent is FunctionExpression) {
var grandparent = parent.parent;
if (grandparent is FunctionDeclaration) {
return BodyInferenceContext.of(parent.body).contextType;
return BodyInferenceContext.of(parent.body)?.contextType;
}
return _visitParent(parent);
}
@@ -693,15 +692,15 @@ Class: ${parent.parent}
}
@override
DartType visitFieldDeclaration(FieldDeclaration node) {
if (node.fields != null && node.fields.contains(offset)) {
DartType? visitFieldDeclaration(FieldDeclaration node) {
if (node.fields.contains(offset)) {
return node.fields.accept(this);
}
return null;
}
@override
DartType visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
DartType? visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
if (range
.startOffsetEndOffset(node.inKeyword.end, node.end)
.contains(offset)) {
@@ -716,7 +715,7 @@ Class: ${parent.parent}
}
@override
DartType visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
DartType? visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
if (range.endEnd(node.inKeyword, node).contains(offset)) {
var parent = node.parent;
if ((parent is ForStatement && parent.awaitKeyword != null) ||
@@ -729,31 +728,27 @@ Class: ${parent.parent}
}
@override
DartType visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
if (node.leftSeparator != null &&
node.rightSeparator != null &&
range
.endStart(node.leftSeparator, node.rightSeparator)
.contains(offset)) {
DartType? visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
if (range
.endStart(node.leftSeparator, node.rightSeparator)
.contains(offset)) {
return typeProvider.boolType;
}
return null;
}
@override
DartType visitForPartsWithExpression(ForPartsWithExpression node) {
if (node.leftSeparator != null &&
node.rightSeparator != null &&
range
.endStart(node.leftSeparator, node.rightSeparator)
.contains(offset)) {
DartType? visitForPartsWithExpression(ForPartsWithExpression node) {
if (range
.endStart(node.leftSeparator, node.rightSeparator)
.contains(offset)) {
return typeProvider.boolType;
}
return null;
}
@override
DartType visitFunctionExpressionInvocation(
DartType? visitFunctionExpressionInvocation(
FunctionExpressionInvocation node) {
if (node.function.contains(offset)) {
return _visitParent(node);
@@ -762,7 +757,7 @@ Class: ${parent.parent}
}
@override
DartType visitIfElement(IfElement node) {
DartType? visitIfElement(IfElement node) {
if (range
.endStart(node.leftParenthesis, node.rightParenthesis)
.contains(offset)) {
@@ -772,7 +767,7 @@ Class: ${parent.parent}
}
@override
DartType visitIfStatement(IfStatement node) {
DartType? visitIfStatement(IfStatement node) {
if (range
.endStart(node.leftParenthesis, node.rightParenthesis)
.contains(offset)) {
@@ -782,7 +777,7 @@ Class: ${parent.parent}
}
@override
DartType visitIndexExpression(IndexExpression node) {
DartType? visitIndexExpression(IndexExpression node) {
if (range.endStart(node.leftBracket, node.rightBracket).contains(offset)) {
var parameters = node.staticElement?.parameters;
if (parameters != null && parameters.isNotEmpty) {
@@ -793,7 +788,7 @@ Class: ${parent.parent}
}
@override
DartType visitIsExpression(IsExpression node) {
DartType? visitIsExpression(IsExpression node) {
if (node.isOperator.end < offset) {
return node.expression.staticType;
}
@@ -801,7 +796,7 @@ Class: ${parent.parent}
}
@override
DartType visitLabel(Label node) {
DartType? visitLabel(Label node) {
if (offset == node.offset) {
return _visitParent(node);
}
@@ -812,7 +807,7 @@ Class: ${parent.parent}
}
@override
DartType visitListLiteral(ListLiteral node) {
DartType? visitListLiteral(ListLiteral node) {
if (range.endStart(node.leftBracket, node.rightBracket).contains(offset)) {
return (node.staticType as InterfaceType).typeArguments[0];
}
@@ -820,10 +815,11 @@ Class: ${parent.parent}
}
@override
DartType visitMapLiteralEntry(MapLiteralEntry node) {
DartType? visitMapLiteralEntry(MapLiteralEntry node) {
var literal = node.thisOrAncestorOfType<SetOrMapLiteral>();
if (literal != null && literal.staticType.isDartCoreMap) {
var typeArguments = (literal.staticType as InterfaceType).typeArguments;
var literalType = literal?.staticType;
if (literalType is InterfaceType && literalType.isDartCoreMap) {
var typeArguments = literalType.typeArguments;
if (offset <= node.separator.offset) {
return typeArguments[0];
} else {
@@ -834,7 +830,7 @@ Class: ${parent.parent}
}
@override
DartType visitMethodInvocation(MethodInvocation node) {
DartType? visitMethodInvocation(MethodInvocation node) {
if (offset == node.offset) {
return _visitParent(node);
}
@@ -842,7 +838,7 @@ Class: ${parent.parent}
}
@override
DartType visitNamedExpression(NamedExpression node) {
DartType? visitNamedExpression(NamedExpression node) {
if (offset == node.offset) {
return _visitParent(node);
}
@@ -853,65 +849,66 @@ Class: ${parent.parent}
}
@override
DartType visitParenthesizedExpression(ParenthesizedExpression node) {
DartType? visitParenthesizedExpression(ParenthesizedExpression node) {
return _visitParent(node);
}
@override
DartType visitPostfixExpression(PostfixExpression node) {
DartType? visitPostfixExpression(PostfixExpression node) {
return node.operand.staticParameterElement?.type;
}
@override
DartType visitPrefixedIdentifier(PrefixedIdentifier node) {
DartType? visitPrefixedIdentifier(PrefixedIdentifier node) {
return _visitParent(node);
}
@override
DartType visitPrefixExpression(PrefixExpression node) {
DartType? visitPrefixExpression(PrefixExpression node) {
return node.operand.staticParameterElement?.type;
}
@override
DartType visitPropertyAccess(PropertyAccess node) {
DartType? visitPropertyAccess(PropertyAccess node) {
return _visitParent(node);
}
@override
DartType visitReturnStatement(ReturnStatement node) {
DartType? visitReturnStatement(ReturnStatement node) {
if (node.returnKeyword.end < offset) {
var functionBody = node.thisOrAncestorOfType<FunctionBody>();
if (functionBody != null) {
return BodyInferenceContext.of(functionBody).contextType;
return BodyInferenceContext.of(functionBody)?.contextType;
}
}
return null;
}
@override
DartType visitSetOrMapLiteral(SetOrMapLiteral node) {
DartType? visitSetOrMapLiteral(SetOrMapLiteral node) {
var type = node.staticType;
if (range.endStart(node.leftBracket, node.rightBracket).contains(offset) &&
if (type is InterfaceType &&
range.endStart(node.leftBracket, node.rightBracket).contains(offset) &&
(type.isDartCoreMap || type.isDartCoreSet)) {
return (type as InterfaceType).typeArguments[0];
return type.typeArguments[0];
}
return null;
}
@override
DartType visitSimpleIdentifier(SimpleIdentifier node) {
DartType? visitSimpleIdentifier(SimpleIdentifier node) {
return _visitParent(node);
}
@override
DartType visitSimpleStringLiteral(SimpleStringLiteral node) {
DartType? visitSimpleStringLiteral(SimpleStringLiteral node) {
// The only completion inside of a String literal would be a directive,
// where the context type would not be of value.
return null;
}
@override
DartType visitSpreadElement(SpreadElement node) {
DartType? visitSpreadElement(SpreadElement node) {
if (node.spreadOperator.end <= offset) {
var currentNode = node.parent;
while (currentNode != null) {
@@ -931,44 +928,45 @@ Class: ${parent.parent}
}
@override
DartType visitSwitchCase(SwitchCase node) {
DartType? visitSwitchCase(SwitchCase node) {
if (range.endStart(node.keyword, node.colon).contains(offset)) {
var parent = node.parent;
if (parent is SwitchStatement) {
return parent.expression?.staticType;
return parent.expression.staticType;
}
}
return super.visitSwitchCase(node);
}
@override
DartType visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
if (node.variables != null && node.variables.contains(offset)) {
DartType? visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
if (node.variables.contains(offset)) {
return node.variables.accept(this);
}
return null;
}
@override
DartType visitVariableDeclaration(VariableDeclaration node) {
if (node.equals != null && node.equals.end <= offset) {
DartType? visitVariableDeclaration(VariableDeclaration node) {
var equals = node.equals;
if (equals != null && equals.end <= offset) {
var parent = node.parent;
if (parent is VariableDeclarationList) {
return parent.type?.type ??
impliedDartTypeWithName(typeProvider, node.name?.name);
_impliedDartTypeWithName(typeProvider, node.name.name);
}
}
return null;
}
@override
DartType visitVariableDeclarationList(VariableDeclarationList node) {
DartType? visitVariableDeclarationList(VariableDeclarationList node) {
for (var varDecl in node.variables) {
if (varDecl != null && varDecl.contains(offset)) {
if (varDecl.contains(offset)) {
var equals = varDecl.equals;
if (equals != null && equals.end <= offset) {
return node.type?.type ??
impliedDartTypeWithName(typeProvider, varDecl.name?.name);
_impliedDartTypeWithName(typeProvider, varDecl.name.name);
}
}
}
@@ -976,7 +974,7 @@ Class: ${parent.parent}
}
@override
DartType visitWhileStatement(WhileStatement node) {
DartType? visitWhileStatement(WhileStatement node) {
if (range
.endStart(node.leftParenthesis, node.rightParenthesis)
.contains(offset)) {
@@ -986,11 +984,11 @@ Class: ${parent.parent}
}
@override
DartType visitYieldStatement(YieldStatement node) {
DartType? visitYieldStatement(YieldStatement node) {
if (range.endStart(node.yieldKeyword, node.semicolon).contains(offset)) {
var functionBody = node.thisOrAncestorOfType<FunctionBody>();
if (functionBody != null) {
return BodyInferenceContext.of(functionBody).contextType;
return BodyInferenceContext.of(functionBody)?.contextType;
}
}
return null;
@@ -999,7 +997,7 @@ Class: ${parent.parent}
/// Return the result of visiting the parent of the [node] after setting the
/// [childNode] to the [node]. Note that this method is destructive in that it
/// does not reset the [childNode] before returning.
DartType _visitParent(AstNode node) {
DartType? _visitParent(AstNode node) {
var parent = node.parent;
if (parent == null) {
return null;
@@ -1016,7 +1014,7 @@ extension on AstNode {
/// Some useful extensions on [ArgumentList] for this computer.
extension on ArgumentList {
/// Return the [FunctionType], if there is one, for this [ArgumentList].
FunctionType get functionType {
FunctionType? get functionType {
var parent = this.parent;
if (parent is InstanceCreationExpression) {
return parent.constructorName.staticElement?.type;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/yaml/producer.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/completion/yaml/producer.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -2,12 +2,9 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/pub/pub_package_service.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
/// An object that represents the location of a Boolean value.
@@ -117,8 +114,9 @@ abstract class KeyValueProducer extends Producer {
/// Initialize a producer representing a key/value pair in a map.
const KeyValueProducer();
/// Returns a producer for values of the given [key].
Producer producerForKey(String key);
/// Returns a producer for values of the given [key], or `null` if there is
/// no registered producer for the [key].
Producer? producerForKey(String key);
}
/// An object that represents the location of an element in a list.
@@ -155,7 +153,7 @@ class MapProducer extends KeyValueProducer {
const MapProducer(this._children);
@override
Producer producerForKey(String key) => _children[key];
Producer? producerForKey(String key) => _children[key];
@override
Iterable<CompletionSuggestion> suggestions(
@@ -198,7 +196,7 @@ class YamlCompletionRequest {
final ResourceProvider resourceProvider;
/// The Pub package service used for looking up package names/versions.
final PubPackageService pubPackageService;
final PubPackageService? pubPackageService;
/// The absolute path of the file in which completions are being requested.
final String filePath;
@@ -208,8 +206,8 @@ class YamlCompletionRequest {
/// Initialize a newly created completion request.
YamlCompletionRequest(
{@required this.filePath,
@required this.precedingText,
@required this.resourceProvider,
@required this.pubPackageService});
{required this.filePath,
required this.precedingText,
required this.resourceProvider,
required this.pubPackageService});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/yaml/producer.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
@@ -17,10 +15,12 @@ class PubPackageNameProducer extends Producer {
@override
Iterable<CompletionSuggestion> suggestions(
YamlCompletionRequest request) sync* {
final cachedPackages = request.pubPackageService.cachedPackages;
var relevance = cachedPackages.length;
yield* cachedPackages.map((package) =>
packageName('${package.packageName}: ', relevance: relevance--));
final cachedPackages = request.pubPackageService?.cachedPackages;
if (cachedPackages != null) {
var relevance = cachedPackages.length;
yield* cachedPackages.map((package) =>
packageName('${package.packageName}: ', relevance: relevance--));
}
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/yaml/producer.dart';
import 'package:analysis_server/src/services/pub/pub_package_service.dart';
@@ -19,9 +17,9 @@ abstract class YamlCompletionGenerator {
/// completion was requested.
final ResourceProvider resourceProvider;
/// A service used for collecting Pub package information. May be null for
/// A service used for collecting Pub package information. May be `null` for
/// generators that do not use Pub packages.
final PubPackageService pubPackageService;
final PubPackageService? pubPackageService;
/// Initialize a newly created generator to use the [resourceProvider] to
/// access the content of the file in which completion was requested.
@@ -86,15 +84,21 @@ abstract class YamlCompletionGenerator {
}
}
final node = nodePath.isNotEmpty ? nodePath.last : null;
final replaceNode = node is YamlScalar && node.containsOffset(offset);
final replacementOffset = replaceNode ? node.span.start.offset : offset;
final replacementLength = replaceNode ? node.span.length : 0;
int replacementOffset;
int replacementLength;
if (node is YamlScalar && node.containsOffset(offset)) {
replacementOffset = node.span.start.offset;
replacementLength = node.span.length;
} else {
replacementOffset = offset;
replacementLength = 0;
}
return YamlCompletionResults(
suggestions, replacementOffset, replacementLength);
}
/// Return the result of parsing the file [content] into a YAML node.
YamlNode _parseYaml(String content) {
YamlNode? _parseYaml(String content) {
try {
return loadYamlNode(content, recover: true);
} on YamlException {
@@ -108,7 +112,7 @@ abstract class YamlCompletionGenerator {
/// and the node containing the offset is the last element in the list.
List<YamlNode> _pathToOffset(YamlNode root, int offset) {
var path = <YamlNode>[];
var node = root;
YamlNode? node = root;
while (node != null) {
path.add(node);
node = node.childContainingOffset(offset);
@@ -118,19 +122,19 @@ abstract class YamlCompletionGenerator {
/// Return the producer that should be used to produce completion suggestions
/// for the last node in the node [path].
Producer _producerForPath(List<YamlNode> path) {
var producer = topLevelProducer;
Producer? _producerForPath(List<YamlNode> path) {
Producer? producer = topLevelProducer;
for (var i = 0; i < path.length - 1; i++) {
var node = path[i];
if (node is YamlMap && producer is KeyValueProducer) {
var key = node.keyAtValue(path[i + 1]);
if (key is YamlScalar) {
producer = (producer as KeyValueProducer).producerForKey(key.value);
producer = producer.producerForKey(key.value);
} else {
return null;
}
} else if (node is YamlList && producer is ListProducer) {
producer = (producer as ListProducer).element;
producer = producer.element;
} else {
return producer;
}
@@ -141,7 +145,7 @@ abstract class YamlCompletionGenerator {
/// Return a list of the suggestions that should not be suggested because they
/// are already in the structure.
List<String> _siblingsOnPath(List<YamlNode> path) {
List<String> siblingsInList(YamlList list, YamlNode currentElement) {
List<String> siblingsInList(YamlList list, YamlNode? currentElement) {
var siblings = <String>[];
for (var element in list.nodes) {
if (element != currentElement &&
@@ -153,7 +157,7 @@ abstract class YamlCompletionGenerator {
return siblings;
}
List<String> siblingsInMap(YamlMap map, YamlNode currentKey) {
List<String> siblingsInMap(YamlMap map, YamlNode? currentKey) {
var siblings = <String>[];
for (var key in map.nodes.keys) {
if (key != currentKey && key is YamlScalar && key.value is String) {
@@ -41,7 +41,7 @@ class PubApi {
};
PubApi(this.instrumentationService, http.Client? httpClient,
String envPubHostedUrl)
String? envPubHostedUrl)
: httpClient =
httpClient != null ? _NoCloseHttpClient(httpClient) : http.Client(),
_pubHostedUrl = _validPubHostedUrl(envPubHostedUrl);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'protocol_dart_test.dart' as protocol_dart_test;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
import 'package:test/test.dart';
@@ -19,10 +17,10 @@ void main() {
@reflectiveTest
class ContextTypeTest extends FeatureComputerTest {
Future<void> assertContextType(String content, String expectedType) async {
Future<void> assertContextType(String content, [String? expectedType]) async {
await completeIn(content);
var computer = FeatureComputer(
testAnalysisResult.typeSystem, testAnalysisResult.typeProvider);
var result = testAnalysisResult!;
var computer = FeatureComputer(result.typeSystem, result.typeProvider);
var type = computer.computeContextType(
completionTarget.containingNode, cursorIndex);
@@ -68,7 +66,7 @@ void f({int i = 0}) {}
void g() {
f(i^:);
}
''', null);
''');
}
Future<void> test_argumentList_named_beforeLabel() async {
@@ -77,7 +75,7 @@ void f({int i = 0}) {}
void g() {
f(^i:);
}
''', null);
''');
}
Future<void>
@@ -118,7 +116,7 @@ void f({int i}) {}
void g() {
f(j: ^);
}
''', null);
''');
}
Future<void> test_argumentList_named_unresolved_noNamedParameters() async {
@@ -128,7 +126,7 @@ void f() {}
void g() {
f(j: ^);
}
''', null);
''');
}
Future<void> test_argumentList_named_with_requiredPositional() async {
@@ -156,7 +154,7 @@ void f() {}
void g() {
f(^);
}
''', null);
''');
}
Future<void> test_argumentList_noParameters_whitespace() async {
@@ -165,7 +163,7 @@ void f() {}
void g() {
f( ^ );
}
''', null);
''');
}
Future<void> test_argumentList_noParameters_whitespace_left() async {
@@ -174,7 +172,7 @@ void f() {}
void g() {
f( ^);
}
''', null);
''');
}
Future<void> test_argumentList_noParameters_whitespace_right() async {
@@ -183,7 +181,7 @@ void f() {}
void g() {
f(^ );
}
''', null);
''');
}
Future<void> test_argumentList_positional() async {
@@ -201,7 +199,7 @@ void f([int i]) {}
void g() {
f(i: ^);
}
''', null);
''');
}
Future<void> test_argumentList_positional_asNamed_beforeColon() async {
@@ -210,7 +208,7 @@ void f(String s, bool b, [int i = 0]) {}
void g() {
f(i^:);
}
''', null);
''');
}
Future<void> test_argumentList_positional_asNamed_beforeLabel() async {
@@ -266,7 +264,7 @@ void f(int i, String str, bool b) {}
void g() {
f(i: ^);
}
''', null);
''');
}
Future<void> test_argumentList_requiredPositional_first() async {
@@ -421,7 +419,7 @@ class C {
void g(String s) {
var x = ^s.length;
}
''', null);
''');
}
Future<void> test_assignmentExpression_withType() async {
@@ -485,7 +483,7 @@ class Foo {
class Foo {
var x =^;
}
''', null);
''');
}
Future<void> test_fieldDeclaration_var_impliedType_int() async {
@@ -517,7 +515,7 @@ class Foo {
class Foo {
var x = ^ ;
}
''', null);
''');
}
Future<void> test_ifElement() async {
@@ -565,7 +563,7 @@ void foo() {
void f(int e) {
var l = ^<int>[e];
}
''', null);
''');
}
Future<void> test_listLiteral_element() async {
@@ -589,7 +587,7 @@ void f(int e) {
void f(int e) {
var l = <^int>[e];
}
''', null);
''');
}
Future<void> test_mapLiteralEntry_key() async {
@@ -633,7 +631,7 @@ void g(C c) {
void f() {
var m = ^<int, int>{};
}
''', null);
''');
}
Future<void> test_setOrMapLiteral_map_element() async {
@@ -649,7 +647,7 @@ void f(bool b, int e) {
void f() {
var m = <int, ^int>{};
}
''', null);
''');
}
Future<void> test_setOrMapLiteral_set_beforeTypeParameter() async {
@@ -657,7 +655,7 @@ void f() {
void f() {
var s = ^<int>{};
}
''', null);
''');
}
Future<void> test_setOrMapLiteral_set_element() async {
@@ -673,7 +671,7 @@ void f(int e) {
void f() {
var s = <^int>{};
}
''', null);
''');
}
Future<void> test_topLevelVariableDeclaration_int() async {
@@ -710,26 +708,26 @@ int i = ^ ;
Future<void> test_topLevelVariableDeclaration_var() async {
await assertContextType('''
var x=^;
''', null);
''');
}
Future<void> test_topLevelVariableDeclaration_var_noEqual() async {
await assertContextType('''
int x^;
''', null);
''');
}
Future<void> test_topLevelVariableDeclaration_var_whitespace() async {
await assertContextType('''
var x= ^ ;
''', null);
''');
}
}
abstract class FeatureComputerTest extends AbstractSingleUnitTest {
int cursorIndex = 0;
CompletionTarget completionTarget;
late CompletionTarget completionTarget;
@override
bool verifyNoTestUnitErrors = false;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/completion/yaml/analysis_options_generator.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:linter/src/rules.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
import 'package:analysis_server/src/services/pub/pub_api.dart';
import 'package:analysis_server/src/services/pub/pub_package_service.dart';
@@ -23,9 +21,10 @@ void main() {
@reflectiveTest
class PubspecGeneratorTest extends YamlGeneratorTest {
MockHttpClient httpClient;
late MockHttpClient httpClient;
late PubPackageService pubPackageService;
PubPackageService pubPackageService;
@override
String get fileName => 'pubspec.yaml';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'analysis_options_generator_test.dart' as analysis_options_generator;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
@@ -11,7 +9,7 @@ import 'package:test/test.dart';
abstract class YamlGeneratorTest with ResourceProviderMixin {
/// The completion results produced by [getCompletions].
/* late */ List<CompletionSuggestion> results;
late List<CompletionSuggestion> results;
/// Return the name of the file being tested.
String get fileName;