Skip to content

Commit

Permalink
Integrate new parser with new lookup code (#2637)
Browse files Browse the repository at this point in the history
* Flatten

* rebuild
  • Loading branch information
jcollins-g committed May 7, 2021
1 parent 62e25f1 commit bd11290
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 18 deletions.
36 changes: 33 additions & 3 deletions lib/src/comment_references/model_comment_reference.dart
Expand Up @@ -9,7 +9,14 @@ import 'package:dartdoc/src/comment_references/parser.dart';
import 'package:dartdoc/src/model_utils.dart';

abstract class ModelCommentReference {
/// Does the structure of the reference itself imply a possible default
/// constructor?
// TODO(jcollins-g): rewrite/discard this once default constructor tear-off
// design process is complete.
bool get allowDefaultConstructor;
String get codeRef;
bool get hasConstructorHint;
List<String> get referenceBy;
Element get staticElement;

/// Construct a [ModelCommentReference] using the analyzer AST.
Expand All @@ -18,16 +25,37 @@ abstract class ModelCommentReference {
_ModelCommentReferenceImpl(ref, resourceProvider);

/// Construct a [ModelCommentReference] given a raw string.
factory ModelCommentReference.synthetic(String codeRef, Element element) =>
_ModelCommentReferenceImpl.synthetic(codeRef, element);
factory ModelCommentReference.synthetic(String codeRef) =>
_ModelCommentReferenceImpl.synthetic(codeRef, null);
}

/// A stripped down analyzer AST [CommentReference] containing only that
/// information needed for Dartdoc. Drops link to the [CommentReference]
/// and [ResourceProvider] after construction.
class _ModelCommentReferenceImpl implements ModelCommentReference {
@override
bool get allowDefaultConstructor {
if (parsed.length >= 2) {
return parsed[parsed.length - 2] == parsed[parsed.length - 1];
}
return false;
}

@override
final String codeRef;

@override
bool get hasConstructorHint =>
parsed.isNotEmpty &&
(parsed.first is ConstructorHintStartNode ||
parsed.last is ConstructorHintEndNode);

@override
List<String> get referenceBy => parsed
.whereType<IdentifierNode>()
.map<String>((i) => i.text)
.toList(growable: false);

@override
final Element staticElement;

Expand All @@ -47,5 +75,7 @@ class _ModelCommentReferenceImpl implements ModelCommentReference {
return contents.substring(ref.offset, ref.end);
}

List<CommentReferenceNode> parse() => CommentReferenceParser(codeRef).parse();
List<CommentReferenceNode> _parsed;
List<CommentReferenceNode> get parsed =>
_parsed ??= CommentReferenceParser(codeRef).parse();
}
12 changes: 12 additions & 0 deletions lib/src/generator/templates.renderers.dart
Expand Up @@ -2146,6 +2146,18 @@ class _Renderer_Class extends RendererBase<Class> {
parent: r));
},
),
'referenceParents': Property(
getValue: (CT_ c) => c.referenceParents,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(
c, remainingNames, 'Iterable<CommentReferable>'),
renderIterable:
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
return c.referenceParents.map(
(e) => renderSimple(e, ast, r.template, parent: r));
},
),
'superChain': Property(
getValue: (CT_ c) => c.superChain,
renderVariable: (CT_ c, Property<CT_> self,
Expand Down
1 change: 0 additions & 1 deletion lib/src/logging.dart
Expand Up @@ -105,7 +105,6 @@ void startLogging(LoggingContext config) {
stdout.write('${ansi.backspace} ${ansi.backspace}');
}
var message = record.message;
assert(message == message.trimRight());
assert(message.isNotEmpty);

if (record.level < Level.WARNING) {
Expand Down
37 changes: 29 additions & 8 deletions lib/src/markdown_processor.dart
Expand Up @@ -9,6 +9,7 @@ import 'dart:convert';
import 'dart:math';

import 'package:analyzer/dart/element/element.dart';
import 'package:dartdoc/src/comment_references/model_comment_reference.dart';
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/comment_referable.dart';
import 'package:dartdoc/src/model/model.dart';
Expand Down Expand Up @@ -275,19 +276,39 @@ ModelElement _getPreferredClass(ModelElement modelElement) {
return null;
}

/// Return false if the passed [referable] is a default [Constructor].
bool _rejectDefaultConstructors(CommentReferable referable) {
if (referable is Constructor &&
referable.name == referable.enclosingElement.name) {
return false;
}
return true;
}

/// Return false unless the passed [referable] is a [Constructor].
bool _requireConstructor(CommentReferable referable) =>
referable is Constructor;

/// Implements _getMatchingLinkElement via [CommentReferable.referenceBy].
MatchingLinkResult _getMatchingLinkElementCommentReferable(
String codeRef, Warnable warnable) {
if (!codeRef.contains(_constructorIndicationPattern) &&
codeRef.contains(notARealDocReference)) {
// Don't waste our time on things we won't ever find.
return MatchingLinkResult(null, warn: false);
var commentReference =
warnable.commentRefs[codeRef] ?? ModelCommentReference.synthetic(codeRef);
var filter = commentReference.hasConstructorHint
? _requireConstructor
: _rejectDefaultConstructors;

/// Neither reject, nor require, a default constructor in the event
/// the comment reference structure implies one. (We can not require it
/// in case a library name is the same as a member class name and the class
/// is the intended lookup).
if (commentReference.allowDefaultConstructor) {
filter = null;
}
var lookupResult =
warnable.referenceBy(commentReference.referenceBy, filter: filter);

// TODO(jcollins-g): implement implied constructor?
var codeRefChompedParts =
codeRef.replaceAll(_constructorIndicationPattern, '').split('.');
var lookupResult = warnable.referenceBy(codeRefChompedParts);
// TODO(jcollins-g): Consider prioritizing analyzer resolution before custom.
return MatchingLinkResult(lookupResult);
}

Expand Down
8 changes: 8 additions & 0 deletions lib/src/model/class.dart
Expand Up @@ -11,6 +11,8 @@ import 'package:dartdoc/src/model_utils.dart' as model_utils;
import 'package:dartdoc/src/quiver.dart' as quiver;
import 'package:meta/meta.dart';

import 'comment_referable.dart';

/// A [Container] defined with a `class` declaration in Dart.
///
/// Members follow similar naming rules to [Container], with the following
Expand Down Expand Up @@ -602,4 +604,10 @@ class Class extends Container

@override
Iterable<Field> get constantFields => allFields.where((f) => f.isConst);

@override
Iterable<CommentReferable> get referenceParents => <CommentReferable>[
...super.referenceParents,
...superChain.map((m) => m.modelElement)
];
}
17 changes: 13 additions & 4 deletions lib/src/model/comment_referable.dart
Expand Up @@ -23,9 +23,12 @@ class ReferenceChildrenLookup {
mixin CommentReferable implements Nameable {
/// Look up a comment reference by its component parts. If [tryParents] is
/// true, try looking up the same reference in any parents of [this].
/// Will skip over results that do not pass a given [filter] and keep
/// searching.
@nonVirtual
CommentReferable referenceBy(List<String> reference,
{bool tryParents = true}) {
{bool tryParents = true, bool Function(CommentReferable) filter}) {
filter ??= (r) => true;
if (reference.isEmpty) {
if (tryParents == false) return this;
return null;
Expand All @@ -37,16 +40,22 @@ mixin CommentReferable implements Nameable {
if (referenceChildren.containsKey(referenceLookup.lookup)) {
result = referenceChildren[referenceLookup.lookup];
if (referenceLookup.remaining.isNotEmpty) {
result =
result?.referenceBy(referenceLookup.remaining, tryParents: false);
result = result?.referenceBy(referenceLookup.remaining,
tryParents: false, filter: filter);
} else if (!filter(result)) {
result = result?.referenceBy([referenceLookup.lookup],
tryParents: false, filter: filter);
}
if (!filter(result)) {
result = null;
}
}
if (result != null) break;
}
// If we can't find it in children, try searching parents if allowed.
if (result == null && tryParents) {
for (var parent in referenceParents) {
result = parent.referenceBy(reference);
result = parent.referenceBy(reference, filter: filter);
if (result != null) break;
}
}
Expand Down
13 changes: 11 additions & 2 deletions test/comment_referable/comment_referable_test.dart
Expand Up @@ -17,13 +17,15 @@ abstract class Base extends Nameable with CommentReferable {
/// Returns the added (or already existing) [Base].
Base add(String newName);

Base lookup(String value) => referenceBy(value.split(_separator));
T lookup<T extends CommentReferable>(String value,
{bool Function(CommentReferable) filter}) =>
referenceBy(value.split(_separator), filter: filter);

@override
Element get element => throw UnimplementedError();
}

class Top extends Base {
class Top extends Base with CommentReferable {
@override
final String name;
final List<TopChild> children;
Expand Down Expand Up @@ -124,6 +126,7 @@ void main() {
referable.add('lib1.class2.member1');
referable.add('lib2');
referable.add('lib2.class3');
referable.add('lib3.lib3.lib3');
});

test('Check that basic lookups work', () {
Expand All @@ -132,5 +135,11 @@ void main() {
expect(referable.lookup('lib1.class2.member1').name, equals('member1'));
expect(referable.lookup('lib2.class3').name, equals('class3'));
});

test('Check that filters work', () {
expect(referable.lookup('lib3'), isA<TopChild>());
expect(referable.lookup('lib3', filter: ((r) => r is GenericChild)),
isA<GenericChild>());
});
});
}

0 comments on commit bd11290

Please sign in to comment.