OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library docgen.models.clazz; | |
6 | |
7 import '../exports/dart2js_mirrors.dart' as dart2js_mirrors; | |
8 import '../exports/mirrors_util.dart' as dart2js_util; | |
9 import '../exports/source_mirrors.dart'; | |
10 | |
11 import '../library_helpers.dart'; | |
12 | |
13 import 'dummy_mirror.dart'; | |
14 import 'generic.dart'; | |
15 import 'library.dart'; | |
16 import 'method.dart'; | |
17 import 'model_helpers.dart'; | |
18 import 'owned_indexable.dart'; | |
19 import 'variable.dart'; | |
20 | |
21 /// A class containing contents of a Dart class. | |
22 class Class extends OwnedIndexable<dart2js_mirrors.Dart2JsInterfaceTypeMirror> | |
23 implements Comparable<Class> { | |
24 | |
25 /// List of the names of interfaces that this class implements. | |
26 List<Class> interfaces = []; | |
27 | |
28 /// Names of classes that extends or implements this class. | |
29 Set<Class> subclasses = new Set<Class>(); | |
30 | |
31 /// Top-level variables in the class. | |
32 Map<String, Variable> variables; | |
33 | |
34 /// Inherited variables in the class. | |
35 final Map<String, Variable> inheritedVariables = {}; | |
36 | |
37 /// Methods in the class. | |
38 Map<String, Method> methods; | |
39 | |
40 final Map<String, Method> inheritedMethods = new Map<String, Method>(); | |
41 | |
42 /// Generic infomation about the class. | |
43 final Map<String, Generic> generics; | |
44 | |
45 Class _superclass; | |
46 bool get isAbstract => mirror.isAbstract; | |
47 | |
48 /// Make sure that we don't check for inherited comments more than once. | |
49 bool _commentsEnsured = false; | |
50 | |
51 /// Returns the [Class] for the given [mirror] if it has already been created, | |
52 /// else creates it. | |
53 factory Class(ClassMirror mirror, Library owner) { | |
54 var clazz = getDocgenObject(mirror, owner); | |
55 if (clazz is DummyMirror) { | |
56 clazz = new Class._(mirror, owner); | |
57 } | |
58 return clazz; | |
59 } | |
60 | |
61 /// Called when we are constructing a superclass or interface class, but it | |
62 /// is not known if it belongs to the same owner as the original class. In | |
63 /// this case, we create an object whose owner is what the original mirror | |
64 /// says it is. | |
65 factory Class._possiblyDifferentOwner(ClassMirror mirror, | |
66 Library originalOwner) { | |
67 var realOwner = getDocgenObject(mirror.owner); | |
68 if (realOwner is Library) { | |
69 return new Class(mirror, realOwner); | |
70 } else { | |
71 return new Class(mirror, originalOwner); | |
72 } | |
73 } | |
74 | |
75 Class._(ClassSourceMirror classMirror, Library owner) | |
76 : generics = createGenerics(classMirror), | |
77 super(classMirror, owner) { | |
78 | |
79 // The reason we do this madness is the superclass and interface owners may | |
80 // not be this class's owner!! Example: BaseClient in http pkg. | |
81 var superinterfaces = classMirror.superinterfaces.map( | |
82 (interface) => new Class._possiblyDifferentOwner(interface, owner)); | |
83 this._superclass = classMirror.superclass == null? null : | |
84 new Class._possiblyDifferentOwner(classMirror.superclass, owner); | |
85 | |
86 interfaces = superinterfaces.toList(); | |
87 variables = createVariables( | |
88 dart2js_util.variablesOf(classMirror.declarations), this); | |
89 methods = createMethods(dart2js_util.anyMethodOf(classMirror.declarations), | |
90 this); | |
91 | |
92 // Tell superclass that you are a subclass, unless you are not | |
93 // visible or an intermediary mixin class. | |
94 if (!classMirror.isNameSynthetic && isVisible && _superclass != null) { | |
95 _superclass.addSubclass(this); | |
96 } | |
97 | |
98 if (this._superclass != null) addInherited(_superclass); | |
99 interfaces.forEach((interface) => addInherited(interface)); | |
100 } | |
101 | |
102 String _lookupInClassAndSuperclasses(String name) { | |
103 var lookupFunc = determineLookupFunc(name); | |
104 var classScope = this; | |
105 while (classScope != null) { | |
106 var classFunc = lookupFunc(classScope.mirror, name); | |
107 if (classFunc != null) { | |
108 return packagePrefix + getDocgenObject(classFunc, owner).docName; | |
109 } | |
110 classScope = classScope._superclass; | |
111 } | |
112 return null; | |
113 } | |
114 | |
115 /// Look for the specified name starting with the current member, and | |
116 /// progressively working outward to the current library scope. | |
117 String findElementInScope(String name) { | |
118 var lookupFunc = determineLookupFunc(name); | |
119 var result = _lookupInClassAndSuperclasses(name); | |
120 if (result != null) { | |
121 return result; | |
122 } | |
123 result = owner.findElementInScope(name); | |
124 return result == null ? super.findElementInScope(name) : result; | |
125 } | |
126 | |
127 String get typeName => 'class'; | |
128 | |
129 /// Add all inherited variables and methods from the provided superclass. | |
130 /// If [_includePrivate] is true, it also adds the variables and methods from | |
131 /// the superclass. | |
132 void addInherited(Class superclass) { | |
133 inheritedVariables.addAll(superclass.inheritedVariables); | |
134 inheritedVariables.addAll(_allButStatics(superclass.variables)); | |
135 addInheritedMethod(superclass, this); | |
136 } | |
137 | |
138 /** [newParent] refers to the actual class is currently using these methods. | |
139 * which may be different because with the mirror system, we only point to the | |
140 * original canonical superclasse's method. | |
141 */ | |
142 void addInheritedMethod(Class parent, Class newParent) { | |
143 parent.inheritedMethods.forEach((name, method) { | |
144 if (!method.mirror.isConstructor) { | |
145 inheritedMethods[name] = new Method(method.mirror, newParent, method); | |
146 } | |
147 }); | |
148 _allButStatics(parent.methods).forEach((name, method) { | |
149 if (!method.mirror.isConstructor) { | |
150 inheritedMethods[name] = new Method(method.mirror, newParent, method); | |
151 } | |
152 }); | |
153 } | |
154 | |
155 /// Remove statics from the map of inherited items before adding them. | |
156 Map _allButStatics(Map items) { | |
157 var result = {}; | |
158 items.forEach((name, item) { | |
159 if (!item.isStatic) { | |
160 result[name] = item; | |
161 } | |
162 }); | |
163 return result; | |
164 } | |
165 | |
166 /// Add the subclass to the class. | |
167 /// | |
168 /// If [this] is private (or an intermediary mixin class), it will add the | |
169 /// subclass to the list of subclasses in the superclasses. | |
170 void addSubclass(Class subclass) { | |
171 if (docName == 'dart:core.Object') return; | |
172 | |
173 if (!includePrivateMembers && isPrivate || mirror.isNameSynthetic) { | |
174 if (_superclass != null) _superclass.addSubclass(subclass); | |
175 interfaces.forEach((interface) { | |
176 interface.addSubclass(subclass); | |
177 }); | |
178 } else { | |
179 subclasses.add(subclass); | |
180 } | |
181 } | |
182 | |
183 /// Check if this [Class] is an error or exception. | |
184 bool isError() { | |
185 if (qualifiedName == 'dart:core.Error' || | |
186 qualifiedName == 'dart:core.Exception') | |
187 return true; | |
188 for (var interface in interfaces) { | |
189 if (interface.isError()) return true; | |
190 } | |
191 if (_superclass == null) return false; | |
192 return _superclass.isError(); | |
193 } | |
194 | |
195 /// Makes sure that all methods with inherited equivalents have comments. | |
196 void ensureComments() { | |
197 if (_commentsEnsured) return; | |
198 _commentsEnsured = true; | |
199 if (_superclass != null) _superclass.ensureComments(); | |
200 inheritedMethods.forEach((qualifiedName, inheritedMethod) { | |
201 var method = methods[qualifiedName]; | |
202 if (method != null) { | |
203 // if we have overwritten this method in this class, we still provide | |
204 // the opportunity to inherit the comments. | |
205 method.ensureCommentFor(inheritedMethod); | |
206 } | |
207 }); | |
208 // we need to populate the comments for all methods. so that the subclasses | |
209 // can get for their inherited versions the comments. | |
210 methods.forEach((qualifiedName, method) { | |
211 if (!method.mirror.isConstructor) method.ensureCommentFor(method); | |
212 }); | |
213 } | |
214 | |
215 /// If a class extends a private superclass, find the closest public | |
216 /// superclass of the private superclass. | |
217 String validSuperclass() { | |
218 if (_superclass == null) return 'dart:core.Object'; | |
219 if (_superclass.isVisible) return _superclass.qualifiedName; | |
220 return _superclass.validSuperclass(); | |
221 } | |
222 | |
223 /// Generates a map describing the [Class] object. | |
224 Map toMap() => { | |
225 'name': name, | |
226 'qualifiedName': qualifiedName, | |
227 'comment': comment, | |
228 'isAbstract' : isAbstract, | |
229 'superclass': validSuperclass(), | |
230 'implements': interfaces.where((i) => i.isVisible) | |
231 .map((e) => e.qualifiedName).toList(), | |
232 'subclass': (subclasses.toList()..sort()) | |
233 .map((x) => x.qualifiedName).toList(), | |
234 'variables': recurseMap(variables), | |
235 'inheritedVariables': recurseMap(inheritedVariables), | |
236 'methods': expandMethodMap(methods), | |
237 'inheritedMethods': expandMethodMap(inheritedMethods), | |
238 'annotations': annotations.map((a) => a.toMap()).toList(), | |
239 'generics': recurseMap(generics) | |
240 }; | |
241 | |
242 int compareTo(Class other) => name.compareTo(other.name); | |
243 | |
244 bool isValidMirror(DeclarationMirror mirror) => mirror is ClassMirror; | |
245 } | |
OLD | NEW |