Skip to content

Commit b7b0eb0

Browse files
authored
Breakdown comment reference handling further and tweak performance (#1863)
* Add option for asyncStackTraces * Added lookup helper, but doesn't seem to actually help much * More breakdown of the comment reference handling * dartfmt
1 parent 34051ce commit b7b0eb0

File tree

4 files changed

+95
-75
lines changed

4 files changed

+95
-75
lines changed

bin/dartdoc.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ class DartdocProgramOptionContext extends DartdocGeneratorOptionContext
1818
DartdocProgramOptionContext(DartdocOptionSet optionSet, Directory dir)
1919
: super(optionSet, dir);
2020

21+
bool get asyncStackTraces => optionSet['asyncStackTraces'].valueAt(context);
2122
bool get help => optionSet['help'].valueAt(context);
2223
bool get version => optionSet['version'].valueAt(context);
2324
}
2425

2526
Future<List<DartdocOption>> createDartdocProgramOptions() async {
2627
return <DartdocOption>[
28+
new DartdocOptionArgOnly<bool>('asyncStackTraces', false,
29+
help: 'Display coordinated asynchronous stack traces (slow)',
30+
negatable: true),
2731
new DartdocOptionArgOnly<bool>('help', false,
2832
abbr: 'h', help: 'Show command help.', negatable: false),
2933
new DartdocOptionArgOnly<bool>('version', false,
@@ -88,7 +92,7 @@ void main(List<String> arguments) async {
8892
stderr.writeln('\nGeneration failed: ${e}\n${chain.terse}');
8993
exit(255);
9094
}
91-
});
95+
}, when: config.asyncStackTraces);
9296
} finally {
9397
// Clear out any cached tool snapshots.
9498
SnapshotCache.instance.dispose();

lib/src/io_utils.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
library dartdoc.io_utils;
77

88
import 'dart:async';
9-
import 'dart:collection';
109
import 'dart:convert';
1110
import 'dart:io';
1211

@@ -89,27 +88,28 @@ class MultiFutureTracker<T> {
8988
/// Approximate maximum number of simultaneous active Futures.
9089
final int parallel;
9190

92-
final Queue<Future<T>> _queue = new Queue();
91+
final Set<Future<T>> _trackedFutures = new Set();
9392

9493
MultiFutureTracker(this.parallel);
9594

9695
/// Wait until fewer or equal to this many Futures are outstanding.
9796
Future<void> _waitUntil(int max) async {
98-
while (_queue.length > max) {
99-
await Future.any(_queue);
97+
while (_trackedFutures.length > max) {
98+
await Future.any(_trackedFutures);
10099
}
101100
}
102101

103102
/// Generates a [Future] from the given closure and adds it to the queue,
104-
/// once the queue is sufficiently empty.
103+
/// once the queue is sufficiently empty. The returned future completes
104+
/// when the generated [Future] has been added to the queue.
105105
Future<void> addFutureFromClosure(Future<T> Function() closure) async {
106-
while (_queue.length > parallel - 1) {
107-
await Future.any(_queue);
106+
while (_trackedFutures.length > parallel - 1) {
107+
await Future.any(_trackedFutures);
108108
}
109109
Future future = closure();
110-
_queue.add(future);
110+
_trackedFutures.add(future);
111111
// ignore: unawaited_futures
112-
future.then((f) => _queue.remove(future));
112+
future.then((f) => _trackedFutures.remove(future));
113113
}
114114

115115
/// Wait until all futures added so far have completed.

lib/src/markdown_processor.dart

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:dartdoc/src/tuple.dart';
1515
import 'package:dartdoc/src/warnings.dart';
1616
import 'package:html/parser.dart' show parse;
1717
import 'package:markdown/markdown.dart' as md;
18+
import 'package:quiver/iterables.dart' as quiverIterables;
1819

1920
const validHtmlTags = const [
2021
"a",
@@ -547,8 +548,7 @@ class _MarkdownCommentReference {
547548
if (codeRefChomped == modelElement.fullyQualifiedNameWithoutLibrary ||
548549
(modelElement is Library &&
549550
codeRefChomped == modelElement.fullyQualifiedName)) {
550-
results.add(
551-
packageGraph.findCanonicalModelElementFor(modelElement.element));
551+
_addCanonicalResult(modelElement, null);
552552
}
553553
}
554554
}
@@ -559,9 +559,7 @@ class _MarkdownCommentReference {
559559
if (library.modelElementsNameMap.containsKey(codeRefChomped)) {
560560
for (final modelElement in library.modelElementsNameMap[codeRefChomped]) {
561561
if (!_ConsiderIfConstructor(modelElement)) continue;
562-
results.add(packageGraph.findCanonicalModelElementFor(
563-
modelElement.element,
564-
preferredClass: preferredClass));
562+
_addCanonicalResult(modelElement, preferredClass);
565563
}
566564
}
567565
}
@@ -579,11 +577,11 @@ class _MarkdownCommentReference {
579577
// might make no sense. Instead, use the enclosing class from the
580578
// element in [packageGraph.findRefElementCache], because that element's
581579
// enclosing class will be preferred from [codeRefChomped]'s perspective.
582-
results.add(packageGraph.findCanonicalModelElementFor(
583-
modelElement.element,
584-
preferredClass: modelElement.enclosingElement is Class
580+
_addCanonicalResult(
581+
modelElement,
582+
modelElement.enclosingElement is Class
585583
? modelElement.enclosingElement
586-
: null));
584+
: null);
587585
}
588586
}
589587
}
@@ -639,6 +637,12 @@ class _MarkdownCommentReference {
639637
}
640638
}
641639

640+
// Add a result, but make it canonical.
641+
void _addCanonicalResult(ModelElement modelElement, Class tryClass) {
642+
results.add(packageGraph.findCanonicalModelElementFor(modelElement.element,
643+
preferredClass: tryClass));
644+
}
645+
642646
/// _getResultsForClass assumes codeRefChomped might be a member of tryClass (inherited or not)
643647
/// and will add to [results]
644648
void _getResultsForClass(Class tryClass) {
@@ -653,8 +657,7 @@ class _MarkdownCommentReference {
653657
} else {
654658
// People like to use 'this' in docrefs too.
655659
if (codeRef == 'this') {
656-
results
657-
.add(packageGraph.findCanonicalModelElementFor(tryClass.element));
660+
_addCanonicalResult(tryClass, null);
658661
} else {
659662
// TODO(jcollins-g): get rid of reimplementation of identifier resolution
660663
// or integrate into ModelElement in a simpler way.
@@ -666,62 +669,42 @@ class _MarkdownCommentReference {
666669
// Fortunately superChains are short, but optimize this if it matters.
667670
superChain.addAll(tryClass.superChain.map((t) => t.element as Class));
668671
for (final c in superChain) {
669-
// TODO(jcollins-g): add a hash-map-enabled lookup function to Class?
670-
for (final modelElement in c.allModelElements) {
671-
if (!_ConsiderIfConstructor(modelElement)) continue;
672-
String namePart = modelElement.fullyQualifiedName.split('.').last;
673-
if (modelElement is Accessor) {
674-
// TODO(jcollins-g): Individual classes should be responsible for
675-
// this name comparison munging.
676-
namePart = namePart.split('=').first;
677-
}
678-
// TODO(jcollins-g): fix operators so we can use 'name' here or similar.
679-
if (codeRefChomped == namePart) {
680-
results.add(packageGraph.findCanonicalModelElementFor(
681-
modelElement.element,
682-
preferredClass: tryClass));
683-
continue;
684-
}
685-
// Handle non-documented class documentation being imported into a
686-
// documented class when it refers to itself (with help from caller's
687-
// iteration on tryClasses).
688-
// TODO(jcollins-g): Fix partial qualifications in _findRefElementInLibrary so it can tell
689-
// when it is referenced from a non-documented element?
690-
// TODO(jcollins-g): We could probably check this early.
691-
if (codeRefChompedParts.first == c.name &&
692-
codeRefChompedParts.last == namePart) {
693-
results.add(packageGraph.findCanonicalModelElementFor(
694-
modelElement.element,
695-
preferredClass: tryClass));
696-
continue;
697-
}
698-
if (modelElement is Constructor) {
699-
// Constructor names don't include the class, so we might miss them in the above search.
700-
if (codeRefChompedParts.length > 1) {
701-
String codeRefClass =
702-
codeRefChompedParts[codeRefChompedParts.length - 2];
703-
String codeRefConstructor = codeRefChompedParts.last;
704-
if (codeRefClass == c.name &&
705-
codeRefConstructor ==
706-
modelElement.fullyQualifiedName.split('.').last) {
707-
results.add(packageGraph.findCanonicalModelElementFor(
708-
modelElement.element,
709-
preferredClass: tryClass));
710-
continue;
711-
}
712-
}
713-
}
714-
}
715-
results.remove(null);
672+
_getResultsForSuperChainElement(c, tryClass);
716673
if (results.isNotEmpty) break;
717-
if (c.fullyQualifiedNameWithoutLibrary == codeRefChomped) {
718-
results.add(c);
719-
break;
720-
}
721674
}
722675
}
723676
}
724677
}
678+
679+
/// Get any possible results for this class in the superChain. Returns
680+
/// true if we found something.
681+
void _getResultsForSuperChainElement(Class c, Class tryClass) {
682+
Iterable<ModelElement> membersToCheck;
683+
membersToCheck = (c.allModelElementsByNamePart[codeRefChomped] ?? [])
684+
.where((m) => _ConsiderIfConstructor(m));
685+
for (final ModelElement modelElement in membersToCheck) {
686+
// [thing], a member of this class
687+
_addCanonicalResult(modelElement, tryClass);
688+
}
689+
membersToCheck = (c.allModelElementsByNamePart[codeRefChompedParts.last] ??
690+
<ModelElement>[])
691+
.where((m) => _ConsiderIfConstructor(m));
692+
if (codeRefChompedParts.first == c.name) {
693+
// [Foo...thing], a member of this class (possibly a parameter).
694+
membersToCheck.map((m) => _addCanonicalResult(m, tryClass));
695+
} else if (codeRefChompedParts.length > 1 &&
696+
codeRefChompedParts[codeRefChompedParts.length - 2] == c.name) {
697+
// [....Foo.thing], a member of this class partially specified.
698+
membersToCheck
699+
.whereType<Constructor>()
700+
.map((m) => _addCanonicalResult(m, tryClass));
701+
}
702+
results.remove(null);
703+
if (results.isNotEmpty) return;
704+
if (c.fullyQualifiedNameWithoutLibrary == codeRefChomped) {
705+
results.add(c);
706+
}
707+
}
725708
}
726709

727710
String _linkDocReference(String codeRef, Warnable warnable,

lib/src/model.dart

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,14 @@ class Accessor extends ModelElement implements EnclosedElement {
531531
@override
532532
String get kind => 'accessor';
533533

534+
@override
535+
String get namePart {
536+
if (_namePart == null) {
537+
_namePart = super.namePart.split('=').first;
538+
}
539+
return _namePart;
540+
}
541+
534542
PropertyAccessorElement get _accessor => (element as PropertyAccessorElement);
535543
}
536544

@@ -684,6 +692,21 @@ class Class extends ModelElement
684692
return _allElements;
685693
}
686694

695+
Map<String, List<ModelElement>> _allModelElementsByNamePart;
696+
697+
/// Helper for [_MarkdownCommentReference._getResultsForClass].
698+
Map<String, List<ModelElement>> get allModelElementsByNamePart {
699+
if (_allModelElementsByNamePart == null) {
700+
_allModelElementsByNamePart = {};
701+
for (ModelElement me in allModelElements) {
702+
_allModelElementsByNamePart.update(
703+
me.namePart, (List<ModelElement> v) => v..add(me),
704+
ifAbsent: () => <ModelElement>[me]);
705+
}
706+
}
707+
return _allModelElementsByNamePart;
708+
}
709+
687710
/// This class might be canonical for elements it does not contain.
688711
/// See [Inheritable.canonicalEnclosingElement].
689712
bool contains(Element element) => allElements.containsKey(element);
@@ -4621,6 +4644,7 @@ class ModelFunctionTyped extends ModelElement
46214644
/// Something that has a name.
46224645
abstract class Nameable {
46234646
String get name;
4647+
String get fullyQualifiedName => name;
46244648

46254649
Set<String> _namePieces;
46264650
Set<String> get namePieces {
@@ -4630,11 +4654,22 @@ abstract class Nameable {
46304654
}
46314655
return _namePieces;
46324656
}
4657+
4658+
String _namePart;
4659+
4660+
/// Utility getter/cache for [_MarkdownCommentReference._getResultsForClass].
4661+
String get namePart {
4662+
// TODO(jcollins-g): This should really be the same as 'name', but isn't
4663+
// because of accessors and operators.
4664+
if (_namePart == null) {
4665+
_namePart = fullyQualifiedName.split('.').last;
4666+
}
4667+
return _namePart;
4668+
}
46334669
}
46344670

46354671
/// Something able to be indexed.
46364672
abstract class Indexable implements Nameable {
4637-
String get fullyQualifiedName => name;
46384673
String get href;
46394674
String get kind;
46404675
int get overriddenDepth => 0;
@@ -6568,8 +6603,6 @@ class PackageBuilder {
65686603
PerformanceLog log = new PerformanceLog(null);
65696604
AnalysisDriverScheduler scheduler = new AnalysisDriverScheduler(log);
65706605
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
6571-
options.enableSuperMixins = true;
6572-
options.previewDart2 = true;
65736606

65746607
// TODO(jcollins-g): Make use of currently not existing API for managing
65756608
// many AnalysisDrivers

0 commit comments

Comments
 (0)