Skip to content

Commit

Permalink
Resynthesize expressions for Kernel's StaticGet and PropertyGet.
Browse files Browse the repository at this point in the history
Note, that we don't restore the original AST for StaticGet(s).
The original AST is not available in Kernel.
Instead we generate simple identifiers with correct elements.
It should be enough to compute constant values, although some clients
might have to adapt to the change.

[email protected]
BUG=

Review-Url: https://codereview.chromium.org/2983773002 .
  • Loading branch information
scheglov committed Jul 18, 2017
1 parent ab39958 commit 9d5a249
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 45 deletions.
20 changes: 15 additions & 5 deletions pkg/analyzer/lib/src/dart/element/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1823,7 +1823,7 @@ class CompilationUnitElementImpl extends UriReferencedElementImpl
return typeImpl;
}
}
for (ClassElement type in _enums) {
for (ClassElement type in enums) {
EnumElementImpl typeImpl = type;
if (typeImpl.identifier == identifier) {
return typeImpl;
Expand Down Expand Up @@ -1919,6 +1919,13 @@ class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement {
ConstFieldElementImpl.forSerialized(
UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(unlinkedVariable, enclosingElement);

/**
* Initialize using the given kernel.
*/
ConstFieldElementImpl.forKernel(
ElementImpl enclosingElement, kernel.Field kernel)
: super.forKernel(enclosingElement, kernel);
}

/**
Expand Down Expand Up @@ -4337,18 +4344,21 @@ class FieldElementImpl extends PropertyInducingElementImpl
FieldElementImpl(String name, int offset) : super(name, offset);

/**
* Initialize using the given serialized information.
* Initialize using the given kernel.
*/
FieldElementImpl.forKernel(ElementImpl enclosingElement, kernel.Field kernel)
: super.forKernel(enclosingElement, kernel);

/**
* Initialize using the given serialized information.
* Initialize using the given kernel.
*/
factory FieldElementImpl.forKernelFactory(
ClassElementImpl enclosingClass, kernel.Field kernel) {
// TODO(scheglov) add support for constants.
return new FieldElementImpl.forKernel(enclosingClass, kernel);
if (kernel.isConst) {
return new ConstFieldElementImpl.forKernel(enclosingClass, kernel);
} else {
return new FieldElementImpl.forKernel(enclosingClass, kernel);
}
}

/**
Expand Down
25 changes: 23 additions & 2 deletions pkg/analyzer/test/src/summary/resynthesize_common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ abstract class AbstractResynthesizeTest extends AbstractSingleUnitTest {
*/
bool shouldCompareLibraryElements = true;

/**
* Return `true` if shared front-end is used.
*/
bool get isSharedFrontEnd => false;

/**
* Return `true` if resynthesizing should be done is strong mode.
*/
Expand Down Expand Up @@ -3686,10 +3691,17 @@ const int v =
const v = 'abc'.length;
''');
if (isStrongMode) {
checkElementText(library, r'''
if (isSharedFrontEnd) {
checkElementText(library, r'''
const int v = 'abc'.
length/*location: dart:core;String;length?*/;
''');
} else {
checkElementText(library, r'''
const dynamic v/*error: instanceGetter*/ = 'abc'.
length/*location: dart:core;String;length?*/;
''');
}
} else {
checkElementText(library, r'''
const dynamic v = 'abc'.
Expand All @@ -3704,12 +3716,21 @@ const String S = 'abc';
const v = S.length;
''');
if (isStrongMode) {
checkElementText(library, r'''
if (isSharedFrontEnd) {
checkElementText(library, r'''
const String S = 'abc';
const int v =
S/*location: test.dart;S?*/.
length/*location: dart:core;String;length?*/;
''');
} else {
checkElementText(library, r'''
const String S = 'abc';
const dynamic v/*error: instanceGetter*/ =
S/*location: test.dart;S?*/.
length/*location: dart:core;String;length?*/;
''');
}
} else {
checkElementText(library, r'''
const String S = 'abc';
Expand Down
167 changes: 129 additions & 38 deletions pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'dart:async';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
Expand Down Expand Up @@ -41,6 +42,9 @@ main() {
class ResynthesizeKernelStrongTest extends ResynthesizeTest {
final resourceProvider = new MemoryResourceProvider(context: pathos.posix);

@override
bool get isSharedFrontEnd => true;

@override
bool get isStrongMode => true;

Expand Down Expand Up @@ -223,11 +227,6 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
await super.test_class_documented_withLeadingNotDocumentation();
}

@failingTest
test_class_field_const() async {
await super.test_class_field_const();
}

@failingTest
test_class_interfaces_unresolved() async {
await super.test_class_interfaces_unresolved();
Expand Down Expand Up @@ -405,11 +404,6 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
await super.test_const_invokeConstructor_unnamed_unresolved3();
}

@failingTest
test_const_length_ofClassConstField() async {
await super.test_const_length_ofClassConstField();
}

@failingTest
test_const_length_ofClassConstField_imported() async {
await super.test_const_length_ofClassConstField_imported();
Expand All @@ -420,16 +414,6 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
await super.test_const_length_ofClassConstField_imported_withPrefix();
}

@failingTest
test_const_length_ofStringLiteral() async {
await super.test_const_length_ofStringLiteral();
}

@failingTest
test_const_length_ofTopLevelVariable() async {
await super.test_const_length_ofTopLevelVariable();
}

@failingTest
test_const_length_ofTopLevelVariable_imported() async {
await super.test_const_length_ofTopLevelVariable_imported();
Expand Down Expand Up @@ -467,11 +451,6 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
await super.test_const_parameterDefaultValue_normal();
}

@failingTest
test_const_reference_staticField() async {
await super.test_const_reference_staticField();
}

@failingTest
test_const_reference_staticField_imported() async {
await super.test_const_reference_staticField_imported();
Expand Down Expand Up @@ -642,11 +621,6 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
await super.test_constExpr_pushReference_enum_method();
}

@failingTest
test_constExpr_pushReference_field_simpleIdentifier() async {
await super.test_constExpr_pushReference_field_simpleIdentifier();
}

@failingTest
test_constExpr_pushReference_staticMethod_simpleIdentifier() async {
await super.test_constExpr_pushReference_staticMethod_simpleIdentifier();
Expand Down Expand Up @@ -983,11 +957,6 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
await super.test_field_formal_param_inferred_type_implicit();
}

@failingTest
test_field_propagatedType_const_noDep() async {
await super.test_field_propagatedType_const_noDep();
}

@failingTest
test_field_propagatedType_final_dep_inLib() async {
await super.test_field_propagatedType_final_dep_inLib();
Expand Down Expand Up @@ -2172,6 +2141,10 @@ class ResynthesizeKernelStrongTest extends ResynthesizeTest {
* Builder of [Expression]s from [kernel.Expression]s.
*/
class _ExprBuilder {
final _KernelLibraryResynthesizerContextImpl _context;

_ExprBuilder(this._context);

Expression build(kernel.Expression expr) {
if (expr is kernel.NullLiteral) {
return AstTestFactory.nullLiteral();
Expand Down Expand Up @@ -2199,8 +2172,47 @@ class _ExprBuilder {
List<String> components = expr.value.split('.').toList();
return AstTestFactory.symbolLiteral(components);
}
if (expr is kernel.StaticGet) {
return _buildIdentifier(expr.targetReference, isGet: true);
}
if (expr is kernel.PropertyGet) {
Expression target = build(expr.receiver);
kernel.Reference reference = expr.interfaceTargetReference;
SimpleIdentifier identifier = _buildSimpleIdentifier(reference);
return AstTestFactory.propertyAccess(target, identifier);
}
// TODO(scheglov): complete getExpression
throw new UnimplementedError('kernel: $expr');
throw new UnimplementedError('kernel: (${expr.runtimeType}) $expr');
}

Expression _buildIdentifier(kernel.Reference reference, {bool isGet: false}) {
Element element = _getElement(reference);
if (isGet && element is PropertyInducingElement) {
element = (element as PropertyInducingElement).getter;
}
SimpleIdentifier property = AstTestFactory.identifier3(element.displayName)
..staticElement = element;
Element enclosingElement = element.enclosingElement;
if (enclosingElement is ClassElement) {
SimpleIdentifier classRef = AstTestFactory
.identifier3(enclosingElement.name)
..staticElement = enclosingElement;
return AstTestFactory.propertyAccess(classRef, property);
} else {
return property;
}
}

SimpleIdentifier _buildSimpleIdentifier(kernel.Reference reference) {
String name = reference.canonicalName.name;
SimpleIdentifier identifier = AstTestFactory.identifier3(name);
Element element = _getElement(reference);
identifier.staticElement = element;
return identifier;
}

ElementImpl _getElement(kernel.Reference reference) {
return _context._getElement(reference?.canonicalName);
}

InterpolationElement _newInterpolationElement(Expression expr) {
Expand Down Expand Up @@ -2268,7 +2280,7 @@ class _KernelLibraryResynthesizerContextImpl

@override
Expression getExpression(kernel.Expression expression) {
return new _ExprBuilder().build(expression);
return new _ExprBuilder(this).build(expression);
}

@override
Expand All @@ -2289,6 +2301,64 @@ class _KernelLibraryResynthesizerContextImpl
throw new UnimplementedError('For ${kernelType.runtimeType}');
}

/**
* Return the [ElementImpl] that corresponds to the given [name], or `null`
* if the corresponding element cannot be found.
*/
ElementImpl _getElement(kernel.CanonicalName name) {
if (name == null) return null;
kernel.CanonicalName parentName = name.parent;

// If the parent is the root, then this name is a library.
if (parentName.isRoot) {
return _resynthesizer.getLibrary(name.name);
}

// Skip qualifiers.
bool isGetter = false;
bool isSetter = false;
bool isField = false;
if (parentName.name == '@getters') {
isGetter = true;
parentName = parentName.parent;
} else if (parentName.name == '@setters') {
isSetter = true;
parentName = parentName.parent;
} else if (parentName.name == '@fields') {
isField = true;
parentName = parentName.parent;
}

ElementImpl parentElement = _getElement(parentName);
if (parentElement == null) return null;

// Search in units of the library.
if (parentElement is LibraryElementImpl) {
for (CompilationUnitElement unit in parentElement.units) {
CompilationUnitElementImpl unitImpl = unit;
ElementImpl child = unitImpl.getChild(name.name);
if (child != null) {
return child;
}
}
return null;
}

// Search in the class.
if (parentElement is ClassElementImpl) {
if (isGetter) {
return parentElement.getGetter(name.name) as ElementImpl;
} else if (isSetter) {
return parentElement.getSetter(name.name) as ElementImpl;
} else if (isField) {
return parentElement.getField(name.name) as ElementImpl;
}
return null;
}

throw new UnimplementedError('Should not be reached.');
}

InterfaceType _getInterfaceType(
kernel.CanonicalName className, List<kernel.DartType> kernelArguments) {
var libraryName = className.parent;
Expand All @@ -2314,15 +2384,36 @@ class _KernelResynthesizer {
final Map<String, kernel.Library> _kernelMap;
final Map<String, LibraryElementImpl> _libraryMap = {};

/**
* Cache of [Source] objects that have already been converted from URIs.
*/
final Map<String, Source> _sources = <String, Source>{};

_KernelResynthesizer(this._analysisContext, this._kernelMap);

LibraryElementImpl getLibrary(String uriStr) {
return _libraryMap.putIfAbsent(uriStr, () {
var kernel = _kernelMap[uriStr];
if (kernel == null) return null;

var libraryContext =
new _KernelLibraryResynthesizerContextImpl(this, kernel);
return new LibraryElementImpl.forKernel(_analysisContext, libraryContext);
Source librarySource = _getSource(uriStr);
LibraryElementImpl libraryElement =
new LibraryElementImpl.forKernel(_analysisContext, libraryContext);
CompilationUnitElementImpl definingUnit =
libraryElement.definingCompilationUnit;
definingUnit.source = librarySource;
definingUnit.librarySource = librarySource;
return libraryElement;
});
}

/**
* Get the [Source] object for the given [uri].
*/
Source _getSource(String uri) {
return _sources.putIfAbsent(
uri, () => _analysisContext.sourceFactory.forUri(uri));
}
}

0 comments on commit 9d5a249

Please sign in to comment.