blob: e7860abf98e31c9b68c433cf323cc958f683be49 [file] [log] [blame]
// 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.local.Declaration.visitor;
import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/scanner.dart';
/**
* `LocalDeclarationCollector` visits an [AstNode] and its parent recursively
* along with any declarations in those nodes. Setting the [finished] flag
* `true` will prevent further recursion.
*/
abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor<bool> {
static final TypeName STACKTRACE_TYPE = new TypeName(
new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, 'StackTrace', 0)),
null);
final int offset;
bool finished = false;
LocalDeclarationVisitor(this.offset);
void declaredClass(ClassDeclaration declaration);
void declaredClassTypeAlias(ClassTypeAlias declaration);
void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl);
void declaredFunction(FunctionDeclaration declaration);
void declaredFunctionTypeAlias(FunctionTypeAlias declaration);
void declaredLabel(Label label, bool isCaseLabel);
void declaredLocalVar(SimpleIdentifier name, TypeName type);
void declaredMethod(MethodDeclaration declaration);
void declaredParam(SimpleIdentifier name, TypeName type);
void declaredTopLevelVar(VariableDeclarationList varList,
VariableDeclaration varDecl);
@override
bool visitBlock(Block node) {
node.statements.forEach((Statement stmt) {
if (stmt.offset < offset) {
if (stmt is VariableDeclarationStatement) {
VariableDeclarationList varList = stmt.variables;
if (varList != null) {
varList.variables.forEach((VariableDeclaration varDecl) {
if (varDecl.end < offset) {
declaredLocalVar(varDecl.name, varList.type);
}
});
}
} else if (stmt is FunctionDeclarationStatement) {
FunctionDeclaration declaration = stmt.functionDeclaration;
if (declaration != null && declaration.offset < offset) {
SimpleIdentifier id = declaration.name;
if (id != null) {
String name = id.name;
if (name != null && name.length > 0) {
declaredFunction(declaration);
}
}
}
}
}
});
return visitNode(node);
}
@override
bool visitCatchClause(CatchClause node) {
SimpleIdentifier param = node.exceptionParameter;
if (param != null) {
declaredParam(param, node.exceptionType);
}
param = node.stackTraceParameter;
if (param != null) {
declaredParam(param, STACKTRACE_TYPE);
}
return visitNode(node);
}
@override
bool visitClassDeclaration(ClassDeclaration node) {
_visitClassDeclarationMembers(node);
visitInheritedTypes(node, (ClassDeclaration classNode) {
_visitClassDeclarationMembers(classNode);
}, (String typeName) {
// ignored
});
return visitNode(node);
}
@override
bool visitCompilationUnit(CompilationUnit node) {
node.declarations.forEach((Declaration declaration) {
if (declaration is ClassDeclaration) {
declaredClass(declaration);
} else if (declaration is EnumDeclaration) {
// TODO (danrubel) enum support
// declaredEnum(........)
} else if (declaration is FunctionDeclaration) {
declaredFunction(declaration);
} else if (declaration is TopLevelVariableDeclaration) {
var varList = declaration.variables;
if (varList != null) {
varList.variables.forEach((VariableDeclaration varDecl) {
declaredTopLevelVar(varList, varDecl);
});
}
} else if (declaration is ClassTypeAlias) {
declaredClassTypeAlias(declaration);
} else if (declaration is FunctionTypeAlias) {
declaredFunctionTypeAlias(declaration);
}
});
return finished;
}
@override
bool visitExpressionStatement(ExpressionStatement node) {
Expression expression = node.expression;
if (expression is SimpleIdentifier) {
if (expression.end < offset) {
return finished;
}
}
return visitNode(node);
}
@override
bool visitForEachStatement(ForEachStatement node) {
SimpleIdentifier id;
TypeName type;
DeclaredIdentifier loopVar = node.loopVariable;
if (loopVar != null) {
id = loopVar.identifier;
type = loopVar.type;
} else {
id = node.identifier;
type = null;
}
declaredLocalVar(id, type);
return visitNode(node);
}
@override
bool visitForStatement(ForStatement node) {
VariableDeclarationList varList = node.variables;
if (varList != null) {
varList.variables.forEach((VariableDeclaration varDecl) {
declaredLocalVar(varDecl.name, varList.type);
});
}
return visitNode(node);
}
@override
bool visitFunctionDeclaration(FunctionDeclaration node) {
// declaredFunction is called by the compilation unit containing it
return visitNode(node);
}
@override
bool visitFunctionExpression(FunctionExpression node) {
_visitParamList(node.parameters);
return visitNode(node);
}
@override
bool visitInterpolationExpression(InterpolationExpression node) {
return visitNode(node);
}
@override
bool visitSwitchStatement(SwitchStatement node) {
for (SwitchMember member in node.members) {
for (Label label in member.labels) {
declaredLabel(label, true);
}
}
return visitNode(node);
}
@override
bool visitLabeledStatement(LabeledStatement node) {
for (Label label in node.labels) {
declaredLabel(label, false);
}
return visitNode(node);
}
@override
bool visitMethodDeclaration(MethodDeclaration node) {
_visitParamList(node.parameters);
return visitNode(node);
}
@override
bool visitNode(AstNode node) {
if (finished) {
return true;
}
return node.parent.accept(this);
}
@override
bool visitStringInterpolation(StringInterpolation node) {
return visitNode(node);
}
void _visitClassDeclarationMembers(ClassDeclaration node) {
node.members.forEach((ClassMember member) {
if (member is FieldDeclaration) {
member.fields.variables.forEach((VariableDeclaration varDecl) {
declaredField(member, varDecl);
});
} else if (member is MethodDeclaration) {
declaredMethod(member);
}
});
}
void _visitParamList(FormalParameterList paramList) {
if (paramList != null) {
paramList.parameters.forEach((FormalParameter param) {
NormalFormalParameter normalParam;
if (param is DefaultFormalParameter) {
normalParam = param.parameter;
} else if (param is NormalFormalParameter) {
normalParam = param;
}
TypeName type = null;
if (normalParam is FieldFormalParameter) {
type = normalParam.type;
} else if (normalParam is FunctionTypedFormalParameter) {
type = normalParam.returnType;
} else if (normalParam is SimpleFormalParameter) {
type = normalParam.type;
}
SimpleIdentifier name = param.identifier;
declaredParam(name, type);
});
}
}
}