Skip to content

Commit

Permalink
Convert one more KeywordContributor method
Browse files Browse the repository at this point in the history
Change-Id: Ic58d7a4cd2878981f77221b85b0566a7a0f5b732
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327240
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
  • Loading branch information
bwilkerson authored and Commit Queue committed Sep 21, 2023
1 parent 4ac1217 commit 4c73e0a
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/ast/token.dart';

/// A completion pass that will create candidate suggestions based on the
Expand Down Expand Up @@ -335,6 +336,8 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
if (defaultValue is Expression && defaultValue.coversOffset(offset)) {
collector.completionLocation = 'DefaultFormalParameter_defaultValue';
_forExpression(defaultValue);
} else {
node.parameter.accept(this);
}
}

Expand Down Expand Up @@ -537,8 +540,18 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
var parent = node.parent;
if (parent is FunctionExpression) {
visitFunctionExpression(parent);
return;
}
}
var parameters = node.parameters;
var precedingParameter = parameters.elementBefore(offset);
if (precedingParameter != null && precedingParameter.isIncomplete) {
precedingParameter.accept(this);
return;
}

keywordHelper.addFormalParameterKeywords(node);
_forTypeAnnotation();
}

@override
Expand Down Expand Up @@ -637,6 +650,17 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
}
}

@override
void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
var returnType = node.returnType;
if (returnType != null && offset <= returnType.end) {
keywordHelper.addFormalParameterKeywords(node.parentFormalParameterList);
_forTypeAnnotation();
} else if (returnType == null && offset < node.name.offset) {
_forTypeAnnotation();
}
}

