blob: ad923864b3a1966a3e62596f991624f321108aa8 [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 computer.overrides;
import 'package:analysis_server/src/computer/element.dart';
import 'package:analysis_services/constants.dart';
import 'package:analysis_services/json.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart' as engine;
/**
* A computer for class member overrides in a Dart [CompilationUnit].
*/
class DartUnitOverridesComputer {
final CompilationUnit _unit;
final List<Override> _overrides = <Override>[];
engine.ClassElement _currentClass;
DartUnitOverridesComputer(this._unit);
/**
* Returns the computed occurrences, not `null`.
*/
List<Override> compute() {
for (CompilationUnitMember unitMember in _unit.declarations) {
if (unitMember is ClassDeclaration) {
_currentClass = unitMember.element;
for (ClassMember classMember in unitMember.members) {
if (classMember is MethodDeclaration) {
SimpleIdentifier nameNode = classMember.name;
_addOverride(nameNode.offset, nameNode.length, nameNode.name);
}
if (classMember is FieldDeclaration) {
List<VariableDeclaration> fields = classMember.fields.variables;
for (VariableDeclaration field in fields) {
SimpleIdentifier nameNode = field.name;
_addOverride(nameNode.offset, nameNode.length, nameNode.name);
}
}
}
}
}
return _overrides.map((override) => override.toJson()).toList();
}
void _addOverride(int offset, int length, String name) {
// super
engine.Element superEngineElement;
{
engine.InterfaceType superType = _currentClass.supertype;
if (superType != null) {
superEngineElement = _lookupMember(superType.element, name);
}
}
// interfaces
List<engine.Element> interfaceEngineElements = <engine.Element>[];
for (engine.InterfaceType interfaceType in _currentClass.interfaces) {
engine.ClassElement interfaceElement = interfaceType.element;
engine.Element interfaceMember = _lookupMember(interfaceElement, name);
if (interfaceMember != null) {
interfaceEngineElements.add(interfaceMember);
}
}
// is there any override?
if (superEngineElement != null || interfaceEngineElements.isNotEmpty) {
OverriddenMember superMember = superEngineElement != null ?
OverriddenMember.fromEngine(superEngineElement) :
null;
List<OverriddenMember> interfaceMembers =
interfaceEngineElements.map(OverriddenMember.fromEngine).toList();
_overrides.add(
new Override(offset, length, superMember, interfaceMembers));
}
}
static engine.Element _lookupMember(engine.ClassElement classElement,
String name) {
if (classElement == null) {
return null;
}
engine.LibraryElement library = classElement.library;
// method
engine.Element member = classElement.lookUpMethod(name, library);
if (member != null) {
return member;
}
// getter
member = classElement.lookUpGetter(name, library);
if (member != null) {
return member;
}
// setter
member = classElement.lookUpSetter(name + '=', library);
if (member != null) {
return member;
}
// not found
return null;
}
}
class OverriddenMember implements HasToJson {
final Element element;
final String className;
OverriddenMember(this.element, this.className);
Map<String, Object> toJson() {
return {
ELEMENT: element.toJson(),
CLASS_NAME: className
};
}
@override
String toString() => toJson().toString();
static OverriddenMember fromEngine(engine.Element member) {
Element element = new Element.fromEngine(member);
String className = member.enclosingElement.displayName;
return new OverriddenMember(element, className);
}
static OverriddenMember fromJson(Map<String, Object> json) {
Map<String, Object> elementJson = json[ELEMENT];
Element element = new Element.fromJson(elementJson);
String className = json[CLASS_NAME];
return new OverriddenMember(element, className);
}
}
class Override implements HasToJson {
final int offset;
final int length;
final OverriddenMember superclassMember;
final List<OverriddenMember> interfaceMembers;
Override(this.offset, this.length, this.superclassMember,
this.interfaceMembers);
Map<String, Object> toJson() {
Map<String, Object> json = <String, Object>{};
json[OFFSET] = offset;
json[LENGTH] = length;
if (superclassMember != null) {
json[SUPER_CLASS_MEMBER] = superclassMember.toJson();
}
if (interfaceMembers != null && interfaceMembers.isNotEmpty) {
json[INTERFACE_MEMBERS] = objectToJson(interfaceMembers);
}
return json;
}
@override
String toString() => toJson().toString();
static Override fromJson(Map<String, Object> map) {
int offset = map[OFFSET];
int length = map[LENGTH];
// super
OverriddenMember superclassMember = null;
{
Map<String, Object> superJson = map[SUPER_CLASS_MEMBER];
if (superJson != null) {
superclassMember = OverriddenMember.fromJson(superJson);
}
}
// interfaces
List<OverriddenMember> interfaceElements = null;
{
List<Map<String, Object>> jsonList = map[INTERFACE_MEMBERS];
if (jsonList != null) {
interfaceElements = jsonList.map(OverriddenMember.fromJson).toList();
}
}
// done
return new Override(offset, length, superclassMember, interfaceElements);
}
}