-
Notifications
You must be signed in to change notification settings - Fork 124
canonicalization overhaul part 3: Types, Templates, and Public/Private #1524
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
if (property.name == 'topLevelVariable') | ||
1+1; | ||
if (property.linkedReturnType == '') | ||
1+1; |
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.
Ditto
if (!property.isCanonical) continue; | ||
for (var property in lib.properties.where((p) => p.isDocumented)) { | ||
if (property.name == 'topLevelVariable') | ||
1+1; |
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.
????
lib/src/markdown_processor.dart
Outdated
@@ -390,6 +390,7 @@ Element _findRefElementInLibrary(String codeRef, ModelElement element, | |||
assert(element != null); | |||
assert(element.package.allLibrariesAdded); | |||
|
|||
|
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.
??? Dartfmt won't like this...
To be clear, this is WIP and not intended to land. Mostly this will be reference material for the breakout pieces as I submit those. |
Taking a spin through now just to get familiar - |
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 took a pass through; looking forward to the sub-PRs. Also, good to hear that the new mustache4dart version does template validation :)
@@ -96,86 +96,78 @@ class HtmlGeneratorInstance implements HtmlOptions { | |||
|
|||
generatePackage(); | |||
|
|||
for (var lib in package.libraries) { | |||
for (var lib in package.libraries.where((l) => l.isDocumented)) { |
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.
Consider putting isDocumented
onto Documentable, and having a utility method that would filter a list of Documentable objects to just the ones that were 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.
(I see a lot of .where((o) => o.isDocumented
below)
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
Ran this through the SDK – just curious. Sooo much better. Love seeing all of random toString and hashCode members gone. Also great to see links to Stream<List> in generics. Very nice. Two things I noticed.
Compare https://api.dartlang.org/be/151323/dart-io/FileSystemEvent-class.html CONSTANTS to
Look at https://api.dartlang.org/be/151323/dart-io/ContentType-class.html I have no clue if you're already aware of these – sorry for the noise if you are. Otherwise, super excited to see this change get in! |
ad24a5a
to
966f85b
Compare
lib/src/warnings.dart
Outdated
@@ -256,12 +256,14 @@ class PackageWarningCounter { | |||
} | |||
|
|||
int get errorCount { | |||
if (_warningCounts.isEmpty) return 0; | |||
return _warningCounts.keys | |||
.map((w) => options.asErrors.contains(w) ? _warningCounts[w] : 0) | |||
.reduce((a, b) => a + b); |
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.
using fold
here would let you avoid the extra case
lib/src/warnings.dart
Outdated
return _warningCounts.keys | ||
.map((w) => options.asErrors.contains(w) ? _warningCounts[w] : 0) | ||
.reduce((a, b) => a + b); | ||
} | ||
|
||
int get warningCount { | ||
if (_warningCounts.isEmpty) return 0; | ||
return _warningCounts.keys | ||
.map((w) => | ||
options.asWarnings.contains(w) && !options.asErrors.contains(w) |
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.
Ditto below – replace reduce
with fold
...at least I think
With the exception of flutter's dartdoc script needing to be updated for new parameters and code cleanup, I've finished making the part 3 overhaul function for Flutter, Angular, and the Dart SDK with head and stable versions of analyzer, as well as addressing the issues @kevmoo mentioned and many more. If it wasn't a breaking change before, it definitely is now. New flags and new naming of anonymous libraries make this a big change. In order to fix the complex packages without losing functionality, several more changes were required.
Code here still needs to be cleaned up, including removing my persistent breakpoints (the "1+1"s), and refactoring package construction so that the tests can use the same code as the mainline dartdoc for dependency recursion. Additional pieces for the planned split in addition to what I already indicated:
|
FWIW, I went through the cases I'd seen. All cleared up. Everything looks so much better. Awesome work! |
@jcollins-g, just to confirm:
Still planned (the-breakup-into-pieces)? |
@devoncarew Yes. There will be a couple more pieces now, sadly, but that is still planned. |
Oh, and for those perusing the code, there's been an additional change here that I was trying to avoid but it was just getting too hard to deal with the cut-and-pastiness of Dartdoc. (Not anyone's fault -- this is what happens when a small tool grows without enough focused time on updating the design to match). I've begun selectively factoring out common sections of code and interfaces into mixins and abstract classes, hopefully in a way that makes some sense. There's now a Canonicalization class for adding Dartdoc canonicalization support, a Privacy class for elements that support isPublic and its friends, a TypeParameters class for elements with type parameters, and so on. This hasn't yet been addressed systematically because I was really trying to just fix one bug here and I'm only factoring out code that I'm touching. But hopefully I will have time to follow up and address the larger structural changes Dartdoc needs. |
🎉 Yay for maintainability! |
9245296
to
835570a
Compare
Starting the breakout now, first piece will be some of the separable warnings changes. |
89c7834
to
ff8af5f
Compare
ff8af5f
to
a6fad37
Compare
e44655e
to
b16f863
Compare
I've managed to break out a few pieces, but disentangling changes is starting to become difficult. It's getting very hard to identify non-mutually-dependent pieces of any size. A few things I thought might be separable, like elements of the private/public distinction, can't be extracted without dragging most or all over the overhaul along and still have dartdoc pass tests and generate valid docs. So, we're going to try reviewing this as it is now. Open for comments! |
df7c56a
to
971153c
Compare
import 'package:analyzer/source/sdk_ext.dart'; | ||
import 'package:analyzer/src/context/builder.dart'; | ||
import 'package:analyzer/src/dart/sdk/sdk.dart'; | ||
import 'package:analyzer/analyzer.dart'; |
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.
That's convenient :)
.where((_Error error) => error.isError) | ||
.toList() | ||
..sort(); | ||
// TODO(jcollins-g): Why does the SDK have analysis errors? Annotations |
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.
Perhaps also track as an issue?
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, and issue added to relevant TODOs.
lib/src/element_type.dart
Outdated
@@ -58,7 +71,10 @@ class ElementType { | |||
return _linkedName; | |||
} | |||
|
|||
String get name => _type.name; | |||
String get name { | |||
if (_type.name == null) return _type.element.name; |
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.
or, return _type.name ?? _type.element.name;
?
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.
or, if we're going to get fancy: String get name => _type.name ?? _type.element.name;
Done. :-)
Accessor(PropertyAccessorElement element, Library library) | ||
: super(element, library); | ||
Accessor( | ||
PropertyAccessorElement element, Library library, Member originalMember) |
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 see some subclasses pass null
in for originalMember
; perhaps make it an [optional]
param?
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.
dart-lang/sdk#15101 makes this very tricky. For now, I prefer the simpler approach of passing nulls rather than the suggested workaround, as it is easier to understand at a glance what the code is doing. Added a TODO.
lib/src/model.dart
Outdated
@@ -2278,7 +2510,12 @@ abstract class ModelElement extends Nameable | |||
// WARNING: putting anything into the body of this seems | |||
// to lead to stack overflows. Need to make a registry of ModelElements | |||
// somehow. | |||
ModelElement(this._element, this._library); | |||
ModelElement(this._element, this._library, this._originalMember) {} |
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.
ditto re: possibly making _originalMember
optional
Iterable<TopLevelVariable> get publicConstants => filterNonPublic(constants); | ||
|
||
String _dirName; | ||
String get dirName { |
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.
Thinking about a pattern for this; not sure this helps, but here's one idea:
String get dirName {
return _dirName ?? (_dirName = () {
return ... ; // init code...
}());
}
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.
Yeah, not sure I like that one -- it is far more complex than the original even if it does save us a bit of vertical space. But let's keep thinking on it!
@@ -4548,3 +4864,313 @@ class TypeParameter extends ModelElement { | |||
@override | |||
String toString() => element.name; | |||
} | |||
|
|||
/// Everything you need to instantiate a Package object for documenting. | |||
class PackageBuilder { |
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, this, class Canonicalization
, class Privacy
- I think the modeling improvements here will really help.
AnalysisContext get context { | ||
if (_context == null) { | ||
// TODO(jcollins-g): fix this so it actually obeys analyzer options files. | ||
var options = new AnalysisOptionsImpl()..enableAssertInitializer = 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.
@bwilkerson - Janice has changed dartdoc so that it only creates an analysis context in one place now. We should look into unifying with how the analysis server creates contexts - we have several outstanding issues as dartdoc doesn't pick up the analysis options settings from projects.
[], | ||
[], | ||
true, | ||
withAutoIncludedDependencies) |
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.
a trailing comma here (and some other places with less than ideal formatting) may make dartfmt format this better
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 find that trailing commas can make things this split lines dartfmt better)
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.
Apparently not in this case -- the addition of the method call on the end seems to make this extra-ugly.
Package bootBasicPackage(
String dirPath, List<String> excludes, bool withAutoIncludedDependencies) {
Directory dir = new Directory(dirPath);
return new PackageBuilder(
dir,
excludes,
[],
sdkDir,
new PackageMeta.fromDir(new Directory(dirPath)),
[],
[],
true,
withAutoIncludedDependencies,
)
.buildPackage();
}
Disabling dartdoc's flutter travis for now, since they need to pass different parameters to dartdoc for the new version to work. I'm checking Flutter manually for now. |
Well done, @jcollins-g !!! |
Going to split this out and clean up some of the architectural duct tape here, but creating a PR for reference so @devoncarew and @keertip can see where this is going.
Investigating #1512 resulted in the detection of a regression in #1514, related to the generic type support recently added in #1506 and related PRs. It turns out this is badly broken -- as indicated in #1514 there are some highly visible docs that have confusing types listed since it's normal for different classes type parameters to be
T
.Fixing this pulled on some threads related once again to canonicalization introduced in #1319, with refinements in #1368 and #1390. In order to resolve types correctly, dartdoc's ElementType class has to be instantiated properly, with the right ModelElement and type. To do that, ModelElements have to keep track of the original Member objects that contain type resolution information from the analyzer. And finally, in order to handle referring to elements defined in non-public libraries but reexported elsewhere, we need to have a better handle on what is public vs. non-public, and canonical vs. not-canonical.
The original pre-canonicalization dartdoc documented everything it saw if it was public, and didn't document it if it wasn't public. This made sense since dartdoc didn't try to dedupe as requested in issue #1090, so resolved types could always be displayed. Dartdoc also didn't need to distinguish between Member and Element objects and always used them the same, because issues related to generic types hadn't yet revealed problems like dart-lang/sdk#29600.
However, after canonicalization, there were various hacks that tried to keep type resolution mostly functional, though resulting in some inconsistent behavior noted in #1512. Still, until we added support for anonymous functions & working generic types, these hacks were good enough. But the whole mess finally came to a head there and it became impossible to fix #1514 without either breaking the function support or reworking the base data structures to include more information, including information about non-public ModelElements contained in classes, libraries, etc.
Adding non-public items meant fixing the private/public distinction inside ModelElements. This now results in a new property, isDocumented, and new hasFoo / allFoo equivalents explicitly filtering for public items if needed. (hasPublicFoo, allPublicFoo) with the default being that all elements are included. Fixing the templates for that was virtually impossible with the old version of mustache4dart which silently failed, but the new version obeys the "fail on missing" flag so I upgraded that and then promptly discovered a pile of existing template bugs as well, fixing those.
Now that all objects are included so that type resolution works and the isDocumented call checks canonicalization, warnings became more likely to happen on non-documented elements because we traverse them now. So introduced some infinite-recursion prevention in the warning system and added isDocumented checks for a couple of the non-canonicalization-related warnings typically generated by non-public elements. This results in a net win, hiding many warnings we had that were nonsensical from before this change (partial fix for #1412) as well as squelching new warnings generated by the type resolution fixes.
The planned breakout of this change will be to submit the pieces in the following order if I can:
Disentangling them along these lines will take a bit but should make it easier to review.