Index: pkg/smoke/lib/codegen/recorder.dart |
diff --git a/pkg/smoke/lib/codegen/recorder.dart b/pkg/smoke/lib/codegen/recorder.dart |
index be4c96b9080e2ca7c6aec70935818faeda761c19..6e6f457d1f8a15af70b31f68c2658d0009b26b8c 100644 |
--- a/pkg/smoke/lib/codegen/recorder.dart |
+++ b/pkg/smoke/lib/codegen/recorder.dart |
@@ -63,28 +63,31 @@ class Recorder { |
if (!baseType.type.isObject) generator.addParent(_typeFor(type), baseId); |
} |
- TypeIdentifier _typeFor(ClassElement type) => |
- new TypeIdentifier(importUrlFor(type.library), type.displayName); |
+ TypeIdentifier _typeFor(Element type) => new TypeIdentifier( |
+ type.library == null ? 'dart:core' : importUrlFor(type.library), |
+ type.displayName); |
/// Adds any declaration and superclass information that is needed to answer a |
- /// query on [type] that matches [options]. |
- void runQuery(ClassElement type, QueryOptions options) { |
+ /// query on [type] that matches [options]. Also adds symbols, getters, and |
+ /// setters if [includeAccessors] is true. |
+ void runQuery(ClassElement type, QueryOptions options, |
+ {bool includeAccessors: true}) { |
if (type.type.isObject) return; // We don't include Object in query results. |
var id = _typeFor(type); |
var parent = type.supertype != null ? type.supertype.element : null; |
if (options.includeInherited && parent != null && |
parent != options.includeUpTo) { |
lookupParent(type); |
- runQuery(parent, options); |
+ runQuery(parent, options, includeAccessors: includeAccessors); |
var parentId = _typeFor(parent); |
for (var m in type.mixins) { |
var mixinClass = m.element; |
var mixinId = _mixins[parentId][mixinClass]; |
- _runQueryInternal(mixinClass, mixinId, options); |
+ _runQueryInternal(mixinClass, mixinId, options, includeAccessors); |
parentId = mixinId; |
} |
} |
- _runQueryInternal(type, id, options); |
+ _runQueryInternal(type, id, options, includeAccessors); |
} |
/// Helper for [runQuery]. This runs the query only on a specific [type], |
@@ -93,7 +96,7 @@ class Recorder { |
// we should consider to include the mixin declaration information directly, |
// and remove the duplication we have for mixins today. |
void _runQueryInternal(ClassElement type, TypeIdentifier id, |
- QueryOptions options) { |
+ QueryOptions options, bool includeAccessors) { |
skipBecauseOfAnnotations(Element e) { |
if (options.withAnnotations == null) return false; |
@@ -105,10 +108,13 @@ class Recorder { |
if (f.isStatic) continue; |
if (f.isSynthetic) continue; // exclude getters |
if (options.excludeFinal && f.isFinal) continue; |
+ var name = f.displayName; |
+ if (options.matches != null && !options.matches(name)) continue; |
if (skipBecauseOfAnnotations(f)) continue; |
- generator.addDeclaration(id, f.displayName, _typeFor(f.type.element), |
+ generator.addDeclaration(id, name, _typeFor(f.type.element), |
isField: true, isFinal: f.isFinal, |
annotations: _copyAnnotations(f)); |
+ if (includeAccessors) _addAccessors(name, !f.isFinal); |
} |
} |
@@ -119,44 +125,54 @@ class Recorder { |
var v = a.variable; |
if (v is FieldElement && !v.isSynthetic) continue; // exclude fields |
if (options.excludeFinal && v.isFinal) continue; |
- if (skipBecauseOfAnnotations(v)) continue; |
- generator.addDeclaration(id, v.displayName, _typeFor(v.type.element), |
+ var name = v.displayName; |
+ if (options.matches != null && !options.matches(name)) continue; |
+ if (skipBecauseOfAnnotations(a)) continue; |
+ generator.addDeclaration(id, name, _typeFor(a.type.returnType.element), |
isProperty: true, isFinal: v.isFinal, |
annotations: _copyAnnotations(a)); |
+ if (includeAccessors) _addAccessors(name, !v.isFinal); |
} |
} |
if (options.includeMethods) { |
for (var m in type.methods) { |
if (m.isStatic) continue; |
+ var name = m.displayName; |
+ if (options.matches != null && !options.matches(name)) continue; |
if (skipBecauseOfAnnotations(m)) continue; |
- generator.addDeclaration(id, m.displayName, |
+ generator.addDeclaration(id, name, |
new TypeIdentifier('dart:core', 'Function'), isMethod: true, |
annotations: _copyAnnotations(m)); |
+ if (includeAccessors) _addAccessors(name, false); |
} |
} |
} |
/// Adds the declaration of [name] if it was found in [type]. If [recursive] |
/// is true, then we continue looking up [name] in the parent classes until we |
- /// find it or we reach Object. |
- void lookupMember(ClassElement type, String name, {bool recursive: false}) { |
- _lookupMemberInternal(type, _typeFor(type), name, recursive); |
- } |
+ /// find it or we reach Object. Returns whether the declaration was found. |
+ /// When a declaration is found, add also a symbol, getter, and setter if |
+ /// [includeAccessors] is true. |
+ bool lookupMember(ClassElement type, String name, {bool recursive: false, |
+ bool includeAccessors: true}) => |
+ _lookupMemberInternal(type, _typeFor(type), name, recursive, |
+ includeAccessors); |
/// Helper for [lookupMember] that walks up the type hierarchy including mixin |
/// classes. |
bool _lookupMemberInternal(ClassElement type, TypeIdentifier id, String name, |
- bool recursive) { |
+ bool recursive, bool includeAccessors) { |
// Exclude members from [Object]. |
if (type.type.isObject) return false; |
generator.addEmptyDeclaration(id); |
for (var f in type.fields) { |
if (f.displayName != name) continue; |
if (f.isSynthetic) continue; // exclude getters |
- generator.addDeclaration(id, f.displayName, |
+ generator.addDeclaration(id, name, |
_typeFor(f.type.element), isField: true, isFinal: f.isFinal, |
isStatic: f.isStatic, annotations: _copyAnnotations(f)); |
+ if (includeAccessors) _addAccessors(name, !f.isFinal); |
return true; |
} |
@@ -167,17 +183,20 @@ class Recorder { |
if (a.displayName != name) continue; |
var v = a.variable; |
if (v is FieldElement && !v.isSynthetic) continue; // exclude fields |
- generator.addDeclaration(id, v.displayName, |
- _typeFor(v.type.element), isProperty: true, isFinal: v.isFinal, |
- isStatic: v.isStatic, annotations: _copyAnnotations(a)); |
+ generator.addDeclaration(id, name, |
+ _typeFor(a.type.returnType.element), isProperty: true, |
+ isFinal: v.isFinal, isStatic: a.isStatic, |
+ annotations: _copyAnnotations(a)); |
+ if (includeAccessors) _addAccessors(name, !v.isFinal); |
return true; |
} |
for (var m in type.methods) { |
if (m.displayName != name) continue; |
- generator.addDeclaration(id, m.displayName, |
+ generator.addDeclaration(id, name, |
new TypeIdentifier('dart:core', 'Function'), isMethod: true, |
isStatic: m.isStatic, annotations: _copyAnnotations(m)); |
+ if (includeAccessors) _addAccessors(name, false); |
return true; |
} |
@@ -189,17 +208,26 @@ class Recorder { |
for (var m in type.mixins) { |
var mixinClass = m.element; |
var mixinId = _mixins[parentId][mixinClass]; |
- if (_lookupMemberInternal(mixinClass, mixinId, name, false)) { |
+ if (_lookupMemberInternal(mixinClass, mixinId, name, false, |
+ includeAccessors)) { |
return true; |
} |
parentId = mixinId; |
} |
- return _lookupMemberInternal(parent, parentId, name, true); |
+ return _lookupMemberInternal(parent, parentId, name, true, |
+ includeAccessors); |
} |
return false; |
} |
+ /// Adds [name] as a symbol, a getter, and optionally a setter in [generator]. |
+ _addAccessors(String name, bool includeSetter) { |
+ generator.addSymbol(name); |
+ generator.addGetter(name); |
+ if (includeSetter) generator.addSetter(name); |
+ } |
+ |
/// Copy metadata associated with the declaration of [target]. |
List<ConstExpression> _copyAnnotations(Element target) { |
var node = target.node; |
@@ -338,6 +366,10 @@ class QueryOptions { |
/// included. |
final List<Element> withAnnotations; |
+ /// If [matches] is not null, then only those fields, properties, or methods |
+ /// that match will be included. |
+ final NameMatcher matches; |
+ |
const QueryOptions({ |
this.includeFields: true, |
this.includeProperties: true, |
@@ -345,5 +377,9 @@ class QueryOptions { |
this.includeUpTo: null, |
this.excludeFinal: false, |
this.includeMethods: false, |
- this.withAnnotations: null}); |
+ this.withAnnotations: null, |
+ this.matches: null}); |
} |
+ |
+/// Predicate that tells whether [name] should be included in query results. |
+typedef bool NameMatcher(String name); |