Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Unified Diff: pkg/analysis_server/lib/src/services/completion/optype_ast_visitor.dart

Issue 804323002: refactor duplicate code into single visitor (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merge and address comments Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/lib/src/services/completion/optype_ast_visitor.dart
diff --git a/pkg/analysis_server/lib/src/services/completion/optype_ast_visitor.dart b/pkg/analysis_server/lib/src/services/completion/optype_ast_visitor.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d4e6e1dbc8b61d1bd1106e71355b9cad62373cb3
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/optype_ast_visitor.dart
@@ -0,0 +1,444 @@
+// Copyright (c) 2014, 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.
+
+library services.completion.computer.dart.optype;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+
+/**
+ * An [AstVisitor] for determining whether top level suggestions or invocation
+ * suggestions should be made based upon the type of node in which the
+ * suggestions were requested.
+ */
+class OpTypeAstVisitor extends GeneralizingAstVisitor {
+
+ /**
+ * The offset within the source at which the completion is requested.
+ */
+ int offset;
+
+ /**
+ * Indicates whether invocation suggestions should be included.
+ */
+ bool includeInvocationSuggestions = false;
+
+ /**
+ * Indicates whether type names should be suggested.
+ */
+ bool includeTypeNameSuggestions = false;
+
+ /**
+ * Indicates whether setters along with methods and functions that
+ * have a [void] return type should be suggested.
+ */
+ bool includeVoidReturnSuggestions = false;
+
+ /**
+ * Indicates whether fields and getters along with methods and functions that
+ * have a non-[void] return type should be suggested.
+ */
+ bool includeReturnValueSuggestions = false;
+
+ OpTypeAstVisitor(this.offset);
+
+ /**
+ * Indicate whether only type names should be suggested
+ */
+ bool get includeOnlyTypeNameSuggestions =>
+ includeTypeNameSuggestions &&
+ !includeReturnValueSuggestions &&
+ !includeVoidReturnSuggestions &&
+ !includeInvocationSuggestions;
+
+ /**
+ * Indicate whether top level elements should be suggested
+ */
+ bool get includeTopLevelSuggestions =>
+ includeReturnValueSuggestions ||
+ includeTypeNameSuggestions ||
+ includeVoidReturnSuggestions;
+
+ bool isAfterSemicolon(Token semicolon) =>
+ semicolon != null && !semicolon.isSynthetic && semicolon.offset < offset;
+
+ @override
+ void visitAnnotation(Annotation node) {
+ Token atSign = node.atSign;
+ if (atSign == null || offset <= atSign.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ } else {
+ Token period = node.period;
+ if (period == null || offset <= period.offset) {
+ includeTypeNameSuggestions = true;
+ includeReturnValueSuggestions = true;
+ } else {
+ includeInvocationSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitArgumentList(ArgumentList node) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+
+ @override
+ void visitBlock(Block node) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+
+ @override
+ void visitCascadeExpression(CascadeExpression node) {
+ Expression target = node.target;
+ if (target != null && offset <= target.end) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ } else {
+ includeInvocationSuggestions = true;
+ }
+ }
+
+ @override
+ void visitClassDeclaration(ClassDeclaration node) {
+ // Make suggestions in the body of the class declaration
+ Token leftBracket = node.leftBracket;
+ if (leftBracket != null && offset >= leftBracket.end) {
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitClassMember(ClassMember node) {
+ if (offset <= node.offset || node.end <= offset) {
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitCommentReference(CommentReference node) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+
+ @override
+ visitConstructorName(ConstructorName node) {
+ // some PrefixedIdentifier nodes are transformed into
+ // ConstructorName nodes during the resolution process.
+ Token period = node.period;
+ if (period != null && offset > period.offset) {
+ TypeName type = node.type;
+ if (type != null) {
+ SimpleIdentifier prefix = type.name;
+ if (prefix != null) {
+ includeInvocationSuggestions = true;
+ }
+ }
+ }
+ }
+
+ @override
+ void visitDoStatement(DoStatement node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && leftParen.end <= offset) {
+ Token rightParen = node.rightParenthesis;
+ if (rightParen == null || offset <= rightParen.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitEmptyStatement(EmptyStatement node) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+
+ @override
+ void visitExpression(Expression node) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+
+ @override
+ void visitExpressionFunctionBody(ExpressionFunctionBody node) {
+ Token functionDefinition = node.functionDefinition;
+ if (functionDefinition != null && functionDefinition.end <= offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitExpressionStatement(ExpressionStatement node) {
+ Expression expression = node.expression;
+ // A pre-variable declaration (e.g. C ^) is parsed as an expression
+ // statement. Do not make suggestions for the variable name.
+ if (expression is SimpleIdentifier && offset <= expression.end) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ } else {
+ Token semicolon = node.semicolon;
+ if (semicolon != null && semicolon.end <= offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitExtendsClause(ExtendsClause node) {
+ Token keyword = node.keyword;
+ if (keyword != null && keyword.end < offset) {
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitForEachStatement(ForEachStatement node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && leftParen.end <= offset) {
+ Token rightParen = node.rightParenthesis;
+ if (rightParen == null || offset <= rightParen.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitFormalParameterList(FormalParameterList node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && offset > leftParen.offset) {
+ Token rightParen = node.rightParenthesis;
+ if (rightParen == null || offset <= rightParen.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitForStatement(ForStatement node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && offset >= leftParen.end) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ // TODO (danrubel) void return suggestions only belong after
+ // the 2nd semicolon. Return value suggestions only belong after the
+ // e1st or second semicolon.
+ }
+ }
+
+ @override
+ void visitFunctionTypeAlias(FunctionTypeAlias node) {
+ Token keyword = node.keyword;
+ if (keyword != null && keyword.end <= offset) {
+ SimpleIdentifier id = node.name;
+ if (id != null) {
+ TypeName returnType = node.returnType;
+ if (offset <= (returnType != null ? returnType.end : id.end)) {
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+ }
+
+ @override
+ void visitIfStatement(IfStatement node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && offset >= leftParen.end) {
+ Token rightParen = node.rightParenthesis;
+ if (rightParen == null || offset <= rightParen.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitImplementsClause(ImplementsClause node) {
+ Token keyword = node.keyword;
+ if (keyword != null && keyword.end < offset) {
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitInterpolationExpression(InterpolationExpression node) {
+ Expression expression = node.expression;
+ if (expression is SimpleIdentifier) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitMethodDeclaration(MethodDeclaration node) {
+ SimpleIdentifier id = node.name;
+ if (id != null && offset < id.offset) {
+ includeTypeNameSuggestions = true;
+ }
+ visitClassMember(node);
+ }
+
+ @override
+ void visitMethodInvocation(MethodInvocation node) {
+ Token period = node.period;
+ if (period == null || offset <= period.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ } else {
+ includeInvocationSuggestions = true;
+ }
+ }
+
+ @override
+ void visitNode(AstNode node) {
+ // no suggestion by default
+ }
+
+ @override
+ void visitNormalFormalParameter(NormalFormalParameter node) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+
+ @override
+ void visitPrefixedIdentifier(PrefixedIdentifier node) {
+ Token period = node.period;
+ if (period == null || offset <= period.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ } else {
+ includeInvocationSuggestions = true;
+ }
+ }
+
+ @override
+ void visitPropertyAccess(PropertyAccess node) {
+ var operator = node.operator;
+ if (operator != null && offset < operator.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ } else {
+ includeInvocationSuggestions = true;
+ }
+ }
+
+ @override
+ void visitReturnStatement(ReturnStatement node) {
+ Token keyword = node.keyword;
+ if (keyword != null && keyword.end < offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitSimpleIdentifier(SimpleIdentifier node) {
+ node.parent.accept(this);
+ }
+
+ @override
+ void visitStringLiteral(StringLiteral node) {
+ // no suggestions
+ }
+
+ @override
+ void visitSwitchCase(SwitchCase node) {
+ Token keyword = node.keyword;
+ if (keyword == null || keyword.end < offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+ }
+
+ @override
+ void visitSwitchStatement(SwitchStatement node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && leftParen.end <= offset) {
+ Token rightParen = node.rightParenthesis;
+ if (rightParen == null || offset <= rightParen.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+
+ @override
+ void visitTypeName(TypeName node) {
+ // If suggesting completions within a TypeName node
+ // then limit suggestions to only types in specific situations
+ AstNode p = node.parent;
+ if (p is IsExpression || p is ConstructorName || p is AsExpression) {
+ includeTypeNameSuggestions = true;
+ // TODO (danrubel) Possible future improvement:
+ // on the RHS of an "is" or "as" expression, don't suggest types that are
+ // guaranteed to pass or guaranteed to fail the cast.
+ // See dartbug.com/18860
+ } else if (p is VariableDeclarationList) {
+ // TODO (danrubel) When entering 1st of 2 identifiers on assignment LHS
+ // the user may be either (1) entering a type for the assignment
+ // or (2) starting a new statement.
+ // Consider suggesting only types
+ // if only spaces separates the 1st and 2nd identifiers.
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ } else {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+ }
+
+ @override
+ void visitTypeParameter(TypeParameter node) {
+ includeTypeNameSuggestions = true;
+ }
+
+ @override
+ void visitVariableDeclaration(VariableDeclaration node) {
+ Token equals = node.equals;
+ // Make suggestions for the RHS of a variable declaration
+ if (equals != null && offset >= equals.end) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
+ void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+ if (isAfterSemicolon(node.semicolon)) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ includeVoidReturnSuggestions = true;
+ }
+ }
+
+ @override
+ void visitWhileStatement(WhileStatement node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && leftParen.end <= offset) {
+ Token rightParen = node.rightParenthesis;
+ if (rightParen == null || offset <= rightParen.offset) {
+ includeReturnValueSuggestions = true;
+ includeTypeNameSuggestions = true;
+ }
+ }
+ }
+}
« no previous file with comments | « pkg/analysis_server/lib/src/services/completion/local_computer.dart ('k') | pkg/analysis_server/test/completion_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698