-
Notifications
You must be signed in to change notification settings - Fork 124
Canonicalization overhaul #1368
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
Conversation
…nonicalization where possible
…nonicalization where possible
…s to work here at least
…mentors-and-file-overwriting
…e-deps had us throwing half the SDK docs into there.
lib/src/model.dart
Outdated
/// clean that up. | ||
factory ModelElement.from(Element e, Library library, | ||
{Class enclosingClass}) { | ||
if (library != null && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get rid of this breakpoint
lib/src/model.dart
Outdated
else | ||
newModelElement = new Operator.inherited(e, enclosingClass, library); | ||
} | ||
if (library != null && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete breakpoint
Taking a first pass through today - |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One pass through:
- the canonicalization work is excellent; this will be a night and day difference for
exports
from a correctness POV - the single factory ctor of model elements will really help the code quality, instead of having construction logic spread throughout the codebase
- we'll need to examine the use of asserts going forward, and make sure that there aren't any asserts that would be better handled as user facing errors
Given the scope of the fixes, this would make a good line in the sand for a 1.0 version. Perhaps we should do some light dartlang.org / css upgrades to give the generated html a slight facelift at the same time?
@@ -41,7 +41,7 @@ main(List<String> arguments) async { | |||
|
|||
Directory sdkDir = getSdkDir(); | |||
if (sdkDir == null) { | |||
print("Error: unable to locate the Dart SDK."); | |||
stderr.write(" Error: unable to locate the Dart SDK."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to using stderr here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
_writeFile(filename, content); | ||
// If you see this assert, we're probably being called to build non-canonical | ||
// docs somehow. Check data.self.isCanonical and callers for bugs. | ||
assert(!_writtenFiles.contains(fullName)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given these new asserts, we should make sure that whenever we run dartdoc during development (or on our CI) we run in checked mode. I believe there are some cases where the grind script is not run in checked mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Grind script now always runs dartdoc in checked mode.
lib/src/model.dart
Outdated
break; | ||
} | ||
} | ||
if (definingEnclosingElement.isCanonical) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we should have braces around single line if statements
lib/src/model.dart
Outdated
Map<String, ExecutableElement> imap = | ||
manager.getMembersInheritedFromInterfaces(element); | ||
library.inheritanceManager.getMembersInheritedFromInterfaces(element); | ||
|
||
_inheritedProperties = []; | ||
List<ExecutableElement> vs = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe vs
here stands for values. If so, perhaps we should rename the variable for understandability?
lib/src/model.dart
Outdated
@@ -610,13 +683,15 @@ class Class extends ModelElement implements EnclosedElement { | |||
return _operators; | |||
} | |||
|
|||
List<Operator> get operatorsForPages => _genPageOperators; | |||
List<Operator> get operatorsForPages => | |||
_genPageOperators.toList(growable: false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious, is there a reason why you're setting growable to false?
@@ -19,9 +19,9 @@ dependencies: | |||
mustache4dart: ^1.0.9 | |||
package_config: '>=0.1.5 <2.0.0' | |||
path: ^1.3.0 | |||
quiver: '>=0.18.0 <0.25.0' | |||
resource: '>=1.1.0 <3.0.0' | |||
resource: ^1.1.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resource
is on 2.1.2
; are we compatible with that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure. I just didn't see the reason for the ceiling so removed it (if we can cross one major version, likely we can cross others).
I can bump to ^2.1.0, add the ceiling, or both. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just check that the sdk deps is bringing in a 2.0 version, and then bump our use up to ^2.0.0.
test/model_test.dart
Outdated
expect(ExtendingClass.supertype.name, equals('BaseClass')); | ||
expect( | ||
ExtendingClass.supertype.element.library.name, equals('two_exports')); | ||
expect(ExtendingClass.superChain[0].name, equals('BaseClass')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to use foo.first
instead of foo[0]
in many cases - it's a bit more semantic; YMMV.
tool/grind.dart
Outdated
@@ -2,7 +2,7 @@ | |||
// for details. All rights reserved. Use of this source code is governed by a | |||
// BSD-style license that can be found in the LICENSE file. | |||
|
|||
import 'dart:async' show Future; | |||
import 'dart:async' show Future, Stream; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could also just drop the show
clause here...
tool/grind.dart
Outdated
@@ -259,6 +265,34 @@ int _findCount(String str, String match) { | |||
return count; | |||
} | |||
|
|||
Stream<FileSystemEntity> dirContents(String dir) { | |||
var lister = new Directory(dir).list(recursive: true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return immediately instead of creating a local var?
tool/grind.dart
Outdated
return lister; | ||
} | ||
|
||
_doFileCheck(String origin, Set<String> visited, bool error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void
?
On general comments: Re: canonicalization, thanks. Working with the code like this makes more sense to me than it did before this, and hopefully other developers will have the same experience. Single factory constructor for ModelElements is functionally correct but I am thinking of restructuring it so that it's possible to construct elements of a known type without harmful consequences. I couldn't think of a way to do this quickly that was actually clearer (or small) so put that off for now. This is definitely better than before; in general I want less constructory logic outside of the classes we're instantiating and there's more to do there with Package in particular. Yes on asserts; for a while I didn't even realize Dart asserts weren't valid outside of checked mode because IntelliJ was helpfully defaulting to having that on. Eventually I want all asserts to be errors, possibly fatal ones. |
As for 1.0, there are a few things I'd like to nail down before that for correctness. Created dartdoc 1.0 to track it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some initial comments, review in progress. Like the direction of the PR, great to see dartdoc get some tlc.
@@ -41,7 +41,7 @@ main(List<String> arguments) async { | |||
|
|||
Directory sdkDir = getSdkDir(); | |||
if (sdkDir == null) { | |||
print("Error: unable to locate the Dart SDK."); | |||
stderr.write(" Error: unable to locate the Dart SDK."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
package.allModelElements.forEach((m) => m.documentation); | ||
// TODO(jcollins-g): move index building into a cached-on-demand generation | ||
// like most other bits in [Package]. | ||
package.allCanonicalModelElements.forEach((m) => m.documentation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eliminates repeats? Were we looking at documentation for elements that were not documented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right.
lib/dartdoc.dart
Outdated
@@ -279,13 +286,40 @@ class DartDoc { | |||
// Use the includeExternals. | |||
for (Source source in context.librarySources) { | |||
LibraryElement library = context.computeLibraryElement(source); | |||
if (library == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you seeing use cases when the analyzer returns null for LibraryElement . Pretty sure it should not do so. Could you check with @bwilkerson on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Poked at this and I'm pretty sure this was an intermediate debugging step that got forgotten. Ran through my cases without it and saw no issues.
@@ -95,54 +97,81 @@ class HtmlGeneratorInstance implements HtmlOptions { | |||
generateLibrary(package, lib); | |||
|
|||
for (var clazz in lib.allClasses) { | |||
// TODO(jcollins-g): consider refactor so that only the canonical | |||
// ModelElements show up in these lists | |||
if (!clazz.isCanonical) continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So essentially there is a always one library that a class is canonical to (not sure if I got the lingo right here) and that's the only place it should be documented? If a class is not canonical, don't document it here, as it will be documented in the canonical library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct.
I seem to be unable to reply to comments once they are "out of date" with github's interface. But, @devoncarew, I believe all your comments are addressed. resource is 1.1.0 in the bleeding edge SDK. Working on @keertip's now. |
You should be able to; perhaps it's not easy to reply to the review header?
lgtm for my part! It'll be great to have these fixes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look good. Like the canonicalization changes, the logic makes sense, especially with the flutter use case. Looked through the changes in model.dart, nothing really stood out as a no no. The ones that I had some doubts about already had a todo, or else there was documentation!
Dartdoc needed this overhaul, as it has been in maintenance mode for a very long time and has organically grown to add support for the more complex use cases. Good to see this happen. Hoping to see a 1.0 release soon!
@@ -143,7 +195,7 @@ class Accessor extends ModelElement | |||
? t.getGetter(element.name) | |||
: t.getSetter(element.name); | |||
if (accessor != null) { | |||
return new Accessor(accessor, library); | |||
return new ModelElement.from(accessor, library); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Great to have just one way of creating ModelElement
lib/src/model.dart
Outdated
} | ||
|
||
var classContent = isDeprecated ? 'class="deprecated" ' : ''; | ||
return '<a ${classContent}href="${href}">$name</a>'; | ||
} | ||
|
||
// TODO(keertip): consolidate all the find library methods | ||
// This differs from package.findOrCreateLibraryFor in a small way, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the TODO still relevant? Also maybe change the names of the methods so that they don't sound so similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the TODO is still relevant; the way these functions are reusing parts of each other's functionality suggests that the lines are wrong between them, even if it isn't obvious yet exactly how to draw them.
Renamed this method and tweaked comments in a couple related places to improve clarity.
/// clean that up. | ||
factory ModelElement.from(Element e, Library library, | ||
{Class enclosingClass}) { | ||
Tuple3<Element, Library, Class> key = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is what was needed. Knew that dartdoc was likely creating ModelElements for the same element multiple times, but this was just a todo, until now!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. It turns out you just can't build things like canonicalization or most of the other things we'd like to do (like machine-readable public API descriptions) without this.
The giant canonicalization overhaul is shaped up well enough I'd prefer to try to submit a PR before improving it further. There are definitely still some known issues, but I'm now reasonably satisfied it introduces no new problems.
This is big. Some tips on reviewing: Changes to ModelElement and the new mixin class, Inheritable, in lib/src/model.dart are the most important, especially any method with the word "canonical" in its name. If you understand the changes there, most of the rest of what you see can be understood as downstream consequences. I've tried to apply comments and inline documentation liberally, please feel free to ask for more where it isn't clear.