@override
void visitGenericTypeAlias(GenericTypeAlias node) {
if (node.typedefKeyword.coversOffset(offset)) {
Expand Down Expand Up @@ -1036,9 +1060,29 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {

@override
void visitSimpleFormalParameter(SimpleFormalParameter node) {
var name = node.name;
if (name != null && node.isSingleIdentifier) {
if (name.isKeyword) {
if (name.keyword == Keyword.REQUIRED && node.covariantKeyword == null) {
keywordHelper.addKeyword(Keyword.COVARIANT);
}
_forTypeAnnotation();
return;
} else if (name.isSynthetic) {
keywordHelper
.addFormalParameterKeywords(node.parentFormalParameterList);
_forTypeAnnotation();
} else {
keywordHelper
.addFormalParameterKeywords(node.parentFormalParameterList);
_forTypeAnnotation();
}
}
var type = node.type;
if (type != null) {
if (type.beginToken.coversOffset(offset)) {
keywordHelper
.addFormalParameterKeywords(node.parentFormalParameterList);
_forTypeAnnotation();
} else if (type is GenericFunctionType &&
offset < type.functionKeyword.offset &&
Expand Down Expand Up @@ -1640,7 +1684,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
}

extension on AstNode {
/// Return `true` if all of the tokens in this node are synthetic.
/// Whether all of the tokens in this node are synthetic.
bool get isFullySynthetic {
var current = beginToken;
var stop = endToken.next!;
Expand Down Expand Up @@ -1745,7 +1789,7 @@ extension on AstNode {
}

extension on ClassDeclaration {
/// Return `true` if this class declaration doesn't have a body.
/// Whether this class declaration doesn't have a body.
bool get hasNoBody {
return leftBracket.isSynthetic && rightBracket.isSynthetic;
}
Expand Down Expand Up @@ -1810,7 +1854,7 @@ extension on CompilationUnit {
}

extension on ExpressionStatement {
/// Return `true` if this statement consists of a single identifier.
/// Whether this statement consists of a single identifier.
bool get isSingleIdentifier {
var first = beginToken;
var last = endToken;
Expand All @@ -1821,14 +1865,14 @@ extension on ExpressionStatement {
}

extension on ExtensionTypeDeclaration {
/// Return `true` if this class declaration doesn't have a body.
/// Whether this class declaration doesn't have a body.
bool get hasNoBody {
return leftBracket.isSynthetic && rightBracket.isSynthetic;
}
}

extension on FieldDeclaration {
/// Return `true` if this field declaration consists of a single identifier.
/// Whether this field declaration consists of a single identifier.
bool get isSingleIdentifier {
var first = beginToken;
var last = endToken;
Expand All @@ -1838,8 +1882,35 @@ extension on FieldDeclaration {
}
}

extension on FormalParameter {
/// Whether this formal parameter declaration is incomplete.
bool get isIncomplete {
final name = this.name;
if (name == null || name.isKeyword) {
return true;
}
var self = this;
if (self is DefaultFormalParameter && self.separator != null) {
var defaultValue = self.defaultValue;
if (defaultValue == null || defaultValue.isSynthetic) {
// The `defaultValue` won't be `null` if the separator is non-`null`,
// but the condition is necessary because the type system can't express
// that constraint.
return true;
}
}
return false;
}

/// Whether this formal parameter declaration consists of a single identifier.
bool get isSingleIdentifier {
final beginToken = this.beginToken;
return beginToken == endToken && beginToken.isKeywordOrIdentifier;
}
}

extension on GuardedPattern {
/// Return `true` if this pattern has, or might have, a `when` keyword.
/// Whether this pattern has, or might have, a `when` keyword.
bool get hasWhen {
if (whenClause != null) {
return true;
Expand Down Expand Up @@ -1883,7 +1954,7 @@ extension on SyntacticEntity? {
}

extension on TopLevelVariableDeclaration {
/// Return `true` if this top level variable declaration consists of a single
/// Whether this top level variable declaration consists of a single
/// identifier.
bool get isSingleIdentifier {
var first = beginToken;
Expand All @@ -1896,7 +1967,7 @@ extension on TopLevelVariableDeclaration {
}

extension on TypeAnnotation? {
/// Return `true` if this type annotation consists of a single identifier.
/// Whether this type annotation consists of a single identifier.
bool get isSingleIdentifier {
var self = this;
return self is NamedType &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ 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/src/dart/ast/extensions.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer_plugin/src/utilities/completion/optype.dart';

Expand Down Expand Up @@ -103,87 +102,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}

@override
void visitFormalParameterList(FormalParameterList node) {
var constructorDeclaration =
node.thisOrAncestorOfType<ConstructorDeclaration>();
if (constructorDeclaration != null) {
if (request.featureSet.isEnabled(Feature.super_parameters)) {
_addSuggestion(Keyword.SUPER);
}
_addSuggestion(Keyword.THIS);
}
final entity = this.entity;
if (entity is Token) {
FormalParameter? lastParameter() {
var parameters = node.parameters;
if (parameters.isNotEmpty) {
return parameters.last.notDefault;
}
return null;
}

bool hasCovariant() {
var last = lastParameter();
return last != null &&
(last.covariantKeyword != null || last.name?.lexeme == 'covariant');
}

bool hasRequired() {
var last = lastParameter();
return last != null &&
(last.requiredKeyword != null || last.name?.lexeme == 'required');
}

var tokenType = entity.type;
if (tokenType == TokenType.CLOSE_PAREN) {
_addSuggestion(Keyword.DYNAMIC);
_addSuggestion(Keyword.VOID);
if (!hasCovariant()) {
_addSuggestion(Keyword.COVARIANT);
}
} else if (tokenType == TokenType.CLOSE_CURLY_BRACKET) {
_addSuggestion(Keyword.DYNAMIC);
_addSuggestion(Keyword.VOID);
if (!hasCovariant()) {
_addSuggestion(Keyword.COVARIANT);
if (request.featureSet.isEnabled(Feature.non_nullable) &&
!hasRequired()) {
_addSuggestion(Keyword.REQUIRED);
}
}
} else if (tokenType == TokenType.CLOSE_SQUARE_BRACKET) {
_addSuggestion(Keyword.DYNAMIC);
_addSuggestion(Keyword.VOID);
if (!hasCovariant()) {
_addSuggestion(Keyword.COVARIANT);
}
}
} else if (entity is FormalParameter) {
var beginToken = entity.beginToken;
var offset = request.target.offset;
if (offset <= beginToken.end) {
_addSuggestion(Keyword.COVARIANT);
_addSuggestion(Keyword.DYNAMIC);
_addSuggestion(Keyword.VOID);
if (entity.isNamed &&
!entity.isRequired &&
request.featureSet.isEnabled(Feature.non_nullable)) {
_addSuggestion(Keyword.REQUIRED);
}
} else if (entity is FunctionTypedFormalParameter) {
_addSuggestion(Keyword.COVARIANT);
_addSuggestion(Keyword.DYNAMIC);
_addSuggestion(Keyword.VOID);
if (entity.isNamed &&
!entity.isRequired &&
request.featureSet.isEnabled(Feature.non_nullable)) {
_addSuggestion(Keyword.REQUIRED);
}
}
}
}

void _addExpressionKeywords(AstNode node) {
_addSuggestions([
Keyword.FALSE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,23 @@ class KeywordHelper {
}
}

/// Add the keywords that are appropriate when the selection is at the start
/// of a formal parameter in the given [parameterList].
void addFormalParameterKeywords(FormalParameterList parameterList) {
addKeyword(Keyword.COVARIANT);
addKeyword(Keyword.FINAL);
if (parameterList.inNamedGroup(offset)) {
addKeyword(Keyword.REQUIRED);
}
var parent = parameterList.parent;
if (parent is ConstructorDeclaration) {
if (featureSet.isEnabled(Feature.super_parameters)) {
addKeyword(Keyword.SUPER);
}
addKeyword(Keyword.THIS);
}
}

/// Add the keywords that are appropriate when the selection is before the `{`
/// or `=>` in a function body. The [body] is used to determine which keywords
/// are appropriate.
Expand Down Expand Up @@ -585,6 +602,19 @@ extension on CollectionElement? {
}
}

extension on FormalParameterList {
bool inNamedGroup(int offset) {
final leftDelimiter = this.leftDelimiter;
if (leftDelimiter == null ||
leftDelimiter.type != TokenType.OPEN_CURLY_BRACKET) {
return false;
}
var left = leftDelimiter.end;
var right = rightDelimiter?.offset ?? rightParenthesis.offset;
return left <= offset && offset <= right;
}
}

extension on NodeList<ConstructorInitializer> {
ConstructorInitializer get lastNonSynthetic {
final last = this.last;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ suggestions
kind: keyword
dynamic
kind: keyword
final
kind: keyword
super
kind: keyword
this
Expand Down Expand Up @@ -162,6 +164,8 @@ suggestions
kind: keyword
dynamic
kind: keyword
final
kind: keyword
void
kind: keyword
''');
Expand Down
Loading

0 comments on commit 4c73e0a

Please sign in to comment.