Skip to content

Commit 9da617b

Browse files
authored
Convert to using a single AnalysisDriver in place of a single AnalysisContext. (#1598)
* More or less wired up. * Hacks everywhere but dartdoc mostly works * Analysis driver seems to work * Cleanup and regen docs * Add link to analyzer issue and dartfmt * fix analyzer error I missed somehow * Removing computeNode from annotations tests as safe now. * Cleanup dynamic use (no longer necessary since element.metadata is reliable now) * review comment
1 parent 143d4b2 commit 9da617b

File tree

11 files changed

+111
-95
lines changed

11 files changed

+111
-95
lines changed

lib/dartdoc.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'dart:convert';
1010
import 'dart:io';
1111

1212
import 'package:analyzer/analyzer.dart';
13+
import 'package:analyzer/dart/analysis/results.dart';
1314
import 'package:analyzer/src/generated/engine.dart';
1415
import 'package:analyzer/src/generated/source.dart';
1516
import 'package:dartdoc/src/utils.dart';
@@ -99,14 +100,14 @@ class DartDoc extends PackageBuilder {
99100
Stream<String> get onCheckProgress => _onCheckProgress.stream;
100101

101102
@override
102-
void logAnalysisErrors(Set<Source> sources) {
103+
logAnalysisErrors(Set<Source> sources) async {
103104
List<AnalysisErrorInfo> errorInfos = [];
104105
// TODO(jcollins-g): figure out why sources can't contain includeExternals
105106
// or embedded SDK components without having spurious(?) analysis errors.
106107
// That seems wrong. dart-lang/dartdoc#1547
107108
for (Source source in sources) {
108-
context.computeErrors(source);
109-
AnalysisErrorInfo info = context.getErrors(source);
109+
ErrorsResult errorsResult = await driver.getErrors(source.fullName);
110+
AnalysisErrorInfo info = new AnalysisErrorInfoImpl(errorsResult.errors, errorsResult.lineInfo);
110111
List<_Error> errors = [info]
111112
.expand((AnalysisErrorInfo info) {
112113
return info.errors.map((error) =>
@@ -153,7 +154,7 @@ class DartDoc extends PackageBuilder {
153154
Future<DartDocResults> generateDocs() async {
154155
Stopwatch _stopwatch = new Stopwatch()..start();
155156
double seconds;
156-
package = buildPackage();
157+
package = await buildPackage();
157158
seconds = _stopwatch.elapsedMilliseconds / 1000.0;
158159
logInfo(
159160
"Initialized dartdoc with ${package.libraries.length} librar${package.libraries.length == 1 ? 'y' : 'ies'} "

lib/src/model.dart

Lines changed: 82 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,13 @@
55
/// The models used to represent Dart code.
66
library dartdoc.models;
77

8+
import 'dart:async';
89
import 'dart:collection' show UnmodifiableListView;
910
import 'dart:convert';
1011
import 'dart:io';
1112

1213
import 'package:analyzer/dart/ast/ast.dart'
13-
show
14-
AnnotatedNode,
15-
Declaration,
16-
Expression,
17-
FieldDeclaration,
18-
InstanceCreationExpression,
19-
VariableDeclaration,
20-
VariableDeclarationList;
14+
show Declaration, Expression, InstanceCreationExpression;
2115
import 'package:analyzer/dart/element/element.dart';
2216
import 'package:analyzer/dart/element/type.dart';
2317
import 'package:analyzer/file_system/file_system.dart' as fileSystem;
@@ -26,9 +20,11 @@ import 'package:analyzer/source/package_map_resolver.dart';
2620
import 'package:analyzer/source/sdk_ext.dart';
2721
// TODO(jcollins-g): Stop using internal analyzer structures somehow.
2822
import 'package:analyzer/src/context/builder.dart';
23+
import 'package:analyzer/src/dart/analysis/file_state.dart';
2924
import 'package:analyzer/src/dart/element/element.dart';
25+
import 'package:analyzer/src/dart/element/handle.dart';
3026
import 'package:analyzer/src/dart/sdk/sdk.dart';
31-
import 'package:analyzer/src/generated/engine.dart';
27+
import 'package:analyzer/src/generated/engine.dart' hide AnalysisResult;
3228
import 'package:analyzer/src/generated/java_io.dart';
3329
import 'package:analyzer/src/generated/resolver.dart'
3430
show Namespace, NamespaceBuilder, InheritanceManager;
@@ -38,8 +34,11 @@ import 'package:analyzer/src/generated/source_io.dart';
3834
import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind;
3935
import 'package:analyzer/src/dart/element/member.dart'
4036
show ExecutableMember, Member, ParameterMember;
37+
import 'package:analyzer/src/dart/analysis/driver.dart';
4138
import 'package:collection/collection.dart';
4239
import 'package:dartdoc/src/io_utils.dart';
40+
import 'package:front_end/byte_store.dart';
41+
import 'package:front_end/src/base/performance_logger.dart';
4342
import 'package:path/path.dart' as p;
4443
import 'package:tuple/tuple.dart';
4544
import 'package:package_config/discovery.dart' as package_config;
@@ -2062,7 +2061,7 @@ class Library extends ModelElement {
20622061
String get nameFromPath {
20632062
if (_nameFromPath == null) {
20642063
_nameFromPath =
2065-
getNameFromPath(element, package.context, package.packageMeta);
2064+
getNameFromPath(element, package.driver, package.packageMeta);
20662065
}
20672066
return _nameFromPath;
20682067
}
@@ -2200,13 +2199,13 @@ class Library extends ModelElement {
22002199
/// Not the same as [Package.name] because there we always strip all
22012200
/// path components; this function only strips the package prefix if the
22022201
/// library is part of the default package.
2203-
static String getNameFromPath(LibraryElement element, AnalysisContext context,
2202+
static String getNameFromPath(LibraryElement element, AnalysisDriver driver,
22042203
PackageMeta defaultPackage) {
22052204
String name;
22062205
if (element.source.uri.toString().startsWith('dart:')) {
22072206
name = element.source.uri.toString();
22082207
} else {
2209-
name = context.sourceFactory.restoreUri(element.source).toString();
2208+
name = driver.sourceFactory.restoreUri(element.source).toString();
22102209
}
22112210
if (name.startsWith('file:')) {
22122211
// restoreUri doesn't do anything for the package we're documenting.
@@ -2575,6 +2574,12 @@ abstract class ModelElement extends Canonicalization
25752574
Accessor getter,
25762575
Accessor setter,
25772576
Package package}) {
2577+
// With AnalysisDriver, we sometimes get ElementHandles when building
2578+
// docs for the SDK, seen via [Library.importedExportedLibraries]. Why?
2579+
if (e is ElementHandle) {
2580+
e = (e as ElementHandle).actualElement;
2581+
}
2582+
25782583
Member originalMember;
25792584
// TODO(jcollins-g): Refactor object model to instantiate 'ModelMembers'
25802585
// for members?
@@ -2632,7 +2637,9 @@ abstract class ModelElement extends Canonicalization
26322637
assert(e.enclosingElement.name != '');
26332638
newModelElement = new ModelFunctionTypedef(e, library);
26342639
} else {
2635-
assert(e.name == '');
2640+
// Allowing null here is allowed as a workaround for
2641+
// dart-lang/sdk#32005.
2642+
assert(e.name == '' || e.name == null);
26362643
newModelElement = new ModelFunctionAnonymous(e, library);
26372644
}
26382645
}
@@ -2644,7 +2651,7 @@ abstract class ModelElement extends Canonicalization
26442651
if (enclosingClass == null) {
26452652
if (e.isEnumConstant) {
26462653
int index =
2647-
e.computeConstantValue().getField('index').toIntValue();
2654+
e.computeConstantValue().getField(e.name).toIntValue();
26482655
newModelElement =
26492656
new EnumField.forConstant(index, e, library, getter);
26502657
} else if (e.enclosingElement.isEnum) {
@@ -2737,31 +2744,12 @@ abstract class ModelElement extends Canonicalization
27372744

27382745
// TODO(jcollins-g): annotations should now be able to use the utility
27392746
// functions in package for finding elements and avoid using computeNode().
2740-
List<String> get annotations {
2741-
List<dynamic> metadata;
2742-
if (element.computeNode() is AnnotatedNode) {
2743-
AnnotatedNode node = element.computeNode() as AnnotatedNode;
2744-
2745-
// Declarations are contained inside FieldDeclarations, and that is where
2746-
// the actual annotations are.
2747-
while ((node is VariableDeclaration || node is VariableDeclarationList) &&
2748-
node is! FieldDeclaration) {
2749-
assert(null != node.parent);
2750-
node = node.parent;
2751-
}
2752-
metadata = node.metadata;
2753-
} else {
2754-
metadata = element.metadata;
2755-
}
2756-
return annotationsFromMetadata(metadata);
2757-
}
2747+
List<String> get annotations => annotationsFromMetadata(element.metadata);
27582748

2759-
/// Returns annotations from a given metadata set, with escaping.
2760-
/// md is a dynamic parameter since ElementAnnotation and Annotation have no
2761-
/// common class for calling toSource() and element.
2762-
List<String> annotationsFromMetadata(List<dynamic> md) {
2763-
if (md == null) md = new List<dynamic>();
2764-
return md.map((dynamic a) {
2749+
/// Returns linked annotations from a given metadata set, with escaping.
2750+
List<String> annotationsFromMetadata(List<ElementAnnotation> md) {
2751+
if (md == null) return <String>[];
2752+
return md.map((ElementAnnotation a) {
27652753
String annotation = (const HtmlEscape()).convert(a.toSource());
27662754
// a.element can be null if the element can't be resolved.
27672755
var me =
@@ -3863,7 +3851,7 @@ class Package extends Canonicalization with Nameable, Warnable {
38633851
@override
38643852
Package get package => this;
38653853

3866-
final AnalysisContext context;
3854+
final AnalysisDriver driver;
38673855
final DartSdk sdk;
38683856

38693857
Map<Source, SdkLibrary> _sdkLibrarySources;
@@ -3899,7 +3887,7 @@ class Package extends Canonicalization with Nameable, Warnable {
38993887
bool _macrosAdded = false;
39003888

39013889
Package(Iterable<LibraryElement> libraryElements, this.packageMeta,
3902-
this._packageWarningOptions, this.context,
3890+
this._packageWarningOptions, this.driver,
39033891
[this.sdk]) {
39043892
assert(_allConstructedModelElements.isEmpty);
39053893
assert(allLibraries.isEmpty);
@@ -4641,7 +4629,14 @@ class Parameter extends ModelElement implements EnclosedElement {
46414629
String enclosingName = _parameter.enclosingElement.name;
46424630
if (_parameter.enclosingElement is GenericFunctionTypeElement) {
46434631
// TODO(jcollins-g): Drop when GenericFunctionTypeElement populates name.
4644-
enclosingName = _parameter.enclosingElement.enclosingElement.name;
4632+
// Also, allowing null here is allowed as a workaround for
4633+
// dart-lang/sdk#32005.
4634+
for (Element e = _parameter.enclosingElement;
4635+
e.enclosingElement != null;
4636+
e = e.enclosingElement) {
4637+
enclosingName = e.name;
4638+
if (enclosingName != null && enclosingName.isNotEmpty) break;
4639+
}
46454640
}
46464641
return '${enclosingName}-param-${name}';
46474642
}
@@ -4999,10 +4994,10 @@ class PackageBuilder {
49994994

50004995
void logAnalysisErrors(Set<Source> sources) {}
50014996

5002-
Package buildPackage() {
5003-
Set<LibraryElement> libraries = getLibraries(getFiles);
4997+
Future<Package> buildPackage() async {
4998+
Set<LibraryElement> libraries = await getLibraries(getFiles);
50044999
return new Package(
5005-
libraries, packageMeta, getWarningOptions(), context, sdk);
5000+
libraries, packageMeta, getWarningOptions(), driver, sdk);
50065001
}
50075002

50085003
DartSdk _sdk;
@@ -5079,19 +5074,32 @@ class PackageBuilder {
50795074
return sourceFactory;
50805075
}
50815076

5082-
AnalysisContext _context;
5083-
AnalysisContext get context {
5084-
if (_context == null) {
5085-
// TODO(jcollins-g): fix this so it actually obeys analyzer options files.
5086-
var options = new AnalysisOptionsImpl();
5077+
AnalysisDriver _driver;
5078+
AnalysisDriver get driver {
5079+
if (_driver == null) {
5080+
// The performance log is why we have a direct dependency on front_end.
5081+
PerformanceLog log = new PerformanceLog(null);
5082+
AnalysisDriverScheduler scheduler = new AnalysisDriverScheduler(log);
5083+
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
50875084
options.enableSuperMixins = true;
5088-
AnalysisEngine.instance.processRequiredPlugins();
50895085

5090-
_context = AnalysisEngine.instance.createAnalysisContext()
5091-
..analysisOptions = options
5092-
..sourceFactory = sourceFactory;
5093-
}
5094-
return _context;
5086+
// TODO(jcollins-g): Make use of currently not existing API for managing
5087+
// many AnalysisDrivers
5088+
// TODO(jcollins-g): make use of DartProject isApi()
5089+
_driver = new AnalysisDriver(
5090+
scheduler,
5091+
log,
5092+
PhysicalResourceProvider.INSTANCE,
5093+
new MemoryByteStore(),
5094+
new FileContentOverlay(),
5095+
null,
5096+
sourceFactory,
5097+
options);
5098+
driver.results.listen((_) {});
5099+
driver.exceptions.listen((_) {});
5100+
scheduler.start();
5101+
}
5102+
return _driver;
50955103
}
50965104

50975105
PackageWarningOptions getWarningOptions() {
@@ -5119,11 +5127,11 @@ class PackageBuilder {
51195127

51205128
bool isExcluded(String name) => excludes.any((pattern) => name == pattern);
51215129

5122-
/// Parse a single library at [filePath] using the current analysis context.
5130+
/// Parse a single library at [filePath] using the current analysis driver.
51235131
/// Note: [libraries] and [sources] are output parameters. Adds a libraryElement
51245132
/// only if it has a non-private name.
5125-
void processLibrary(
5126-
String filePath, Set<LibraryElement> libraries, Set<Source> sources) {
5133+
Future processLibrary(String filePath, Set<LibraryElement> libraries,
5134+
Set<Source> sources) async {
51275135
String name = filePath;
51285136
if (name.startsWith(Directory.current.path)) {
51295137
name = name.substring(Directory.current.path.length);
@@ -5140,15 +5148,16 @@ class PackageBuilder {
51405148
if (uri != null) {
51415149
source = new FileBasedSource(javaFile, uri);
51425150
} else {
5143-
uri = context.sourceFactory.restoreUri(source);
5151+
uri = driver.sourceFactory.restoreUri(source);
51445152
if (uri != null) {
51455153
source = new FileBasedSource(javaFile, uri);
51465154
}
51475155
}
51485156
// TODO(jcollins-g): Excludes can match on uri or on name. Fix that.
51495157
if (!isExcluded(source.uri.toString())) {
5150-
if (context.computeKindOf(source) == SourceKind.LIBRARY) {
5151-
LibraryElement library = context.computeLibraryElement(source);
5158+
LibraryElement library =
5159+
await driver.getLibraryByUri(source.uri.toString());
5160+
if (library != null) {
51525161
if (!isExcluded(Library.getLibraryName(library)) &&
51535162
!excludePackages.contains(Library.getPackageMeta(library)?.name)) {
51545163
libraries.add(library);
@@ -5158,16 +5167,13 @@ class PackageBuilder {
51585167
}
51595168
}
51605169

5161-
List<LibraryElement> _parseLibraries(Set<String> files) {
5170+
Future<List<LibraryElement>> _parseLibraries(Set<String> files) async {
51625171
Set<LibraryElement> libraries = new Set();
5163-
Set<Source> sources = new Set();
5164-
files.forEach((filename) => processLibrary(filename, libraries, sources));
5165-
// Ensure that the analysis engine performs all remaining work.
5166-
AnalysisResult result = context.performAnalysisTask();
5167-
while (result.hasMoreWork) {
5168-
result = context.performAnalysisTask();
5169-
}
5170-
logAnalysisErrors(sources);
5172+
Set<Source> sources = new Set<Source>();
5173+
files.forEach((filename) => driver.addFile(filename));
5174+
5175+
await Future.wait(files.map((f) => processLibrary(f, libraries, sources)));
5176+
await logAnalysisErrors(sources);
51715177
return libraries.toList();
51725178
}
51735179

@@ -5238,16 +5244,16 @@ class PackageBuilder {
52385244
});
52395245
}
52405246
// Use the includeExternals.
5241-
for (Source source in context.librarySources) {
5242-
if (includeExternals.any((string) => source.fullName.endsWith(string)))
5243-
files.add(source.fullName);
5247+
for (String fullName in driver.knownFiles) {
5248+
if (includeExternals.any((string) => fullName.endsWith(string)))
5249+
files.add(fullName);
52445250
}
5245-
return files;
5251+
return new Set.from(files.map((s) => new File(s).absolute.path));
52465252
}
52475253

5248-
Set<LibraryElement> getLibraries(Set<String> files) {
5254+
Future<Set<LibraryElement>> getLibraries(Set<String> files) async {
52495255
Set<LibraryElement> libraries = new Set();
5250-
libraries.addAll(_parseLibraries(files));
5256+
libraries.addAll(await _parseLibraries(files));
52515257
if (includes != null && includes.isNotEmpty) {
52525258
Iterable knownLibraryNames = libraries.map((l) => l.name);
52535259
Set notFound =

lib/src/model_utils.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ bool isInExportedLibraries(
6767

6868
final RegExp slashes = new RegExp('[\/]');
6969
bool hasPrivateName(Element e) {
70+
if (e.name == null) return false;
71+
7072
if (e.name.startsWith('_')) {
7173
return true;
7274
}

pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ packages:
8686
source: hosted
8787
version: "0.3.1"
8888
front_end:
89-
dependency: transitive
89+
dependency: "direct main"
9090
description:
9191
name: front_end
9292
url: "https://pub.dartlang.org"

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies:
1212
analyzer: 0.31.0-alpha.2
1313
args: '>=0.13.0 <2.0.0'
1414
collection: ^1.2.0
15+
front_end: ^0.1.0-alpha.7
1516
html: '>=0.12.1 <0.14.0'
1617
# We don't use http_parser directly; this dep exists to ensure that we get at
1718
# least version 3.0.3 to work around an issue with 3.0.2.

test/model_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ void main() {
3131
Library interceptorsLib;
3232
Package sdkAsPackage;
3333

34-
setUpAll(() {
35-
utils.init();
34+
setUpAll(() async {
35+
await utils.init();
3636
package = utils.testPackage;
3737
ginormousPackage = utils.testPackageGinormous;
3838
exLibrary = package.libraries.firstWhere((lib) => lib.name == 'ex');
@@ -2065,7 +2065,7 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans,
20652065
expect(
20662066
aComplexTypedef.linkedReturnType,
20672067
equals(
2068-
'Function<span class="signature">(<span class="parameter" id="-param-"><span class="type-annotation">A1</span>, </span> <span class="parameter" id="-param-"><span class="type-annotation">A2</span>, </span> <span class="parameter" id="-param-"><span class="type-annotation">A3</span></span>)</span>'));
2068+
'Function<span class="signature">(<span class="parameter" id="aComplexTypedef-param-"><span class="type-annotation">A1</span>, </span> <span class="parameter" id="aComplexTypedef-param-"><span class="type-annotation">A2</span>, </span> <span class="parameter" id="aComplexTypedef-param-"><span class="type-annotation">A3</span></span>)</span>'));
20692069
expect(
20702070
aComplexTypedef.linkedParamsLines,
20712071
equals(

0 commit comments

Comments
 (0)