Move more of KeywordContributor to the new framework

Change-Id: I2b257545a3af7fa2f803e8f954d14cd3679c35c1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319781
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Brian Wilkerson 2023-08-10 16:58:51 +00:00 committed by Commit Queue
parent fc35778ff7
commit 98608662e7
4 changed files with 238 additions and 190 deletions

View file

@ -102,6 +102,11 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
_forExpression(node);
}
@override
void visitBooleanLiteral(BooleanLiteral node) {
_forExpression(node);
}
@override
void visitClassDeclaration(ClassDeclaration node) {
if (offset < node.classKeyword.offset) {
@ -141,11 +146,99 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
}
}
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
var separator = node.separator;
if (separator != null) {
if (offset >= separator.end && offset <= node.body.offset) {
collector.completionLocation = 'ConstructorDeclaration_initializer';
keywordHelper.addConstructorInitializerKeywords(node);
}
}
}
@override
void visitDoubleLiteral(DoubleLiteral node) {
_visitParentIfAtOrBeforeNode(node);
}
@override
void visitEnumDeclaration(EnumDeclaration node) {
if (!featureSet.isEnabled(Feature.enhanced_enums)) {
return;
}
if (offset < node.enumKeyword.offset) {
// There are no modifiers for enums.
return;
}
if (offset <= node.enumKeyword.end) {
keywordHelper.addKeyword(Keyword.ENUM);
return;
}
if (offset <= node.name.end) {
// TODO(brianwilkerson) Suggest a name for the mixin.
return;
}
if (offset <= node.leftBracket.offset) {
keywordHelper.addEnumDeclarationKeywords(node);
return;
}
var rightBracket = node.rightBracket;
if (!rightBracket.isSynthetic && offset >= rightBracket.end) {
return;
}
var semicolon = node.semicolon;
if (semicolon != null && offset >= semicolon.end) {
collector.completionLocation = 'EnumDeclaration_member';
_forEnumMember();
}
}
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
if (offset < node.extensionKeyword.offset) {
// There are no modifiers for extensions.
return;
}
if (offset <= node.extensionKeyword.end) {
keywordHelper.addKeyword(Keyword.EXTENSION);
return;
}
var name = node.name;
if (name != null && offset <= name.end) {
// TODO(brianwilkerson) We probably need to suggest `on`.
// TODO(brianwilkerson) We probably need to suggest `type` when extension
// types are supported.
// Don't suggest a name for the extension.
return;
}
if (offset <= node.leftBracket.offset) {
if (node.onKeyword.isSynthetic) {
keywordHelper.addExtensionDeclarationKeywords(node);
} else {
collector.completionLocation = 'ExtensionDeclaration_extendedType';
}
return;
}
if (offset >= node.leftBracket.end && offset <= node.rightBracket.offset) {
collector.completionLocation = 'ExtensionDeclaration_member';
_forExtensionMember();
}
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
// If the cursor is at the beginning of the declaration, include the
// compilation unit keywords. See dartbug.com/41039.
var returnType = node.returnType;
if ((returnType == null || returnType.beginToken == returnType.endToken) &&
offset <= node.name.offset) {
collector.completionLocation = 'FunctionDeclaration_returnType';
keywordHelper.addKeyword(Keyword.DYNAMIC);
keywordHelper.addKeyword(Keyword.VOID);
}
}
@override
void visitIntegerLiteral(IntegerLiteral node) {
_visitParentIfAtOrBeforeNode(node);
@ -204,6 +297,42 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
_forPattern();
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
if (offset < node.mixinKeyword.offset) {
keywordHelper.addMixinModifiers(node);
return;
}
if (offset <= node.mixinKeyword.end) {
keywordHelper.addKeyword(Keyword.MIXIN);
return;
}
if (offset <= node.name.end) {
// TODO(brianwilkerson) Suggest a name for the mixin.
return;
}
if (offset <= node.leftBracket.offset) {
keywordHelper.addMixinDeclarationKeywords(node);
return;
}
if (offset >= node.leftBracket.end && offset <= node.rightBracket.offset) {
collector.completionLocation = 'MixinDeclaration_member';
_forMixinMember();
var element = node.members.elementBefore(offset);
if (element is MethodDeclaration) {
var body = element.body;
if (body.isEmpty) {
keywordHelper.addFunctionBodyModifiers(body);
}
}
}
}
@override
void visitNullLiteral(NullLiteral node) {
_forExpression(node);
}
@override
void visitParenthesizedPattern(ParenthesizedPattern node) {
collector.completionLocation = 'ParenthesizedPattern_expression';
@ -274,6 +403,53 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
_visitParentIfAtOrBeforeNode(node);
}
@override
void visitSymbolLiteral(SymbolLiteral node) {
_forExpression(node);
}
@override
void visitThisExpression(ThisExpression node) {
_forExpression(node);
}
@override
void visitThrowExpression(ThrowExpression node) {
collector.completionLocation = 'ThrowExpression_expression';
_forExpression(node);
}
@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
var variableDeclarationList = node.variables;
var variables = variableDeclarationList.variables;
if (variables.isEmpty || offset > variables.first.beginToken.end) {
return;
}
if (node.externalKeyword == null) {
keywordHelper.addKeyword(Keyword.EXTERNAL);
}
if (variableDeclarationList.lateKeyword == null &&
featureSet.isEnabled(Feature.non_nullable)) {
keywordHelper.addKeyword(Keyword.LATE);
}
if (!variables.first.isConst) {
keywordHelper.addKeyword(Keyword.CONST);
}
if (!variables.first.isFinal) {
keywordHelper.addKeyword(Keyword.FINAL);
}
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
var equals = node.equals;
if (equals != null && offset >= equals.end) {
collector.completionLocation = 'VariableDeclaration_initializer';
_forExpression(node);
}
}
/// Add the suggestions that are appropriate when the selection is at the
/// beginning of a class member.
void _forClassMember() {
@ -304,6 +480,12 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
// _addVariablesInScope(node, mustBeConstant: true);
}
/// Add the suggestions that are appropriate when the selection is at the
/// beginning of an enum member.
void _forEnumMember() {
keywordHelper.addEnumMemberKeywords();
}
/// Add the suggestions that are appropriate when the selection is at the
/// beginning of an expression. The [node] provides context to determine which
/// keywords to include.
@ -314,6 +496,18 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
// _addVariablesInScope(node);
}
/// Add the suggestions that are appropriate when the selection is at the
/// beginning of an extension member.
void _forExtensionMember() {
keywordHelper.addExtensionMemberKeywords();
}
/// Add the suggestions that are appropriate when the selection is at the
/// beginning of a mixin member.
void _forMixinMember() {
keywordHelper.addMixinMemberKeywords();
}
/// Add the suggestions that are appropriate when the selection is at the
/// beginning of a pattern.
void _forPattern() {

View file

@ -170,11 +170,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitBooleanLiteral(BooleanLiteral node) {
_addExpressionKeywords(node);
}
@override
void visitCascadeExpression(CascadeExpression node) {
_addExpressionKeywords(node);
@ -251,33 +246,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
_addExpressionKeywords(node);
}
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
if (node.initializers.isNotEmpty) {
if (entity is ConstructorInitializer) {
_addSuggestion(Keyword.ASSERT);
}
var last = node.initializers.last;
if (last == entity) {
var previous = node.findPrevious(last.beginToken);
if (previous != null && previous.end <= request.offset) {
_addSuggestion(Keyword.SUPER);
_addSuggestion(Keyword.THIS);
}
}
} else {
var separator = node.separator;
if (separator != null) {
var offset = request.offset;
if (separator.end <= offset && offset <= separator.next!.offset) {
_addSuggestion(Keyword.ASSERT);
_addSuggestion(Keyword.SUPER);
_addSuggestion(Keyword.THIS);
}
}
}
}
@override
void visitConstructorReference(ConstructorReference node) {
_addExpressionKeywords(node);
@ -301,29 +269,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitEnumDeclaration(EnumDeclaration node) {
if (!request.featureSet.isEnabled(Feature.enhanced_enums)) {
return;
}
if (entity == node.name) {
return;
}
var semicolon = node.semicolon;
if (request.offset <= node.leftBracket.offset) {
if (node.withClause == null) {
_addSuggestion(Keyword.WITH);
}
if (node.implementsClause == null) {
_addSuggestion(Keyword.IMPLEMENTS);
}
} else if (semicolon != null && semicolon.end <= request.offset) {
_addEnumBodyKeywords();
}
}
@override
void visitExpressionFunctionBody(ExpressionFunctionBody node) {
if (entity == node.expression) {
@ -331,21 +276,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
// Don't suggest extension name
if (entity == node.name) {
return;
}
if (entity == node.rightBracket) {
_addExtensionBodyKeywords();
} else if (entity is ClassMember) {
_addExtensionBodyKeywords();
} else {
_addExtensionDeclarationKeywords(node);
}
}
@override
void visitExtensionOverride(ExtensionOverride node) {
_addExpressionKeywords(node);
@ -546,16 +476,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
// If the cursor is at the beginning of the declaration, include the
// compilation unit keywords. See dartbug.com/41039.
if (entity == node.returnType || entity == node.name) {
_addSuggestion(Keyword.DYNAMIC);
_addSuggestion(Keyword.VOID);
}
}
@override
void visitFunctionExpression(FunctionExpression node) {
if (entity == node.body) {
@ -724,29 +644,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
final entity = this.entity;
// Don't suggest mixin name
if (entity == node.name) {
return;
}
if (entity == node.rightBracket) {
_addClassBodyKeywords();
} else if (entity is ClassMember) {
_addClassBodyKeywords();
var index = node.members.indexOf(entity);
var previous = index > 0 ? node.members[index - 1] : null;
if (previous is MethodDeclaration && previous.body.isEmpty) {
_addSuggestion(Keyword.ASYNC);
_addSuggestion2(ASYNC_STAR);
_addSuggestion2(SYNC_STAR);
}
} else if (entity != node.mixinKeyword) {
_addMixinDeclarationKeywords(node);
}
}
@override
void visitNamedExpression(NamedExpression node) {
if (entity is SimpleIdentifier && entity == node.expression) {
@ -754,11 +651,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitNullLiteral(NullLiteral node) {
_addExpressionKeywords(node);
}
@override
void visitParenthesizedExpression(ParenthesizedExpression node) {
var expression = node.expression;
@ -913,44 +805,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
@override
void visitSymbolLiteral(SymbolLiteral node) {
_addExpressionKeywords(node);
}
@override
void visitThisExpression(ThisExpression node) {
_addExpressionKeywords(node);
}
@override
void visitThrowExpression(ThrowExpression node) {
_addExpressionKeywords(node);
}
@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
var variableDeclarationList = node.variables;
if (entity != variableDeclarationList) return;
var variables = variableDeclarationList.variables;
if (variables.isEmpty || request.offset > variables.first.beginToken.end) {
return;
}
if (node.externalKeyword == null) {
_addSuggestion(Keyword.EXTERNAL);
}
if (variableDeclarationList.lateKeyword == null &&
request.featureSet.isEnabled(Feature.non_nullable)) {
_addSuggestion(Keyword.LATE);
}
if (!variables.first.isConst) {
_addSuggestion(Keyword.CONST);
}
if (!variables.first.isFinal) {
_addSuggestion(Keyword.FINAL);
}
}
@override
void visitTryStatement(TryStatement node) {
var obj = entity;
@ -973,13 +827,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
_addExpressionKeywords(node);
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
if (entity == node.initializer) {
_addExpressionKeywords(node);
}
}
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
var keyword = node.keyword;
@ -1086,21 +933,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
void _addEnumBodyKeywords() {
_addSuggestions([
Keyword.CONST,
Keyword.DYNAMIC,
Keyword.FINAL,
Keyword.GET,
Keyword.LATE,
Keyword.OPERATOR,
Keyword.SET,
Keyword.STATIC,
Keyword.VAR,
Keyword.VOID
]);
}
void _addExpressionKeywords(AstNode node) {
_addSuggestions([
Keyword.FALSE,
@ -1121,23 +953,6 @@ class _KeywordVisitor extends SimpleAstVisitor<void> {
}
}
void _addExtensionBodyKeywords() {
_addSuggestions([
Keyword.CONST,
Keyword.DYNAMIC,
Keyword.FINAL,
Keyword.GET,
Keyword.OPERATOR,
Keyword.SET,
Keyword.STATIC,
Keyword.VAR,
Keyword.VOID
]);
if (request.featureSet.isEnabled(Feature.non_nullable)) {
_addSuggestion(Keyword.LATE);
}
}
void _addExtensionDeclarationKeywords(ExtensionDeclaration node) {
if (node.onKeyword.isSynthetic) {
_addSuggestion(Keyword.ON);

View file

@ -164,6 +164,32 @@ class KeywordHelper {
}
}
/// Add the keywords that are appropriate when the selection is in the
/// initializer list of the given [node].
void addConstructorInitializerKeywords(ConstructorDeclaration node) {
addKeyword(Keyword.ASSERT);
var suggestSuper = node.parent is! ExtensionTypeDeclaration;
var initializers = node.initializers;
if (initializers.isNotEmpty) {
var last = initializers.lastNonSynthetic;
if (offset >= last.end &&
last is! SuperConstructorInvocation &&
last is! RedirectingConstructorInvocation) {
if (suggestSuper) {
addKeyword(Keyword.SUPER);
}
addKeyword(Keyword.THIS);
}
} else {
// if (separator.end <= offset && offset <= separator.next!.offset) {
if (suggestSuper) {
addKeyword(Keyword.SUPER);
}
addKeyword(Keyword.THIS);
// }
}
}
/// Add the keywords that are appropriate when the selection is in an enum
/// declaration between the name of the enum and the body. The [node] is the
/// enum declaration containing the selection point.
@ -204,7 +230,12 @@ class KeywordHelper {
if (node is CollectionElement && node is! Expression) {
node = node.parent;
}
return node is Expression && !node.inConstantContext;
if (node is Expression) {
return !node.inConstantContext;
} else if (node is VariableDeclaration) {
return !node.isConst;
}
return false;
}
addKeyword(Keyword.FALSE);
@ -428,3 +459,13 @@ extension on CollectionElement? {
return finalElement is IfElement && finalElement.elseKeyword == null;
}
}
extension on NodeList<ConstructorInitializer> {
ConstructorInitializer get lastNonSynthetic {
final last = this.last;
if (last.beginToken.isSynthetic && length > 1) {
return this[length - 2];
}
return last;
}
}

View file

@ -254,8 +254,7 @@ suggestions
Keyword.CONST,
if (context.isClass || context.isMixin) Keyword.COVARIANT,
Keyword.DYNAMIC,
// TODO(scheglov) This does not look right, mixin.
if (context.isClass || context.isMixin) Keyword.FACTORY,
if (context.isClass) Keyword.FACTORY,
Keyword.FINAL,
Keyword.GET,
Keyword.LATE,
@ -499,8 +498,7 @@ ${keywords.asKeywordSuggestions}
Keyword.CONST,
if (context.isClass || context.isMixin) Keyword.COVARIANT,
Keyword.DYNAMIC,
// TODO(scheglov) This does not look right, mixin.
if (context.isClass || context.isMixin) Keyword.FACTORY,
if (context.isClass) Keyword.FACTORY,
Keyword.FINAL,
Keyword.GET,
Keyword.LATE,