Skip to content

Commit b2d317b

Browse files
authored
Refactor annotations handling, update to 0.9. (#1349)
This refactoring of annotations handling drops adding @s from templates in some cases, unifies code for pulling data out of analyzer, and eliminates hard to maintain and bug-causing returns in the middle of complex functions. It fixes multiple issues, including #1081, #1268, #1162 and more.
1 parent bf92da1 commit b2d317b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+144
-101
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.9.13
2+
3+
* fix multiple issues in annotation/feature list handling (#1268, #1162, #1081)
4+
15
## 0.9.12
26

37
* add print styles

lib/dartdoc.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export 'src/package_meta.dart';
4040

4141
const String name = 'dartdoc';
4242
// Update when pubspec version changes.
43-
const String version = '0.9.12';
43+
const String version = '0.9.13';
4444

4545
final String defaultOutDir = path.join('doc', 'api');
4646

lib/resources/styles.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,6 @@ nav .self-name {
456456
display: inline;
457457
}
458458

459-
.annotation-list li:before {
460-
content: "@";
461-
}
462-
463459
.comma-separated {
464460
list-style: none;
465461
padding: 0;

lib/src/model.dart

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import 'dart:convert';
99
import 'dart:io';
1010

1111
import 'package:analyzer/dart/ast/ast.dart'
12-
show AnnotatedNode, Annotation, Declaration;
12+
show AnnotatedNode, Declaration, FormalParameter, FieldDeclaration,
13+
VariableDeclaration, VariableDeclarationList;
1314
import 'package:analyzer/dart/element/element.dart';
1415
import 'package:analyzer/dart/element/type.dart';
1516
import 'package:analyzer/src/generated/resolver.dart'
@@ -913,9 +914,23 @@ class Field extends ModelElement
913914

914915
bool get writeOnly => hasSetter && !hasGetter;
915916

917+
@override
918+
List<String> get annotations {
919+
List<String> all_annotations = new List<String>();
920+
all_annotations.addAll(super.annotations);
921+
922+
if (element is PropertyInducingElement) {
923+
var pie = element as PropertyInducingElement;
924+
all_annotations.addAll(annotationsFromMetadata(pie.getter?.metadata));
925+
all_annotations.addAll(annotationsFromMetadata(pie.setter?.metadata));
926+
}
927+
return all_annotations.toList(growable: false);
928+
}
929+
916930
@override
917931
Set<String> get features {
918932
Set<String> all_features = super.features;
933+
all_features.addAll(annotations);
919934
/// final/const implies read-only, so don't display both strings.
920935
if (readOnly && !isFinal && !isConst) all_features.add('read-only');
921936
if (writeOnly) all_features.add('write-only');
@@ -1475,43 +1490,56 @@ abstract class ModelElement implements Comparable, Nameable, Documentable {
14751490
}
14761491

14771492
List<String> get annotations {
1478-
// Check https://code.google.com/p/dart/issues/detail?id=23181
1479-
// If that is fixed, this code might get a lot easier
1480-
if (element.computeNode() != null &&
1481-
element.computeNode() is AnnotatedNode) {
1482-
return (element.computeNode() as AnnotatedNode)
1483-
.metadata
1484-
.map((Annotation a) {
1485-
var annotationString = a.toSource().substring(1); // remove the @
1486-
var e = a.element;
1487-
if (e != null && (e is ConstructorElement)) {
1488-
var me = new ModelElement.from(
1489-
e.enclosingElement, package._getLibraryFor(e.enclosingElement));
1490-
if (me.href != null) {
1491-
return annotationString.replaceAll(me.name, me.linkedName);
1492-
}
1493-
}
1494-
return annotationString;
1495-
}).toList(growable: false);
1496-
} else {
1497-
return element.metadata.map((ElementAnnotation a) {
1498-
// TODO link to the element's href
1499-
return a.element.name;
1500-
}).toList(growable: false);
1501-
}
1493+
List<dynamic> metadata;
1494+
if (element.computeNode() is AnnotatedNode) {
1495+
AnnotatedNode node = element.computeNode() as AnnotatedNode;
1496+
1497+
// Declarations are contained inside FieldDeclarations, and that is where
1498+
// the actual annotations are.
1499+
while ((node is VariableDeclaration || node is VariableDeclarationList) &&
1500+
node is! FieldDeclaration) {
1501+
assert (null != (node as AnnotatedNode).parent);
1502+
node = node.parent;
1503+
}
1504+
metadata = node.metadata;
1505+
} else if (element.computeNode() is! FormalParameter) {
1506+
// TODO(jcollins-g): This is special cased to suppress annotations for
1507+
// parameters in constructor documentation. Do we
1508+
// want to do this?
1509+
metadata = element.metadata;
1510+
}
1511+
return annotationsFromMetadata(metadata);
1512+
}
1513+
1514+
/// Returns annotations from a given metadata set, with escaping.
1515+
/// md is a dynamic parameter since ElementAnnotation and Annotation have no
1516+
/// common class for calling toSource() and element.
1517+
List<String> annotationsFromMetadata(List<dynamic> md) {
1518+
if (md == null) md = new List<dynamic>();
1519+
return md.map((dynamic a) {
1520+
String annotation = (const HtmlEscape()).convert(a.toSource());
1521+
if (a.element is ConstructorElement) {
1522+
var me = new ModelElement.from(a.element.enclosingElement,
1523+
package._getLibraryFor(a.element.enclosingElement));
1524+
annotation = annotation.replaceFirst(me.name, me.linkedName);
1525+
}
1526+
return annotation;
1527+
}).toList(growable: false);
15021528
}
15031529

1504-
/// const and static are not needed here because const/static elements get
1505-
/// their own sections in the doc.
15061530
Set<String> get features {
15071531
Set<String> all_features = new Set<String>();
15081532
all_features.addAll(annotations);
1509-
/// override as an annotation should be replaced with direct information
1510-
/// from the analyzer if we decide to display it at this level.
1511-
all_features.remove('override');
1512-
/// Drop the plain "deprecated" annotation, that's indicated via
1513-
/// strikethroughs. Custom @Deprecated() will still appear.
1514-
all_features.remove('deprecated');
1533+
1534+
// override as an annotation should be replaced with direct information
1535+
// from the analyzer if we decide to display it at this level.
1536+
all_features.remove('@override');
1537+
1538+
// Drop the plain "deprecated" annotation, that's indicated via
1539+
// strikethroughs. Custom @Deprecated() will still appear.
1540+
all_features.remove('@deprecated');
1541+
// const and static are not needed here because const/static elements get
1542+
// their own sections in the doc.
15151543
if (isFinal) all_features.add('final');
15161544
return all_features;
15171545
}
@@ -1749,7 +1777,7 @@ abstract class ModelElement implements Comparable, Nameable, Documentable {
17491777
buf.write('<span class="parameter" id="${param.htmlId}">');
17501778
if (showMetadata && param.hasAnnotations) {
17511779
param.annotations.forEach((String annotation) {
1752-
buf.write('<span>@$annotation</span> ');
1780+
buf.write('<span>$annotation</span> ');
17531781
});
17541782
}
17551783
if (param.modelType.isFunctionType) {
@@ -2575,6 +2603,7 @@ class TopLevelVariable extends ModelElement
25752603
@override
25762604
Set<String> get features {
25772605
Set<String> all_features = super.features;
2606+
25782607
/// final/const implies read-only, so don't display both strings.
25792608
if (readOnly && !isFinal && !isConst) all_features.add('read-only');
25802609
if (writeOnly) all_features.add('write-only');

pubspec.lock

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ packages:
66
name: analyzer
77
url: "https://pub.dartlang.org"
88
source: hosted
9-
version: "0.29.0"
9+
version: "0.29.8"
1010
ansicolor:
1111
description:
1212
name: ansicolor
@@ -43,6 +43,12 @@ packages:
4343
url: "https://pub.dartlang.org"
4444
source: hosted
4545
version: "1.1.0"
46+
cli_util:
47+
description:
48+
name: cli_util
49+
url: "https://pub.dartlang.org"
50+
source: hosted
51+
version: "0.0.1+2"
4652
collection:
4753
description:
4854
name: collection
@@ -301,6 +307,18 @@ packages:
301307
url: "https://pub.dartlang.org"
302308
source: hosted
303309
version: "1.0.4"
310+
when:
311+
description:
312+
name: when
313+
url: "https://pub.dartlang.org"
314+
source: hosted
315+
version: "0.2.0"
316+
which:
317+
description:
318+
name: which
319+
url: "https://pub.dartlang.org"
320+
source: hosted
321+
version: "0.1.3"
304322
yaml:
305323
description:
306324
name: yaml

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ homepage: https://github.com/dart-lang/dartdoc
77
environment:
88
sdk: '>=1.14.0 <2.0.0'
99
dependencies:
10-
analyzer: ^0.29.0
10+
analyzer: ^0.29.8
1111
args: ^0.13.0
1212
collection: ^1.2.0
1313
html: '>=0.12.1 <0.14.0'

test/model_test.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,24 +1645,24 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans,
16451645
test('has one annotation',
16461646
() => expect(forAnnotation.annotations, hasLength(1)));
16471647

1648-
test('has the right annotation', () {
1648+
test('has the right annotation and is escaped', () {
16491649
expect(
16501650
forAnnotation.annotations.first,
16511651
equals(
1652-
'<a href="ex/ForAnnotation-class.html">ForAnnotation</a>(\'my value\')'));
1652+
'@<a href="ex/ForAnnotation-class.html">ForAnnotation</a>(&#39;my value&#39;)'));
16531653
});
16541654

16551655
test('methods has the right annotation', () {
16561656
var m = dog.instanceMethods.singleWhere((m) => m.name == 'getClassA');
16571657
expect(m.hasAnnotations, isTrue);
1658-
expect(m.annotations.first, equals('deprecated'));
1658+
expect(m.annotations.first, equals('@deprecated'));
16591659
});
16601660

1661-
test('method annotations have the right link', () {
1661+
test('method annotations have the right link and are escaped', () {
16621662
expect(
16631663
ctr.annotations[0],
16641664
equals(
1665-
'<a href="ex/Deprecated-class.html">Deprecated</a>("Internal use")'));
1665+
'@<a href="ex/Deprecated-class.html">Deprecated</a>(&quot;Internal use&quot;)'));
16661666
});
16671667
});
16681668

testing/test_package_docs/ex/B-class.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ <h2>Properties</h2>
198198
</dt>
199199
<dd>
200200
<p></p>
201-
<div class="features">read-only</div>
201+
<div class="features">@override, read-only</div>
202202
</dd>
203203
<dt id="list" class="property">
204204
<span class="name"><a href="ex/B/list.html">list</a></span>
@@ -214,7 +214,7 @@ <h2>Properties</h2>
214214
</dt>
215215
<dd>
216216
<p></p>
217-
<div class="features">read-only</div>
217+
<div class="features">@override, read-only</div>
218218
</dd>
219219
<dt id="fieldWithTypedef" class="property inherited">
220220
<span class="name"><a href="ex/Apple/fieldWithTypedef.html">fieldWithTypedef</a></span>

testing/test_package_docs/ex/B/abstractMethod.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ <h5><a href="ex/B-class.html">B</a></h5>
116116
<section class="multi-line-signature">
117117
<div>
118118
<ol class="annotation-list">
119-
<li>override</li>
119+
<li>@override</li>
120120
</ol>
121121
</div>
122122
<span class="returntype">void</span>

testing/test_package_docs/ex/B/doNothing.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ <h5><a href="ex/B-class.html">B</a></h5>
116116
<section class="multi-line-signature">
117117
<div>
118118
<ol class="annotation-list">
119-
<li>deprecated</li>
119+
<li>@deprecated</li>
120120
</ol>
121121
</div>
122122
<span class="returntype">Future</span>

0 commit comments

Comments
 (0)