Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Unified Diff: pkg/docgen/lib/docgen.dart

Issue 63193006: Resolve comments lazily and re-evaluate inherited comments for subclasses (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/docgen/lib/docgen.dart
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index 8f48f5f53e3aadab4eb24df5ebd85d34e203ad33..046cdf159ceb47978395c61fe36c182ea8fbea98 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -51,22 +51,10 @@ Iterable<LibraryMirror> _sdkLibraries;
/// without import.
LibraryMirror _coreLibrary;
-/// Current library being documented to be used for comment links.
-LibraryMirror _currentLibrary;
Emily Fortuna 2013/11/18 21:00:41 yay! :-)
-
-/// Current class being documented to be used for comment links.
-ClassMirror _currentClass;
-
-/// Current member being documented to be used for comment links.
-MemberMirror _currentMember;
-
/// Support for [:foo:]-style code comments to the markdown parser.
List<markdown.InlineSyntax> markdownSyntaxes =
[new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')];
-/// Resolves reference links in doc comments.
-markdown.Resolver linkResolver;
-
/// Index of all indexable items. This also ensures that no class is
/// created more than once.
Map<String, Indexable> entityMap = new Map<String, Indexable>();
@@ -108,8 +96,6 @@ Future<bool> docgen(List<String> files, {String packageRoot,
}
}
logger.info('Package Root: ${packageRoot}');
- linkResolver = (name) =>
- fixReference(name, _currentLibrary, _currentClass, _currentMember);
return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk)
.then((MirrorSystem mirrorSystem) {
@@ -143,6 +129,7 @@ Future<bool> docgen(List<String> files, {String packageRoot,
/// If [library] is specified, we set the packageName field. If no package could
/// be determined, we return an empty string.
String _findPackage(LibraryMirror mirror, [Library library]) {
+ if (mirror == null) return '';
if (mirror.uri.scheme != 'file') return '';
var filePath = mirror.uri.toFilePath();
// We assume that we are documenting only libraries under package/lib
@@ -172,13 +159,13 @@ String _packageIntro(packageDir) {
// If there are multiples, pick the shortest name.
readmes.sort((a, b) => a.length.compareTo(b.length));
var readme = readmes.first;
+ var linkResolver = (name) => fixReference(name, null, null, null);
var contents = markdown.markdownToHtml(readme
.readAsStringSync(), linkResolver: linkResolver,
inlineSyntaxes: markdownSyntaxes);
return contents;
}
-
List<String> _listLibraries(List<String> args) {
var libraries = new List<String>();
for (var arg in args) {
@@ -330,6 +317,7 @@ void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false,
// Outputs a JSON file with all libraries and their preview comments.
// This will help the viewer know what libraries are available to read in.
var libraryMap;
+ var linkResolver = (name) => fixReference(name, null, null, null);
if (append) {
var docsDir = listDir('docs');
if (!docsDir.contains('docs/library_list.json')) {
@@ -384,12 +372,12 @@ void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false,
}
Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
- _currentLibrary = library;
- var result = new Library(docName(library), _commentToHtml(library),
+ var result = new Library(docName(library),
+ (actualLibrary) => _commentToHtml(library, actualLibrary),
_classes(library.classes),
_methods(library.functions),
_variables(library.variables),
- _isHidden(library));
+ _isHidden(library), library);
_findPackage(library, result);
logger.fine('Generated library for ${result.name}');
return result;
@@ -460,23 +448,14 @@ List<Annotation> _annotations(DeclarationMirror mirror) {
return annotations;
}
-/// Update the global pointers to the current mirror to the particular mirror
-/// we're documenting.
-void _updateCurrentMirror(DeclarationMirror mirror) {
- if (mirror is LibraryMirror) {
- _currentLibrary = mirror;
- } else if (mirror is ClassMirror) {
- _currentClass = mirror;
- } else if (mirror is MethodMirror) {
- _currentMember = mirror;
- }
-}
-
/// Returns any documentation comments associated with a mirror with
/// simple markdown converted to html.
-String _commentToHtml(DeclarationMirror mirror) {
+///
+/// It's possible to have a comment that comes from one mirror applied to
+/// another, in the case of an inherited comment.
+String _commentToHtml(DeclarationMirror mirror, [DeclarationMirror appliedTo]) {
+ if (appliedTo == null) appliedTo = mirror;
String commentText;
- _updateCurrentMirror(mirror);
mirror.metadata.forEach((metadata) {
if (metadata is CommentInstanceMirror) {
CommentInstanceMirror comment = metadata;
@@ -490,6 +469,7 @@ String _commentToHtml(DeclarationMirror mirror) {
}
});
+ var linkResolver = (name) => fixReferenceWithScope(name, appliedTo);
commentText = commentText == null ? '' :
markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver,
inlineSyntaxes: markdownSyntaxes);
@@ -505,7 +485,7 @@ void _mdnComment(Indexable item) {
var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
_mdn = JSON.decode(new File(mdnPath).readAsStringSync());
}
- if (item.comment.isNotEmpty) return;
+ if (item is Library) return;
var domAnnotation = item.annotations.firstWhere(
(e) => e.qualifiedName == 'metadata.DomName', orElse: () => null);
if (domAnnotation == null) return;
@@ -675,18 +655,33 @@ markdown.Node fixReference(String name, LibraryMirror currentLibrary,
return _fixComplexReference(name, currentLibrary, currentClass, currentMember);
}
+markdown.Node fixReferenceWithScope(String name, DeclarationMirror scope) {
+ if (scope is LibraryMirror) return fixReference(name, scope, null, null);
+ if (scope is ClassMirror)
+ return fixReference(name, scope.library, scope, null);
+ if (scope is MemberMirror) {
+ var owner = scope.owner;
+ if (owner is ClassMirror) {
+ return fixReference(name, owner.library, owner, scope);
+ } else {
+ return fixReference(name, owner, null, scope);
+ }
+ }
+ return null;
+}
+
/// Returns a map of [Variable] objects constructed from [mirrorMap].
Map<String, Variable> _variables(Map<String, VariableMirror> mirrorMap) {
var data = {};
// TODO(janicejl): When map to map feature is created, replace the below with
// a filter. Issue(#9590).
mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
- _currentMember = mirror;
if (_includePrivate || !_isHidden(mirror)) {
entityMap[docName(mirror)] = new Variable(mirrorName, mirror.isFinal,
mirror.isStatic, mirror.isConst, _type(mirror.type),
- _commentToHtml(mirror), _annotations(mirror), docName(mirror),
- _isHidden(mirror), docName(mirror.owner));
+ (actualVariable) => _commentToHtml(mirror, actualVariable),
+ _annotations(mirror), docName(mirror),
+ _isHidden(mirror), docName(mirror.owner), mirror);
data[mirrorName] = entityMap[docName(mirror)];
}
});
@@ -713,11 +708,12 @@ Class _class(ClassMirror mirror) {
_class(mirror.superclass) : null;
var interfaces =
mirror.superinterfaces.map((interface) => _class(interface));
- clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror),
+ clazz = new Class(mirror.simpleName, superclass,
+ (actualClass) => _commentToHtml(mirror, actualClass),
interfaces.toList(), _variables(mirror.variables),
_methods(mirror.methods), _annotations(mirror), _generics(mirror),
docName(mirror), _isHidden(mirror), docName(mirror.owner),
- mirror.isAbstract);
+ mirror.isAbstract, mirror);
if (superclass != null) clazz.addInherited(superclass);
interfaces.forEach((interface) => clazz.addInherited(interface));
entityMap[docName(mirror)] = clazz;
@@ -738,7 +734,6 @@ ClassGroup _classes(Map<String, ClassMirror> mirrorMap) {
Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) {
var data = {};
mirrorList.forEach((ParameterMirror mirror) {
- _currentMember = mirror;
data[mirror.simpleName] = new Parameter(mirror.simpleName,
mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
_type(mirror.type), mirror.defaultValue,
@@ -806,34 +801,52 @@ Map recurseMap(Map inputMap) {
return outputMap;
}
+/// A type for the function that generates a comment from a mirror.
+typedef String CommentGenerator(Mirror m);
+
/// A class representing all programming constructs, like library or class.
class Indexable {
String name;
String get qualifiedName => fileName;
bool isPrivate;
+ Mirror mirror;
// The qualified name (for URL purposes) and the file name are the same,
// of the form packageName/ClassName or packageName/ClassName.methodName.
// This defines both the URL and the directory structure.
String get fileName => packagePrefix + ownerPrefix + name;
- Indexable get owningEntity {
- var result = entityMap[owner];
- return result;
- }
+ Indexable get owningEntity => entityMap[owner];
+
String get ownerPrefix => owningEntity == null
? (owner == null || owner.isEmpty ? '' : owner + '.')
: owningEntity.qualifiedName + '.';
String get packagePrefix => '';
+
/// Documentation comment with converted markdown.
- String comment;
+ String _comment;
+
+ String get comment {
+ if (_comment != null) return _comment;
+ _comment = _commentFunction(mirror);
+ if (_comment.isEmpty) {
+ _mdnComment(this);
+ }
+ return _comment;
+ }
+
+ set comment(x) => _comment = x;
+
+ /// We defer evaluating the comment until we have all the context available
+ CommentGenerator _commentFunction;
/// Qualified Name of the owner of this Indexable Item.
/// For Library, owner will be "";
String owner;
- Indexable(this.name, this.comment, this.isPrivate, this.owner);
+ Indexable(this.name, this._commentFunction, this.isPrivate, this.owner,
+ this.mirror);
/// The type of this member to be used in index.txt.
String get typeName => '';
@@ -884,9 +897,9 @@ class Library extends Indexable {
return basic;
}
- Library(String name, String comment, this.classes, this.functions,
- this.variables, bool isPrivate) : super(name, comment,
- isPrivate, "");
+ Library(String name, Function commentFunction, this.classes, this.functions,
+ this.variables, bool isPrivate, Mirror mirror)
+ : super(name, commentFunction, isPrivate, "", mirror);
/// Generates a map describing the [Library] object.
Map toMap() => {
@@ -933,11 +946,13 @@ class Class extends Indexable implements Comparable {
/// List of the meta annotations on the class.
List<Annotation> annotations;
- Class(String name, this.superclass, String comment, this.interfaces,
+ bool _commentsEnsured = false;
Emily Fortuna 2013/11/18 21:00:41 comment explaining this variable?
Alan Knight 2013/11/18 22:04:46 Done.
+
+ Class(String name, this.superclass, Function commentFunction, this.interfaces,
this.variables, this.methods, this.annotations, this.generics,
- String qualifiedName, bool isPrivate, String owner, this.isAbstract)
- : super(name, comment, isPrivate, owner) {
- _mdnComment(this);
+ String qualifiedName, bool isPrivate, String owner, this.isAbstract,
+ Mirror mirror)
+ : super(name, commentFunction, isPrivate, owner, mirror) {
Emily Fortuna 2013/11/18 21:00:41 you can take out the { } and just have a semicolon
Alan Knight 2013/11/18 22:04:46 Done.
}
String get typeName => 'class';
@@ -1004,6 +1019,8 @@ class Class extends Indexable implements Comparable {
/// Makes sure that all methods with inherited equivalents have comments.
void ensureComments() {
+ if (_commentsEnsured) return;
+ _commentsEnsured = true;
inheritedMethods.forEach((qualifiedName, inheritedMethod) {
var method = methods[qualifiedName];
if (method != null) method.ensureCommentFor(inheritedMethod);
@@ -1047,22 +1064,22 @@ class ClassGroup {
Map<String, Typedef> typedefs = {};
Map<String, Class> errors = {};
- void addClass(ClassMirror mirror) {
- _currentClass = mirror;
- if (mirror.isTypedef) {
+ void addClass(ClassMirror classMirror) {
+ if (classMirror.isTypedef) {
// This is actually a Dart2jsTypedefMirror, and it does define value,
// but we don't have visibility to that type.
- var mirror = _currentClass;
+ var mirror = classMirror;
if (_includePrivate || !mirror.isPrivate) {
entityMap[docName(mirror)] = new Typedef(mirror.simpleName,
- docName(mirror.value.returnType), _commentToHtml(mirror),
+ docName(mirror.value.returnType),
+ (actualTypedef) => _commentToHtml(mirror, actualTypedef),
_generics(mirror), _parameters(mirror.value.parameters),
_annotations(mirror), docName(mirror), _isHidden(mirror),
- docName(mirror.owner));
+ docName(mirror.owner), mirror);
typedefs[mirror.simpleName] = entityMap[docName(mirror)];
}
} else {
- var clazz = _class(mirror);
+ var clazz = _class(classMirror);
// Adding inherited parent variables and methods.
clazz.parent().forEach((parent) {
@@ -1071,14 +1088,13 @@ class ClassGroup {
}
});
- clazz.ensureComments();
-
if (clazz.isError()) {
- errors[mirror.simpleName] = clazz;
- } else if (mirror.isClass) {
- classes[mirror.simpleName] = clazz;
+ errors[classMirror.simpleName] = clazz;
+ } else if (classMirror.isClass) {
+ classes[classMirror.simpleName] = clazz;
} else {
- throw new ArgumentError('${mirror.simpleName} - no class type match. ');
+ throw new ArgumentError(
+ '${classMirror.simpleName} - no class type match. ');
}
}
}
@@ -1108,10 +1124,10 @@ class Typedef extends Indexable {
/// List of the meta annotations on the typedef.
List<Annotation> annotations;
- Typedef(String name, this.returnType, String comment, this.generics,
+ Typedef(String name, this.returnType, Function commentFunction, this.generics,
this.parameters, this.annotations,
- String qualifiedName, bool isPrivate, String owner)
- : super(name, comment, isPrivate, owner);
+ String qualifiedName, bool isPrivate, String owner, Mirror mirror)
+ : super(name, commentFunction, isPrivate, owner, mirror);
Map toMap() => {
'name': name,
@@ -1138,9 +1154,9 @@ class Variable extends Indexable {
List<Annotation> annotations;
Variable(String name, this.isFinal, this.isStatic, this.isConst, this.type,
- String comment, this.annotations, String qualifiedName, bool isPrivate,
- String owner) : super(name, comment, isPrivate, owner) {
- _mdnComment(this);
+ Function commentFunction, this.annotations, String qualifiedName,
+ bool isPrivate, String owner, Mirror mirror)
+ : super(name, commentFunction, isPrivate, owner, mirror) {
}
/// Generates a map describing the [Variable] object.
@@ -1156,6 +1172,15 @@ class Variable extends Indexable {
};
String get typeName => 'property';
+
+ get comment {
+ if (_comment != null) return _comment;
+ var owningClass = owningEntity;
+ if (owningClass is Class) {
+ owningClass.ensureComments();
+ }
+ return super.comment;
+ }
}
/// A class containing properties of a Dart method.
@@ -1180,18 +1205,17 @@ class Method extends Indexable {
List<Annotation> annotations;
Method(String name, this.isStatic, this.isAbstract, this.isConst,
- this.returnType, String comment, this.parameters, this.annotations,
+ this.returnType, Function commentFunction, this.parameters,
+ this.annotations,
String qualifiedName, bool isPrivate, String owner, this.isConstructor,
- this.isGetter, this.isSetter, this.isOperator)
- : super(name, comment, isPrivate, owner) {
- _mdnComment(this);
+ this.isGetter, this.isSetter, this.isOperator, Mirror mirror)
+ : super(name, commentFunction, isPrivate, owner, mirror) {
}
/// Makes sure that the method with an inherited equivalent have comments.
void ensureCommentFor(Method inheritedMethod) {
if (comment.isNotEmpty) return;
- (entityMap[inheritedMethod.owner] as Class).ensureComments();
- comment = inheritedMethod.comment;
+ comment = inheritedMethod._commentFunction(mirror);
commentInheritedFrom = inheritedMethod.commentInheritedFrom == '' ?
inheritedMethod.qualifiedName : inheritedMethod.commentInheritedFrom;
}
@@ -1213,6 +1237,15 @@ class Method extends Indexable {
String get typeName => isConstructor ? 'constructor' :
isGetter ? 'getter' : isSetter ? 'setter' :
isOperator ? 'operator' : 'method';
+
+ get comment {
+ if (_comment != null) return _comment;
+ var owningClass = owningEntity;
+ if (owningClass is Class) {
+ owningClass.ensureComments();
+ }
+ return super.comment;
+ }
}
/// A container to categorize methods into the following groups: setters,
@@ -1227,12 +1260,12 @@ class MethodGroup {
void addMethod(MethodMirror mirror) {
var method = new Method(mirror.simpleName, mirror.isStatic,
mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType),
- _commentToHtml(mirror), _parameters(mirror.parameters),
+ (actualMethod) => _commentToHtml(mirror, actualMethod),
+ _parameters(mirror.parameters),
_annotations(mirror), docName(mirror), _isHidden(mirror),
docName(mirror.owner), mirror.isConstructor, mirror.isGetter,
- mirror.isSetter, mirror.isOperator);
+ mirror.isSetter, mirror.isOperator, mirror);
entityMap[docName(mirror)] = method;
- _currentMember = mirror;
if (mirror.isSetter) {
setters[mirror.simpleName] = method;
} else if (mirror.isGetter) {
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698