blob: c97e96cd954f8e35c5bff902e033159da1f2553e [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 protocol.server;
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/services/search/search_engine.dart' as
engine;
import 'package:analyzer/src/generated/ast.dart' as engine;
import 'package:analyzer/src/generated/element.dart' as engine;
import 'package:analyzer/src/generated/engine.dart' as engine;
import 'package:analyzer/src/generated/error.dart' as engine;
import 'package:analyzer/src/generated/source.dart' as engine;
import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
export 'package:analysis_server/src/protocol.dart';
/**
* Returns a list of AnalysisErrors correponding to the given list of Engine
* errors.
*/
List<AnalysisError> doAnalysisError_listFromEngine(engine.LineInfo lineInfo,
List<engine.AnalysisError> errors) {
return errors.map((engine.AnalysisError error) {
return newAnalysisError_fromEngine(lineInfo, error);
}).toList();
}
/**
* Adds [edit] to the [FileEdit] for the given [element].
*/
void doSourceChange_addElementEdit(SourceChange change, engine.Element element,
SourceEdit edit) {
engine.AnalysisContext context = element.context;
engine.Source source = element.source;
doSourceChange_addSourceEdit(change, context, source, edit);
}
/**
* Adds [edit] to the [FileEdit] for the given [source].
*/
void doSourceChange_addSourceEdit(SourceChange change,
engine.AnalysisContext context, engine.Source source, SourceEdit edit) {
String file = source.fullName;
int fileStamp = context.getModificationStamp(source);
change.addEdit(file, fileStamp, edit);
}
/**
* Construct based on error information from the analyzer engine.
*/
AnalysisError newAnalysisError_fromEngine(engine.LineInfo lineInfo,
engine.AnalysisError error) {
engine.ErrorCode errorCode = error.errorCode;
// prepare location
Location location;
{
String file = error.source.fullName;
int offset = error.offset;
int length = error.length;
int startLine = -1;
int startColumn = -1;
if (lineInfo != null) {
engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset);
if (lineLocation != null) {
startLine = lineLocation.lineNumber;
startColumn = lineLocation.columnNumber;
}
}
location = new Location(file, offset, length, startLine, startColumn);
}
// done
var severity = new AnalysisErrorSeverity(errorCode.errorSeverity.name);
var type = new AnalysisErrorType(errorCode.type.name);
String message = error.message;
String correction = error.correction;
return new AnalysisError(
severity,
type,
location,
message,
correction: correction);
}
/**
* Construct from an analyzer engine element kind.
*/
CompletionSuggestionKind
newCompletionSuggestionKind_fromElementKind(engine.ElementKind kind) {
// ElementKind.ANGULAR_FORMATTER,
// ElementKind.ANGULAR_COMPONENT,
// ElementKind.ANGULAR_CONTROLLER,
// ElementKind.ANGULAR_DIRECTIVE,
// ElementKind.ANGULAR_PROPERTY,
// ElementKind.ANGULAR_SCOPE_PROPERTY,
// ElementKind.ANGULAR_SELECTOR,
// ElementKind.ANGULAR_VIEW,
if (kind == engine.ElementKind.CLASS) return CompletionSuggestionKind.CLASS;
// ElementKind.COMPILATION_UNIT,
if (kind ==
engine.ElementKind.CONSTRUCTOR) return CompletionSuggestionKind.CONSTRUCTOR;
// ElementKind.DYNAMIC,
// ElementKind.EMBEDDED_HTML_SCRIPT,
// ElementKind.ERROR,
// ElementKind.EXPORT,
// ElementKind.EXTERNAL_HTML_SCRIPT,
if (kind == engine.ElementKind.FIELD) return CompletionSuggestionKind.FIELD;
if (kind ==
engine.ElementKind.FUNCTION) return CompletionSuggestionKind.FUNCTION;
if (kind ==
engine.ElementKind.FUNCTION_TYPE_ALIAS) return
CompletionSuggestionKind.FUNCTION_TYPE_ALIAS;
if (kind == engine.ElementKind.GETTER) return CompletionSuggestionKind.GETTER;
// ElementKind.HTML,
if (kind == engine.ElementKind.IMPORT) return CompletionSuggestionKind.IMPORT;
// ElementKind.LABEL,
// ElementKind.LIBRARY,
if (kind ==
engine.ElementKind.LOCAL_VARIABLE) return
CompletionSuggestionKind.LOCAL_VARIABLE;
if (kind == engine.ElementKind.METHOD) return CompletionSuggestionKind.METHOD;
// ElementKind.NAME,
if (kind ==
engine.ElementKind.PARAMETER) return CompletionSuggestionKind.PARAMETER;
// ElementKind.POLYMER_ATTRIBUTE,
// ElementKind.POLYMER_TAG_DART,
// ElementKind.POLYMER_TAG_HTML,
// ElementKind.PREFIX,
if (kind == engine.ElementKind.SETTER) return CompletionSuggestionKind.SETTER;
if (kind ==
engine.ElementKind.TOP_LEVEL_VARIABLE) return
CompletionSuggestionKind.TOP_LEVEL_VARIABLE;
// ElementKind.TYPE_PARAMETER,
// ElementKind.UNIVERSE
throw new ArgumentError('Unknown CompletionSuggestionKind for: $kind');
}
/**
* Construct based on a value from the analyzer engine.
*/
ElementKind newElementKind_fromEngine(engine.ElementKind kind) {
if (kind == engine.ElementKind.CLASS) {
return ElementKind.CLASS;
}
if (kind == engine.ElementKind.COMPILATION_UNIT) {
return ElementKind.COMPILATION_UNIT;
}
if (kind == engine.ElementKind.CONSTRUCTOR) {
return ElementKind.CONSTRUCTOR;
}
if (kind == engine.ElementKind.FIELD) {
return ElementKind.FIELD;
}
if (kind == engine.ElementKind.FUNCTION) {
return ElementKind.FUNCTION;
}
if (kind == engine.ElementKind.FUNCTION_TYPE_ALIAS) {
return ElementKind.FUNCTION_TYPE_ALIAS;
}
if (kind == engine.ElementKind.GETTER) {
return ElementKind.GETTER;
}
if (kind == engine.ElementKind.LABEL) {
return ElementKind.LABEL;
}
if (kind == engine.ElementKind.LIBRARY) {
return ElementKind.LIBRARY;
}
if (kind == engine.ElementKind.LOCAL_VARIABLE) {
return ElementKind.LOCAL_VARIABLE;
}
if (kind == engine.ElementKind.METHOD) {
return ElementKind.METHOD;
}
if (kind == engine.ElementKind.PARAMETER) {
return ElementKind.PARAMETER;
}
if (kind == engine.ElementKind.PREFIX) {
return ElementKind.PREFIX;
}
if (kind == engine.ElementKind.SETTER) {
return ElementKind.SETTER;
}
if (kind == engine.ElementKind.TOP_LEVEL_VARIABLE) {
return ElementKind.TOP_LEVEL_VARIABLE;
}
if (kind == engine.ElementKind.TYPE_PARAMETER) {
return ElementKind.TYPE_PARAMETER;
}
return ElementKind.UNKNOWN;
}
/**
* Construct based on a value from the analyzer engine.
*/
Element newElement_fromEngine(engine.Element element) {
String name = element.displayName;
String elementParameters = _getParametersString(element);
String elementReturnType = _getReturnTypeString(element);
return new Element(
newElementKind_fromEngine(element.kind),
name,
Element.makeFlags(
isPrivate: element.isPrivate,
isDeprecated: element.isDeprecated,
isAbstract: _isAbstract(element),
isConst: _isConst(element),
isFinal: _isFinal(element),
isStatic: _isStatic(element)),
location: newLocation_fromElement(element),
parameters: elementParameters,
returnType: elementReturnType);
}
/**
* Create a Location based on an [engine.Element].
*/
Location newLocation_fromElement(engine.Element element) {
engine.AnalysisContext context = element.context;
engine.Source source = element.source;
if (context == null || source == null) {
return null;
}
String name = element.displayName;
int offset = element.nameOffset;
int length = name != null ? name.length : 0;
if (element is engine.CompilationUnitElement) {
offset = 0;
length = 0;
}
engine.SourceRange range = new engine.SourceRange(offset, length);
return _locationForArgs(context, source, range);
}
/**
* Create a Location based on an [engine.SearchMatch].
*/
Location newLocation_fromMatch(engine.SearchMatch match) {
engine.Element enclosingElement = match.element;
return _locationForArgs(
enclosingElement.context,
enclosingElement.source,
match.sourceRange);
}
/**
* Create a Location based on an [engine.AstNode].
*/
Location newLocation_fromNode(engine.AstNode node) {
engine.CompilationUnit unit =
node.getAncestor((node) => node is engine.CompilationUnit);
engine.CompilationUnitElement unitElement = unit.element;
engine.AnalysisContext context = unitElement.context;
engine.Source source = unitElement.source;
engine.SourceRange range = new engine.SourceRange(node.offset, node.length);
return _locationForArgs(context, source, range);
}
/**
* Create a Location based on an [engine.CompilationUnit].
*/
Location newLocation_fromUnit(engine.CompilationUnit unit,
engine.SourceRange range) {
engine.CompilationUnitElement unitElement = unit.element;
engine.AnalysisContext context = unitElement.context;
engine.Source source = unitElement.source;
return _locationForArgs(context, source, range);
}
/**
* Construct based on an element from the analyzer engine.
*/
OverriddenMember newOverriddenMember_fromEngine(engine.Element member) {
Element element = newElement_fromEngine(member);
String className = member.enclosingElement.displayName;
return new OverriddenMember(element, className);
}
/**
* Construct based on a value from the search engine.
*/
SearchResultKind newSearchResultKind_fromEngine(engine.MatchKind kind) {
if (kind == engine.MatchKind.DECLARATION) {
return SearchResultKind.DECLARATION;
}
if (kind == engine.MatchKind.READ) {
return SearchResultKind.READ;
}
if (kind == engine.MatchKind.READ_WRITE) {
return SearchResultKind.READ_WRITE;
}
if (kind == engine.MatchKind.WRITE) {
return SearchResultKind.WRITE;
}
if (kind == engine.MatchKind.INVOCATION) {
return SearchResultKind.INVOCATION;
}
if (kind == engine.MatchKind.REFERENCE) {
return SearchResultKind.REFERENCE;
}
return SearchResultKind.UNKNOWN;
}
/**
* Construct based on a value from the search engine.
*/
SearchResult newSearchResult_fromMatch(engine.SearchMatch match) {
SearchResultKind kind = newSearchResultKind_fromEngine(match.kind);
Location location = newLocation_fromMatch(match);
List<Element> path = _computePath(match.element);
return new SearchResult(location, kind, !match.isResolved, path);
}
/**
* Construct based on a SourceRange.
*/
SourceEdit newSourceEdit_range(engine.SourceRange range, String replacement,
{String id}) {
return new SourceEdit(range.offset, range.length, replacement, id: id);
}
List<Element> _computePath(engine.Element element) {
List<Element> path = <Element>[];
while (element != null) {
path.add(newElement_fromEngine(element));
// go up
if (element is engine.PrefixElement) {
// imports are library children, but they are physically in the unit
engine.LibraryElement library = element.enclosingElement;
element = library.definingCompilationUnit;
} else {
element = element.enclosingElement;
}
}
return path;
}
String _getParametersString(engine.Element element) {
// TODO(scheglov) expose the corresponding feature from ExecutableElement
if (element is engine.ExecutableElement) {
var sb = new StringBuffer();
String closeOptionalString = '';
for (var parameter in element.parameters) {
if (sb.isNotEmpty) {
sb.write(', ');
}
if (closeOptionalString.isEmpty) {
if (parameter.kind == engine.ParameterKind.NAMED) {
sb.write('{');
closeOptionalString = '}';
}
if (parameter.kind == engine.ParameterKind.POSITIONAL) {
sb.write('[');
closeOptionalString = ']';
}
}
sb.write(parameter.toString());
}
sb.write(closeOptionalString);
return '(' + sb.toString() + ')';
} else {
return null;
}
}
String _getReturnTypeString(engine.Element element) {
if (element is engine.ExecutableElement) {
if (element.kind == engine.ElementKind.SETTER) {
return null;
} else {
return element.returnType.toString();
}
} else {
return null;
}
}
bool _isAbstract(engine.Element element) {
// TODO(scheglov) add isAbstract to Element API
if (element is engine.ClassElement) {
return element.isAbstract;
}
if (element is engine.MethodElement) {
return element.isAbstract;
}
if (element is engine.PropertyAccessorElement) {
return element.isAbstract;
}
return false;
}
bool _isConst(engine.Element element) {
// TODO(scheglov) add isConst to Element API
if (element is engine.ConstructorElement) {
return element.isConst;
}
if (element is engine.VariableElement) {
return element.isConst;
}
return false;
}
bool _isFinal(engine.Element element) {
// TODO(scheglov) add isFinal to Element API
if (element is engine.VariableElement) {
return element.isFinal;
}
return false;
}
bool _isStatic(engine.Element element) {
// TODO(scheglov) add isStatic to Element API
if (element is engine.ExecutableElement) {
return element.isStatic;
}
if (element is engine.PropertyInducingElement) {
return element.isStatic;
}
return false;
}
/**
* Creates a new [Location].
*/
Location _locationForArgs(engine.AnalysisContext context, engine.Source source,
engine.SourceRange range) {
int startLine = 0;
int startColumn = 0;
{
engine.LineInfo lineInfo = context.getLineInfo(source);
if (lineInfo != null) {
engine.LineInfo_Location offsetLocation =
lineInfo.getLocation(range.offset);
startLine = offsetLocation.lineNumber;
startColumn = offsetLocation.columnNumber;
}
}
return new Location(
source.fullName,
range.offset,
range.length,
startLine,
startColumn);
}