Skip to content

Classes and helper methods to avoid holding AstNodes #1857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions lib/src/markdown_processor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ library dartdoc.markdown_processor;
import 'dart:convert';
import 'dart:math';

import 'package:analyzer/dart/ast/ast.dart' hide TypeParameter;
import 'package:analyzer/dart/element/element.dart';
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model.dart';
Expand Down Expand Up @@ -186,7 +185,7 @@ ModelElement _getPreferredClass(ModelElement modelElement) {

/// Returns null if element is a parameter.
MatchingLinkResult _getMatchingLinkElement(
String codeRef, Warnable element, List<CommentReference> commentRefs) {
String codeRef, Warnable element, List<ModelCommentReference> commentRefs) {
if (!codeRef.contains(isConstructor) &&
codeRef.contains(notARealDocReference)) {
// Don't waste our time on things we won't ever find.
Expand Down Expand Up @@ -244,15 +243,14 @@ MatchingLinkResult _getMatchingLinkElement(

/// Given a set of commentRefs, return the one whose name matches the codeRef.
Element _getRefElementFromCommentRefs(
List<CommentReference> commentRefs, String codeRef) {
List<ModelCommentReference> commentRefs, String codeRef) {
if (commentRefs != null) {
for (CommentReference ref in commentRefs) {
if (ref.identifier.name == codeRef) {
bool isConstrElement =
ref.identifier.staticElement is ConstructorElement;
for (ModelCommentReference ref in commentRefs) {
if (ref.name == codeRef) {
bool isConstrElement = ref.staticElement is ConstructorElement;
// Constructors are now handled by library search.
if (!isConstrElement) {
Element refElement = ref.identifier.staticElement;
Element refElement = ref.staticElement;
if (refElement is PropertyAccessorElement) {
// yay we found an accessor that wraps a const, but we really
// want the top-level field itself
Expand All @@ -278,8 +276,8 @@ class _MarkdownCommentReference {
/// The element containing the code reference.
final Warnable element;

/// A list of [CommentReference]s from the analyzer.
final List<CommentReference> commentRefs;
/// A list of [ModelCommentReference]s for this element.
final List<ModelCommentReference> commentRefs;

/// Disambiguate inheritance with this class.
final Class preferredClass;
Expand Down Expand Up @@ -726,8 +724,8 @@ class _MarkdownCommentReference {
}
}

String _linkDocReference(
String codeRef, Warnable warnable, List<CommentReference> commentRefs) {
String _linkDocReference(String codeRef, Warnable warnable,
List<ModelCommentReference> commentRefs) {
MatchingLinkResult result;
result = _getMatchingLinkElement(codeRef, warnable, commentRefs);
final ModelElement linkedElement = result.element;
Expand Down Expand Up @@ -950,7 +948,7 @@ class Documentation {
return _asOneLiner;
}

List<CommentReference> get commentRefs => _element.commentRefs;
List<ModelCommentReference> get commentRefs => _element.commentRefs;

void _renderHtmlForDartdoc(bool processAllDocs) {
Tuple3<String, String, bool> renderResults =
Expand Down
133 changes: 82 additions & 51 deletions lib/src/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,9 @@ class Accessor extends ModelElement implements EnclosedElement {
String get sourceCode {
if (_sourceCode == null) {
if (isSynthetic) {
_sourceCode =
sourceCodeFor((element as PropertyAccessorElement).variable);
_sourceCode = packageGraph
._getModelNodeFor((element as PropertyAccessorElement).variable)
.sourceCode;
} else {
_sourceCode = super.sourceCode;
}
Expand Down Expand Up @@ -1420,13 +1421,72 @@ abstract class Categorization implements ModelElement {
}
}

/// A stripped down [CommentReference] containing only that information needed
/// for Dartdoc. Drops link to the [CommentReference] after construction.
class ModelCommentReference {
final String name;
final Element staticElement;
ModelCommentReference(CommentReference ref)
: name = ref.identifier.name,
staticElement = ref.identifier.staticElement {}
}

/// Stripped down information derived from [AstNode] containing only information
/// needed for Dartdoc. Drops link to the [AstNode] after construction.
class ModelNode {
final List<ModelCommentReference> commentRefs;
final String sourceCode;
final Element element;

ModelNode(AstNode sourceNode, this.element)
: sourceCode = _sourceCodeFor(sourceNode, element),
commentRefs = _commentRefsFor(sourceNode) {}

static List<ModelCommentReference> _commentRefsFor(AstNode node) {
if (node is AnnotatedNode &&
node?.documentationComment?.references != null) {
return node.documentationComment.references
.map((c) => ModelCommentReference(c))
.toList(growable: false);
}
return null;
}

static String _sourceCodeFor(AstNode node, Element element) {
String contents = getFileContentsFor(element);
if (node != null) {
// Find the start of the line, so that we can line up all the indents.
int i = node.offset;
while (i > 0) {
i -= 1;
if (contents[i] == '\n' || contents[i] == '\r') {
i += 1;
break;
}
}

// Trim the common indent from the source snippet.
var start = node.offset - (node.offset - i);
String source = contents.substring(start, node.end);

source = const HtmlEscape().convert(source);
source = stripIndentFromSource(source);
source = stripDartdocCommentsFromSource(source);

return source.trim();
} else {
return '';
}
}
}

/// Classes extending this class have canonicalization support in Dartdoc.
abstract class Canonicalization implements Locatable, Documentable {
bool get isCanonical;
Library get canonicalLibrary;

List<CommentReference> _commentRefs;
List<CommentReference> get commentRefs => _commentRefs;
List<ModelCommentReference> _commentRefs;
List<ModelCommentReference> get commentRefs => _commentRefs;

/// Pieces of the location split by [locationSplitter] (removing package: and
/// slashes).
Expand Down Expand Up @@ -1758,7 +1818,7 @@ class Field extends ModelElement
String get sourceCode {
if (_sourceCode == null) {
// We could use a set to figure the dupes out, but that would lose ordering.
String fieldSourceCode = sourceCodeFor(element) ?? '';
String fieldSourceCode = modelNode.sourceCode ?? '';
String getterSourceCode = getter?.sourceCode ?? '';
String setterSourceCode = setter?.sourceCode ?? '';
StringBuffer buffer = new StringBuffer();
Expand Down Expand Up @@ -3036,12 +3096,10 @@ abstract class ModelElement extends Canonicalization
.packageGraph.libraryElementReexportedBy[this.element.library];
}

AstNode _astNode;
ModelNode _modelNode;
@override
AstNode get astNode {
_astNode ??= element?.computeNode();
return _astNode;
}
ModelNode get modelNode =>
_modelNode ??= packageGraph._getModelNodeFor(element);

List<String> get annotations => annotationsFromMetadata(element.metadata);

Expand Down Expand Up @@ -3112,7 +3170,7 @@ abstract class ModelElement extends Canonicalization
}

@override
List<CommentReference> get commentRefs {
List<ModelCommentReference> get commentRefs {
if (_commentRefs == null) {
_commentRefs = [];
for (ModelElement from in documentationFrom) {
Expand All @@ -3121,11 +3179,7 @@ abstract class ModelElement extends Canonicalization
checkReferences.add(from.enclosingCombo);
}
for (ModelElement e in checkReferences) {
AstNode node = e.astNode;
if (node is AnnotatedNode &&
node?.documentationComment?.references != null) {
_commentRefs.addAll(node.documentationComment.references);
}
_commentRefs.addAll(e.modelNode.commentRefs ?? []);
}
}
}
Expand Down Expand Up @@ -4674,6 +4728,16 @@ class PackageGraph {
}
}

// Many ModelElements have the same ModelNode; don't build/cache this data more
// than once for them.
final Map<Element, ModelNode> _modelNodes = Map();
ModelNode _getModelNodeFor(element) {
/// TODO(jcollins-g): merge with removal of computeNode.
_modelNodes.putIfAbsent(
element, () => ModelNode(element?.computeNode(), element));
return _modelNodes[element];
}

SpecialClasses specialClasses;

/// It is safe to cache values derived from the _implementors table if this
Expand Down Expand Up @@ -6087,7 +6151,7 @@ class Parameter extends ModelElement implements EnclosedElement {
}

abstract class SourceCodeMixin implements Documentable {
AstNode get astNode;
ModelNode get modelNode;

Tuple2<int, int> get lineAndColumn;

Expand All @@ -6097,41 +6161,8 @@ abstract class SourceCodeMixin implements Documentable {

Library get library;

String sourceCodeFor(Element element) {
String contents = getFileContentsFor(element);
var node = element.computeNode();
if (node != null) {
// Find the start of the line, so that we can line up all the indents.
int i = node.offset;
while (i > 0) {
i -= 1;
if (contents[i] == '\n' || contents[i] == '\r') {
i += 1;
break;
}
}

// Trim the common indent from the source snippet.
var start = node.offset - (node.offset - i);
String source = contents.substring(start, node.end);

source = const HtmlEscape().convert(source);
source = stripIndentFromSource(source);
source = stripDartdocCommentsFromSource(source);

return source.trim();
} else {
return '';
}
}

String _sourceCode;
String get sourceCode {
if (_sourceCode == null) {
_sourceCode = sourceCodeFor(element);
}
return _sourceCode;
}
String get sourceCode => _sourceCode ??= modelNode.sourceCode;
}

abstract class TypeParameters implements ModelElement {
Expand Down