blob: af2d9e38fb580bcb251eb5a76493cd3b374afac7 [file] [log] [blame]
// Copyright (c) 2015, 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 'dart:async';
import 'package:analysis_server/src/protocol_server.dart'
show CompletionSuggestion, CompletionSuggestionKind;
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'
show DartCompletionRequestImpl;
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer_plugin/src/utilities/completion/optype.dart';
/**
* Given some [String] name "foo", return a [CompletionSuggestion] with the
* [String].
*
* If the passed [String] is null or empty, null is returned.
*/
CompletionSuggestion _createNameSuggestion(String name) {
if (name == null || name.isEmpty) {
return null;
}
return new CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
DART_RELEVANCE_DEFAULT, name, name.length, 0, false, false);
}
/**
* Convert some [Identifier] to its [String] name.
*/
String _getStringName(Identifier id) {
if (id == null) {
return null;
}
if (id is SimpleIdentifier) {
return id.name;
} else if (id is PrefixedIdentifier) {
return id.identifier.name;
}
return id.name;
}
/**
* A contributor for calculating suggestions for variable names.
*/
class VariableNameContributor extends DartCompletionContributor {
@override
Future<List<CompletionSuggestion>> computeSuggestions(
DartCompletionRequest request) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
OpType optype = (request as DartCompletionRequestImpl).opType;
// Collect suggestions from the specific child [AstNode] that contains
// the completion offset and all of its parents recursively.
if (optype.includeVarNameSuggestions) {
// Resolution not needed for this completion
AstNode node = request.target.containingNode;
String strName = null;
if (node is ExpressionStatement) {
if (node.expression is Identifier) {
strName = _getStringName(node.expression as Identifier);
}
} else if (node is VariableDeclarationList) {
TypeAnnotation typeAnnotation = node.type;
if (typeAnnotation is TypeName) {
strName = _getStringName(typeAnnotation.name);
}
} else if (node is TopLevelVariableDeclaration) {
// The parser parses 'Foo ' and 'Foo ;' differently, resulting in the
// following.
// 'Foo ': handled above
// 'Foo ;': TopLevelVariableDeclaration with type null, and a first
// variable of 'Foo'
VariableDeclarationList varDeclarationList = node.variables;
TypeAnnotation typeAnnotation = varDeclarationList.type;
if (typeAnnotation != null) {
if (typeAnnotation is TypeName) {
strName = _getStringName(typeAnnotation.name);
}
} else {
NodeList<VariableDeclaration> varDeclarations =
varDeclarationList.variables;
if (varDeclarations.length == 1) {
VariableDeclaration varDeclaration = varDeclarations.first;
strName = _getStringName(varDeclaration.name);
}
}
}
if (strName == null) {
return const <CompletionSuggestion>[];
}
var doIncludePrivateVersion = !optype.inMethodBody &&
!optype.inFunctionBody &&
!optype.inConstructorBody;
List<String> variableNameSuggestions = getCamelWordCombinations(strName);
variableNameSuggestions.remove(strName);
List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
for (String varName in variableNameSuggestions) {
CompletionSuggestion suggestion = _createNameSuggestion(varName);
if (suggestion != null) {
suggestions.add(suggestion);
}
if (doIncludePrivateVersion) {
CompletionSuggestion privateSuggestion =
_createNameSuggestion('_' + varName);
if (privateSuggestion != null) {
suggestions.add(privateSuggestion);
}
}
}
return suggestions;
}
return const <CompletionSuggestion>[];
}
}