diff --git a/DEPS b/DEPS index e554f97ae55..aa1cc9cef37 100644 --- a/DEPS +++ b/DEPS @@ -149,7 +149,7 @@ vars = { "sync_http_rev": "6666fff944221891182e1f80bf56569338164d72", "tar_rev": "13479f7c2a18f499e840ad470cfcca8c579f6909", "test_rev": "14f99ecdcb74778654d936ce26c70798a3b6649f", - "tools_rev": "6a7dd15748e63db7d41cfee8294c54636b668f41", + "tools_rev": "338a2c8380059afb250a1d0c26555e4da24c6ccc", "vector_math_rev": "7bf60fb95e0fbbd7648944071de9ab5e32ce7387", "web_rev": "428cc812ac022c995abfd2b74e3903610f1360fd", "webdev_rev": "f9a56607fac5ad0c979d2647cf11d3e3be993bf6", diff --git a/pkg/analyzer_plugin/api.txt b/pkg/analyzer_plugin/api.txt index fcc7d118cfb..b4b2024b84a 100644 --- a/pkg/analyzer_plugin/api.txt +++ b/pkg/analyzer_plugin/api.txt @@ -206,6 +206,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: INFO (static getter: AnalysisErrorSeverity) WARNING (static getter: AnalysisErrorSeverity) values (static getter: List) + fromJson (constructor: AnalysisErrorSeverity Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) AnalysisErrorType (enum): @@ -218,6 +219,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: SYNTACTIC_ERROR (static getter: AnalysisErrorType) TODO (static getter: AnalysisErrorType) values (static getter: List) + fromJson (constructor: AnalysisErrorType Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) AssistDescription (class extends Object implements HasToJson): @@ -311,6 +313,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: PACKAGE_NAME (static getter: CompletionSuggestionKind) PARAMETER (static getter: CompletionSuggestionKind) values (static getter: List) + fromJson (constructor: CompletionSuggestionKind Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) DiagnosticMessage@1 (class extends Object implements HasToJson): @@ -393,6 +396,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: UNIT_TEST_TEST (static getter: ElementKind@1) UNKNOWN (static getter: ElementKind@1) values (static getter: List) + fromJson (constructor: ElementKind@1 Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) FixDescription (class extends Object implements HasToJson): @@ -421,6 +425,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: LITERAL (static getter: FoldingKind) PARAMETERS (static getter: FoldingKind) values (static getter: List) + fromJson (constructor: FoldingKind Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) FoldingRegion (class extends Object implements HasToJson): @@ -534,6 +539,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: UNRESOLVED_INSTANCE_MEMBER_REFERENCE (static getter: HighlightRegionType) VALID_STRING_ESCAPE (static getter: HighlightRegionType) values (static getter: List) + fromJson (constructor: HighlightRegionType Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) LinkedEditGroup (class extends Object implements HasToJson): @@ -569,6 +575,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: TYPE (static getter: LinkedEditSuggestionKind) VARIABLE (static getter: LinkedEditSuggestionKind) values (static getter: List) + fromJson (constructor: LinkedEditSuggestionKind Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) Location (class extends Object implements HasToJson): @@ -681,6 +688,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: REQUIRED_NAMED (static getter: ParameterKind) REQUIRED_POSITIONAL (static getter: ParameterKind) values (static getter: List) + fromJson (constructor: ParameterKind Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) PluginDetails (class extends Object implements HasToJson): @@ -735,6 +743,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: MOVE_FILE (static getter: RefactoringKind) RENAME (static getter: RefactoringKind) values (static getter: List) + fromJson (constructor: RefactoringKind Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) RefactoringMethodParameter (class extends Object implements HasToJson): @@ -759,6 +768,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: POSITIONAL (static getter: RefactoringMethodParameterKind) REQUIRED (static getter: RefactoringMethodParameterKind) values (static getter: List) + fromJson (constructor: RefactoringMethodParameterKind Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) RefactoringProblem (class extends Object implements HasToJson): @@ -781,6 +791,7 @@ package:analyzer_plugin/protocol/protocol_common.dart: WARNING (static getter: RefactoringProblemSeverity) values (static getter: List) max (static method: RefactoringProblemSeverity? Function(RefactoringProblemSeverity?, RefactoringProblemSeverity?)) + fromJson (constructor: RefactoringProblemSeverity Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) RemoveContentOverlay (class extends Object implements HasToJson): @@ -1090,6 +1101,7 @@ package:analyzer_plugin/protocol/protocol_generated.dart: OCCURRENCES (static getter: AnalysisService) OUTLINE (static getter: AnalysisService) values (static getter: List) + fromJson (constructor: AnalysisService Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) AnalysisSetAnalysisRootsParams (class extends Object implements RequestParams): @@ -1656,6 +1668,7 @@ package:analyzer_plugin/protocol/protocol_generated.dart: PLUGIN_ERROR (static getter: RequestErrorCode) UNKNOWN_REQUEST (static getter: RequestErrorCode) values (static getter: List) + fromJson (constructor: RequestErrorCode Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) WatchEvent (class extends Object implements HasToJson): @@ -1674,6 +1687,7 @@ package:analyzer_plugin/protocol/protocol_generated.dart: MODIFY (static getter: WatchEventType) REMOVE (static getter: WatchEventType) values (static getter: List) + fromJson (constructor: WatchEventType Function(JsonDecoder, String, Object?, {ClientUriConverter? clientUriConverter})) toJson (method: String Function({ClientUriConverter? clientUriConverter})) toString (method: String Function()) package:analyzer_plugin/src/protocol/protocol_internal.dart: diff --git a/pkg/api_summary/CHANGELOG.md b/pkg/api_summary/CHANGELOG.md deleted file mode 100644 index d4f1a2add78..00000000000 --- a/pkg/api_summary/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.1.0-wip - -- First release. diff --git a/pkg/api_summary/LICENSE b/pkg/api_summary/LICENSE deleted file mode 100644 index 9035a416a31..00000000000 --- a/pkg/api_summary/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2026, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkg/api_summary/OWNERS b/pkg/api_summary/OWNERS deleted file mode 100644 index a6bf39e3fd5..00000000000 --- a/pkg/api_summary/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -file:/tools/OWNERS_DEVELOPER_EXPERIENCE -file:/tools/OWNERS_MODEL -kevmoo@google.com diff --git a/pkg/api_summary/README.md b/pkg/api_summary/README.md deleted file mode 100644 index 06195ae2c79..00000000000 --- a/pkg/api_summary/README.md +++ /dev/null @@ -1 +0,0 @@ -A tool to create a human-readable text summary of the public API of a Dart package. This is useful for auditing API changes with a `diff` tool. diff --git a/pkg/api_summary/analysis_options.yaml b/pkg/api_summary/analysis_options.yaml deleted file mode 100644 index aecda684d9b..00000000000 --- a/pkg/api_summary/analysis_options.yaml +++ /dev/null @@ -1,5 +0,0 @@ -include: package:dart_flutter_team_lints/analysis_options.yaml - -linter: - rules: - - unnecessary_ignore diff --git a/pkg/api_summary/api_summary.txt b/pkg/api_summary/api_summary.txt deleted file mode 100644 index 7f6a593ecaf..00000000000 --- a/pkg/api_summary/api_summary.txt +++ /dev/null @@ -1,25 +0,0 @@ -package:api_summary/api_summary.dart: - summarizePackage (function: Future Function(String, String, {ApiSummaryCustomizer Function()? createCustomizer})) - ApiSummaryCustomizer (class extends Object, base): - new (constructor: ApiSummaryCustomizer Function()) - analysisContext= (setter: AnalysisContext) - packageName= (setter: String) - publicApiLibraries= (setter: Iterable) - topLevelPublicElements (getter: Set) - topLevelPublicElements= (setter: Set) - initialScanComplete (method: Future Function()) - setupComplete (method: Future Function()) - shouldShowDetails (method: bool Function(Element)) -dart:async: - Future (referenced) -dart:core: - Iterable (referenced) - Object (referenced) - Set (referenced) - String (referenced) - bool (referenced) -package:analyzer/dart/analysis/analysis_context.dart: - AnalysisContext (referenced) -package:analyzer/dart/element/element.dart: - Element (referenced) - LibraryElement (referenced) diff --git a/pkg/api_summary/bin/api_summary.dart b/pkg/api_summary/bin/api_summary.dart deleted file mode 100644 index 54002b04517..00000000000 --- a/pkg/api_summary/bin/api_summary.dart +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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:io'; - -import 'package:api_summary/api_summary.dart'; -import 'package:args/args.dart'; -import 'package:path/path.dart' as p; -import 'package:yaml/yaml.dart'; - -Future main(List arguments) async { - try { - final results = parser.parse(arguments); - - if (results.flag('help')) { - print('Usage: api_summary [options]'); - print(parser.usage); - return; - } - - final packagePath = - results.option('package-path') ?? Directory.current.path; - final absolutePath = p.normalize(p.absolute(packagePath)); - final pubspecFile = File(p.join(absolutePath, 'pubspec.yaml')); - - if (!pubspecFile.existsSync()) { - stderr.writeln('Error: No pubspec.yaml found at "$absolutePath".'); - exitCode = 1; - return; - } - - final packageName = _extractPackageName(pubspecFile); - final summary = await summarizePackage(absolutePath, packageName); - stdout.write(summary); - } on FormatException catch (e) { - stderr.writeln('Error: ${e.message}'); - stderr.writeln('\nUsage: api_summary [options]'); - stderr.writeln(parser.usage); - exitCode = 64; - return; - } -} - -final parser = ArgParser() - ..addOption( - 'package-path', - abbr: 'p', - help: - 'The path to the package to summarize. Defaults to the current ' - 'directory.', - ) - ..addFlag( - 'help', - abbr: 'h', - help: 'Print this usage information.', - negatable: false, - ); - -String _extractPackageName(File pubspecFile) { - final content = pubspecFile.readAsStringSync(); - final yaml = loadYaml(content); - if (yaml is! Map) { - throw ArgumentError( - 'Expected pubspec.yaml at ${pubspecFile.path} to be a YAML map.', - ); - } - final name = yaml['name']; - if (name == null) { - throw ArgumentError( - 'Could not find a "name" field in pubspec.yaml at ${pubspecFile.path}.', - ); - } - if (name is! String) { - throw ArgumentError( - 'The "name" field in pubspec.yaml at ${pubspecFile.path} must be a ' - 'String.', - ); - } - return name; -} diff --git a/pkg/api_summary/lib/api_summary.dart b/pkg/api_summary/lib/api_summary.dart deleted file mode 100644 index 1963c6ff876..00000000000 --- a/pkg/api_summary/lib/api_summary.dart +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'package:analyzer/dart/analysis/analysis_context_collection.dart'; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'src/api_description.dart'; -import 'src/api_summary_customizer.dart'; -import 'src/node.dart'; - -export 'src/api_summary_customizer.dart' show ApiSummaryCustomizer; - -/// Creates a human-readable text summary of the public API of a package, in a -/// format suitable for auditing with a `diff` tool. -/// -/// [packagePath] is the path to the directory containing the package's -/// `pubspec.yaml` file. -/// -/// [packageName] is the name of the package. -/// -/// If [createCustomizer] is provided, it will be called to create an instance -/// of [ApiSummaryCustomizer] which will be used to customize the behavior of -/// the tool. -Future summarizePackage( - String packagePath, - String packageName, { - ApiSummaryCustomizer Function()? createCustomizer, -}) async { - var provider = PhysicalResourceProvider.INSTANCE; - var libPath = provider.pathContext.join(packagePath, 'lib'); - var collection = AnalysisContextCollection( - resourceProvider: provider, - includedPaths: [libPath], - ); - // Use `.single` to make sure that `collection` just contains a single - // context. This ensures that `publicApi.build` will see all the files in - // the package. - var context = collection.contexts.single; - var publicApi = ApiDescription( - packageName, - createCustomizer?.call() ?? ApiSummaryCustomizer(), - ); - var stringBuffer = StringBuffer(); - printNodes(stringBuffer, await publicApi.build(context)); - return stringBuffer.toString(); -} diff --git a/pkg/api_summary/lib/src/api_description.dart b/pkg/api_summary/lib/src/api_description.dart deleted file mode 100644 index a436391d3d0..00000000000 --- a/pkg/api_summary/lib/src/api_description.dart +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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:collection'; - -import 'package:analyzer/dart/analysis/analysis_context.dart'; -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/nullability_suffix.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:collection/collection.dart'; - -import 'api_summary_customizer.dart'; -import 'extensions.dart'; -import 'member_sorting.dart'; -import 'node.dart'; -import 'unique_namer.dart'; -import 'uri_sorting.dart'; - -/// Data structure keeping track of a package's API while walking it to produce -/// `api.txt`. -class ApiDescription { - final ApiSummaryCustomizer _customizer; - - final String _pkgName; - - /// Top level elements that have already had their child elements dumped. - /// - /// If an element is seen again in a different library, it will be followed - /// with `(see above)` (rather than having its child elements dumped twice). - final _dumpedTopLevelElements = {}; - - /// Top level elements that have been referenced so far and haven't yet been - /// processed by [build]. - /// - /// This is used to ensure that all elements referred to by the public API - /// (e.g., by being mentioned in the type of an API element) also show up in - /// the output. - final _potentiallyDanglingReferences = Queue(); - - final _uniqueNamer = UniqueNamer(); - - /// Cache of values returned by [_getOrComputeImmediateSubinterfaceMap], to - /// avoid unnecessary recomputation. - final _immediateSubinterfaceCache = - >>{}; - - ApiDescription(this._pkgName, this._customizer); - - /// Builds a list of [Node] objects representing all the libraries that are - /// relevant to the package's public API. - /// - /// This includes libraries that are in the package's public API as well as - /// libraries that are referenced by the package's public API (either by being - /// re-exported as part of the package's public API, or by being used as part - /// of the type of something in the public API). - /// - /// Each library node is pared with a [UriSortKey] indicating the order in - /// which the nodes should be output. - Future> build(AnalysisContext context) async { - _customizer.packageName = _pkgName; - _customizer.analysisContext = context; - await _customizer.setupComplete(); - - // First, find all the libraries comprising the package's public API, and - // all the top level elements they export. - var publicApiLibraries = []; - var topLevelPublicElements = {}; - for (var file in context.contextRoot.analyzedFiles().sorted()) { - if (!file.endsWith('.dart')) continue; - var fileResult = context.currentSession.getFile(file) as FileResult; - var uri = fileResult.uri; - if (fileResult.isLibrary && uri.isInPublicLibOf(_pkgName)) { - var resolvedLibraryResult = - (await context.currentSession.getResolvedLibrary(file)) - as ResolvedLibraryResult; - var library = resolvedLibraryResult.element; - topLevelPublicElements.addAll( - library.exportNamespace.definedNames2.values, - ); - publicApiLibraries.add(library); - } - } - _customizer.publicApiLibraries = publicApiLibraries; - _customizer.topLevelPublicElements = topLevelPublicElements; - await _customizer.initialScanComplete(); - - // Then, dump all the libraries in the package's public API. - var nodes = >{}; - for (var library in publicApiLibraries) { - var node = nodes[library.uri] = Node(); - _dumpLibrary(library, node); - } - - // Finally, dump anything referenced by those public libraries. - while (_potentiallyDanglingReferences.isNotEmpty) { - var element = _potentiallyDanglingReferences.removeFirst(); - if (!_dumpedTopLevelElements.add(element)) continue; - var containingLibraryUri = element.library!.uri; - var childNode = Node() - ..text.add(_uniqueNamer.name(element)); - _dumpElement(element, childNode); - (nodes[containingLibraryUri] ??= Node() - ..text.add('$containingLibraryUri:')) - .childNodes - .add((MemberSortKey(element), childNode)); - } - return [ - for (var entry in nodes.entries) - (UriSortKey(entry.key, _pkgName), entry.value), - ]; - } - - /// Creates a list of objects which, when their string representations are - /// concatenated, describes [type]. - /// - /// The reason we use this method rather than [DartType.toString] is to make - /// sure that (a) every element mentioned by the type is added to - /// [_potentiallyDanglingReferences], and (b) if an ambiguous name is used, - /// the ambiguity will be taken care of by [_uniqueNamer]. - List _describeType(DartType type) { - var suffix = switch (type.nullabilitySuffix) { - NullabilitySuffix.none => '', - NullabilitySuffix.star => '*', - NullabilitySuffix.question => '?', - }; - switch (type) { - case DynamicType(): - return ['dynamic']; - case FunctionType( - :var returnType, - :var typeParameters, - :var formalParameters, - ): - var params = >[]; - var optionalParams = >[]; - var namedParams = >{}; - for (var formalParameter in formalParameters) { - if (formalParameter.isNamed) { - namedParams[formalParameter.name!] = [ - if (formalParameter.isDeprecated) 'deprecated ', - if (formalParameter.isRequired) 'required ', - ..._describeType(formalParameter.type), - ]; - } else if (formalParameter.isOptional) { - optionalParams.add([ - if (formalParameter.isDeprecated) 'deprecated ', - ..._describeType(formalParameter.type), - ]); - } else { - params.add([ - if (formalParameter.isDeprecated) 'deprecated ', - ..._describeType(formalParameter.type), - ]); - } - } - if (optionalParams.isNotEmpty) { - params.add(optionalParams.separatedBy(prefix: '[', suffix: ']')); - } - if (namedParams.isNotEmpty) { - params.add( - namedParams.entries - .sortedBy((e) => e.key) - .map((e) => [...e.value, ' ${e.key}']) - .separatedBy(prefix: '{', suffix: '}'), - ); - } - return [ - ..._describeType(returnType), - ' Function', - if (typeParameters.isNotEmpty) - ...typeParameters - .map(_describeTypeParameter) - .separatedBy(prefix: '<', suffix: '>'), - '(', - ...params.separatedBy(), - ')', - suffix, - ]; - case InterfaceType(:var element, :var typeArguments): - _potentiallyDanglingReferences.addLast(element); - return [ - _uniqueNamer.name(element), - if (typeArguments.isNotEmpty) - ...typeArguments - .map(_describeType) - .separatedBy(prefix: '<', suffix: '>'), - suffix, - ]; - case RecordType(:var positionalFields, :var namedFields): - if (positionalFields.length == 1 && namedFields.isEmpty) { - return [ - '(', - ..._describeType(positionalFields[0].type), - ',)', - suffix, - ]; - } - return [ - ...[ - for (var positionalField in positionalFields) - _describeType(positionalField.type), - if (namedFields.isNotEmpty) - namedFields - .sortedBy((f) => f.name) - .map((f) => [..._describeType(f.type), ' ', f.name]) - .separatedBy(prefix: '{', suffix: '}'), - ].separatedBy(prefix: '(', suffix: ')'), - suffix, - ]; - case TypeParameterType(:var element): - return [element.name!, suffix]; - case VoidType(): - return ['void']; - case dynamic(:var runtimeType): - throw UnimplementedError('Unexpected type: $runtimeType'); - } - } - - /// Creates a list of objects which, when their string representations are - /// concatenated, describes [typeParameter]. - List _describeTypeParameter(TypeParameterElement typeParameter) { - return [ - typeParameter.name!, - if (typeParameter.bound case var bound?) ...[ - ' extends ', - ..._describeType(bound), - ], - ]; - } - - /// Appends information to [node] describing [element]. - void _dumpElement(Element element, Node node) { - var enclosingElement = element.enclosingElement; - if (enclosingElement is LibraryElement && - !_customizer.shouldShowDetails(element)) { - if (!enclosingElement.uri.isIn(_pkgName)) { - node.text.add(' (referenced)'); - } else { - node.text.add(' (non-public)'); - } - return; - } - var parentheticals = >[]; - switch (element) { - case TypeAliasElement(:var aliasedType, :var typeParameters): - var description = ['type alias']; - if (typeParameters.isNotEmpty) { - description.addAll( - typeParameters - .map(_describeTypeParameter) - .separatedBy(prefix: '<', suffix: '>'), - ); - } - description.addAll([' for ', ..._describeType(aliasedType)]); - parentheticals.add(description); - case InstanceElement(): - switch (element) { - case InterfaceElement( - :var typeParameters, - :var supertype, - :var mixins, - :var interfaces, - ): - var instanceDescription = [ - switch (element) { - ClassElement() => 'class', - EnumElement() => 'enum', - MixinElement() => 'mixin', - ExtensionTypeElement() => 'extension type', - dynamic(:var runtimeType) => 'TODO: $runtimeType', - }, - ]; - if (typeParameters.isNotEmpty) { - instanceDescription.addAll( - typeParameters - .map(_describeTypeParameter) - .separatedBy(prefix: '<', suffix: '>'), - ); - } - if (element is! EnumElement && supertype != null) { - instanceDescription.addAll([ - ' extends ', - ..._describeType(supertype), - ]); - } - if (mixins.isNotEmpty) { - instanceDescription.addAll( - mixins.map(_describeType).separatedBy(prefix: ' with '), - ); - } - if (element is MixinElement && - element.superclassConstraints.isNotEmpty) { - instanceDescription.addAll( - element.superclassConstraints - .map(_describeType) - .separatedBy(prefix: ' on '), - ); - } - if (interfaces.isNotEmpty) { - instanceDescription.addAll( - interfaces - .map(_describeType) - .separatedBy(prefix: ' implements '), - ); - } - parentheticals.add(instanceDescription); - if (element is ClassElement) { - if (element.isSealed) { - var parenthetical = ['sealed']; - parentheticals.add(parenthetical); - if (_getOrComputeImmediateSubinterfaceMap( - element.library, - )[element] - case var subinterfaces?) { - parenthetical.add(' (immediate subtypes: '); - // Note: it's tempting to just do - // `subinterfaces.map(_uniqueNamer.name).join(', ')`, but that - // won't work, because the names returned by - // `UniqueName.toString()` aren't finalized until we've - // visited the entire API and seen if there are class names - // that need to be disambiguated. So we accumulate the - // `UniqueName` objects into the `parenthetical` list and rely - // on `printNodes` converting everything to a string when the - // final API description is being output. - var commaNeeded = false; - for (var subinterface in subinterfaces) { - if (commaNeeded) { - parenthetical.add(', '); - } else { - commaNeeded = true; - } - parenthetical.add(_uniqueNamer.name(subinterface)); - } - parenthetical.add(')'); - } - } else { - if (element.isAbstract) { - parentheticals.add(['abstract']); - } - if (element.isBase) { - parentheticals.add(['base']); - } - if (element.isMixinClass) { - parentheticals.add(['mixin']); - } - if (element.isInterface) { - parentheticals.add(['interface']); - } - if (element.isFinal) { - parentheticals.add(['final']); - } - } - } else if (element is MixinElement) { - if (element.isBase) { - parentheticals.add(['base']); - } - } - case ExtensionElement(:var extendedType): - parentheticals.add([ - 'extension on ', - ..._describeType(extendedType), - ]); - case dynamic(:var runtimeType): - throw UnimplementedError('Unexpected element: $runtimeType'); - } - for (var member in element.children.sortedBy((m) => m.name ?? '')) { - if (member.name case var name? when name.startsWith('_')) { - // Ignore private members - continue; - } - if (member is FieldElement) { - // Ignore fields; we care about the getters and setters they induce. - continue; - } - if (member is ConstructorElement && - element is ClassElement && - element.isAbstract && - (element.isFinal || element.isInterface || element.isSealed)) { - // The class can't be constructed from outside of the library that - // declares it, so its constructors aren't part of the public API. - continue; - } - if (member is ConstructorElement && element is EnumElement) { - // Enum constructors can't be called from outside the enum itself, - // so they aren't part of the public API. - continue; - } - var childNode = Node(); - childNode.text.add(member.apiName); - _dumpElement(member, childNode); - node.childNodes.add((MemberSortKey(member), childNode)); - } - case TopLevelFunctionElement(:var type): - parentheticals.add(['function: ', ..._describeType(type)]); - case ExecutableElement(:var isStatic): - var maybeStatic = isStatic ? 'static ' : ''; - switch (element) { - case GetterElement(:var type): - parentheticals.add([ - '${maybeStatic}getter: ', - ..._describeType(type.returnType), - ]); - case SetterElement(:var type): - parentheticals.add([ - '${maybeStatic}setter: ', - ..._describeType(type.formalParameters.single.type), - ]); - case MethodElement(:var type): - parentheticals.add([ - '${maybeStatic}method: ', - ..._describeType(type), - ]); - case ConstructorElement(:var type): - parentheticals.add(['constructor: ', ..._describeType(type)]); - case dynamic(:var runtimeType): - throw UnimplementedError('Unexpected element: $runtimeType'); - } - case dynamic(:var runtimeType): - throw UnimplementedError('Unexpected element: $runtimeType'); - } - - // For synthetic elements such as getters/setters induced by top level - // variables and fields, annotations can be found on the corresponding - // non-synthetic element. - var nonSyntheticElement = element.nonSynthetic; - if (nonSyntheticElement.metadata.hasDeprecated) { - parentheticals.add(['deprecated']); - } - if (nonSyntheticElement.metadata.hasExperimental) { - parentheticals.add(['experimental']); - } - - if (parentheticals.isNotEmpty) { - node.text.addAll(parentheticals.separatedBy(prefix: ' (', suffix: ')')); - } - if (node.childNodes.isNotEmpty) { - node.text.add(':'); - } - } - - /// Appends information to [node] describing [library]. - void _dumpLibrary(LibraryElement library, Node node) { - var uri = library.uri; - node.text.addAll([uri, ':']); - var definedNames = library.exportNamespace.definedNames2; - for (var key in definedNames.keys.sorted()) { - var element = definedNames[key]!; - var childNode = Node() - ..text.add(_uniqueNamer.name(element)); - if (!_dumpedTopLevelElements.add(element)) { - childNode.text.add(' (see above)'); - } else { - _dumpElement(element, childNode); - } - node.childNodes.add((MemberSortKey(element), childNode)); - } - } - - /// Returns a map from each sealed class in [library] to the set of its - /// immediate sub-interfaces. - /// - /// If this method has been called before with the same [library], a cached - /// map is returned from [_immediateSubinterfaceCache]. Otherwise a fresh map - /// is computed. - Map> - _getOrComputeImmediateSubinterfaceMap(LibraryElement library) { - if (_immediateSubinterfaceCache[library] case var m?) return m; - var result = >{}; - for (var interface in [ - ...library.classes, - ...library.mixins, - ...library.enums, - ...library.extensionTypes, - ]..sortBy((e) => e.name!)) { - for (var superinterface in [ - interface.supertype, - ...interface.interfaces, - ...interface.mixins, - if (interface is MixinElement) ...interface.superclassConstraints, - ]) { - if (superinterface == null) continue; - var superinterfaceElement = superinterface.element; - if (superinterfaceElement is ClassElement && - superinterfaceElement.isSealed) { - (result[superinterfaceElement] ??= {}).add(interface); - } - } - } - _immediateSubinterfaceCache[library] = result; - return result; - } -} diff --git a/pkg/api_summary/lib/src/api_summary_customizer.dart b/pkg/api_summary/lib/src/api_summary_customizer.dart deleted file mode 100644 index 34c68451487..00000000000 --- a/pkg/api_summary/lib/src/api_summary_customizer.dart +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'package:analyzer/dart/analysis/analysis_context.dart'; -import 'package:analyzer/dart/element/element.dart'; - -/// Clients of the API summary tool may extend this class to customize its -/// behavior. -/// -/// Clients should not *implement* this class, however, because additional -/// methods may be added in the future. -base class ApiSummaryCustomizer { - /// The top level elements exported by the libraries in [publicApiLibraries]. - /// - /// This value is set by the tool before [initialScanComplete] is called. - late final Set topLevelPublicElements; - - /// The analysis context for the package being summarized. - /// - /// This value is set by the tool before [setupComplete] is called. - set analysisContext(AnalysisContext analysisContext) {} - - /// The name of the package whose API is being summarized. - /// - /// This value is set by the tool before [setupComplete] is called. - set packageName(String value) {} - - /// The libraries that comprise the package's public API. - /// - /// This value is set by the tool before [initialScanComplete] is called. - set publicApiLibraries(Iterable value) {} - - /// Called after [publicApiLibraries] and [topLevelPublicElements] have been - /// set, but before any analysis has been performed. - /// - /// Further analysis won't be performed until the returned Future completes. - Future initialScanComplete() async {} - - /// Called after [packageName] and [analysisContext] have been set, but before - /// any analysis has been performed. - /// - /// The initial scan won't be performed until the returned Future completes. - Future setupComplete() async {} - - /// Called after [initialScanComplete] to determine if details about an - /// element should be shown in the API summary. - /// - /// The default behavior is to show details about elements in - /// [topLevelPublicElements]. - bool shouldShowDetails(Element element) => - topLevelPublicElements.contains(element); -} diff --git a/pkg/api_summary/lib/src/extensions.dart b/pkg/api_summary/lib/src/extensions.dart deleted file mode 100644 index 4b663c3f1ab..00000000000 --- a/pkg/api_summary/lib/src/extensions.dart +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'package:analyzer/dart/element/element.dart'; - -extension ElementExtension on Element { - /// Returns the appropriate name for describing the element in `api.txt`. - /// - /// The name is the same as [name], but with `=` appended for setters. - String get apiName { - var apiName = name!; - if (this is SetterElement) { - apiName += '='; - } - return apiName; - } -} - -extension FormalParameterElementExtension on FormalParameterElement { - bool get isDeprecated { - // TODO(paulberry): add this to the analyzer public API - return metadata.hasDeprecated; - } -} - -extension IterableIterableExtension on Iterable> { - /// Forms a list containing [prefix], followed by the elements of `this` - /// (separated by [separator]), followed by [suffix]. - /// - /// Each element of `this` is also an iterable; these elements are added to - /// the resulting list using `.addAll`, so one level of iterable nesting is - /// removed. - List separatedBy({ - String separator = ', ', - String prefix = '', - String suffix = '', - }) { - var result = [prefix]; - var first = true; - for (var item in this) { - if (first) { - first = false; - } else { - result.add(separator); - } - result.addAll(item); - } - result.add(suffix); - return result; - } -} - -extension StringExtension on String { - bool get isPublic => !startsWith('_'); -} - -extension UriExtension on Uri { - bool isIn(String packageName) => - scheme == 'package' && - pathSegments.isNotEmpty && - pathSegments[0] == packageName; - - bool isInPublicLibOf(String packageName) => - scheme == 'package' && - pathSegments.length > 1 && - pathSegments[0] == packageName && - pathSegments[1] != 'src'; -} diff --git a/pkg/api_summary/lib/src/member_sorting.dart b/pkg/api_summary/lib/src/member_sorting.dart deleted file mode 100644 index 7d74a9e3e64..00000000000 --- a/pkg/api_summary/lib/src/member_sorting.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'package:analyzer/dart/element/element.dart'; - -/// Element categorization used by [MemberSortKey]. -enum MemberCategory { - constructor, - propertyAccessor, - topLevelFunctionOrMethod, - interface, - extension, - typeAlias, -} - -/// Sort key used to sort elements in the output. -class MemberSortKey implements Comparable { - final bool _isInstanceMember; - final MemberCategory _category; - final String _name; - final bool _isSetter; - - MemberSortKey(Element element) - : _isInstanceMember = _computeIsInstanceMember(element), - _category = _computeCategory(element), - _name = element.displayName, - _isSetter = element is SetterElement; - - @override - int compareTo(MemberSortKey other) { - if ((_isInstanceMember ? 1 : 0).compareTo(other._isInstanceMember ? 1 : 0) - case var value when value != 0) { - return value; - } - if (_category.index.compareTo(other._category.index) case var value - when value != 0) { - return value; - } - if (_name.compareTo(other._name) case var value when value != 0) { - return value; - } - return (_isSetter ? 1 : 0).compareTo(other._isSetter ? 1 : 0); - } - - static MemberCategory _computeCategory(Element element) => switch (element) { - ConstructorElement() => MemberCategory.constructor, - PropertyAccessorElement() => MemberCategory.propertyAccessor, - TopLevelFunctionElement() => MemberCategory.topLevelFunctionOrMethod, - MethodElement() => MemberCategory.topLevelFunctionOrMethod, - InterfaceElement() => MemberCategory.interface, - ExtensionElement() => MemberCategory.extension, - TypeAliasElement() => MemberCategory.typeAlias, - dynamic(:var runtimeType) => throw UnimplementedError( - 'Unexpected element: $runtimeType', - ), - }; - - static bool _computeIsInstanceMember(Element element) => - element.enclosingElement is InstanceElement && - switch (element) { - ExecutableElement(:var isStatic) => !isStatic, - dynamic(:var runtimeType) => throw UnimplementedError( - 'Unexpected element: $runtimeType', - ), - }; -} diff --git a/pkg/api_summary/lib/src/node.dart b/pkg/api_summary/lib/src/node.dart deleted file mode 100644 index 02f4bf46e68..00000000000 --- a/pkg/api_summary/lib/src/node.dart +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -/// @docImport 'unique_namer.dart'; -library; - -import 'package:collection/collection.dart'; - -/// Outputs the contents of [nodes] to [sink], prepending [prefix] to every -/// line. -void printNodes>( - StringSink sink, - List<(SortKey, Node)> nodes, { - String prefix = '', -}) { - for (var entry in nodes.sortedBy((n) => n.$1)) { - var node = entry.$2; - sink.writeln('$prefix${node.text.join()}'); - node.printChildren(sink, prefix: '$prefix '); - } -} - -/// A node to be printed to the output. -class Node> { - /// A list of objects which, when their string representations are - /// concatenated, is the text that should be displayed on the first line of - /// the node. - /// - /// The reason this is a list rather than a single string is to allow elements - /// of the list to be [UniqueName] objects, which may acquire a disambiguation - /// suffix at a later time. - final text = []; - - /// A list of child nodes, paired with a sort key indicating the order in - /// which they should be output. - final childNodes = <(ChildSortKey, Node)>[]; - - /// Outputs [childNodes], prepending [prefix] to every line. - void printChildren(StringSink sink, {required String prefix}) { - printNodes(sink, childNodes, prefix: prefix); - } -} diff --git a/pkg/api_summary/lib/src/unique_namer.dart b/pkg/api_summary/lib/src/unique_namer.dart deleted file mode 100644 index d9bbb1bd020..00000000000 --- a/pkg/api_summary/lib/src/unique_namer.dart +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'package:analyzer/dart/element/element.dart'; -import 'extensions.dart'; - -/// Object that will have a unique string representation within the context of a -/// given [UniqueNamer] instance. -/// -/// If two or more [UniqueName] objects are constructed with reference to the -/// same [UniqueNamer], and they have the same [_nameHint], then all such -/// objects' [toString] methods will append a unique suffix of the form -/// `@INTEGER`, so that the resulting strings are unique. -class UniqueName { - /// The name that will be returned by [toString] if no disambiguation is - /// needed. - final String _nameHint; - - /// If not `Null`, the integer that [toString] will use to disambiguate this - /// [UniqueName] from other ones with the same [_nameHint]. - int? _disambiguator; - - UniqueName(UniqueNamer uniqueNamer, this._nameHint) - // The uniqueness guarantee depends on `_nameHint` not containing an `@`. - : assert(!_nameHint.contains('@')) { - var conflicts = uniqueNamer._conflicts[_nameHint] ??= []; - if (conflicts.length == 1) { - conflicts[0]._disambiguator = 1; - } - conflicts.add(this); - if (conflicts.length > 1) { - _disambiguator = conflicts.length; - } - } - - @override - String toString() => [ - _nameHint, - if (_disambiguator case var disambiguator?) '@$disambiguator', - ].join(); -} - -/// Manager of unique names for elements. -class UniqueNamer { - final _names = {}; - final _conflicts = >{}; - - /// Returns a [UniqueName] object whose [toString] method will produce a - /// unique name for [element]. - UniqueName name(Element element) => - _names[element] ??= UniqueName(this, element.apiName); -} diff --git a/pkg/api_summary/lib/src/uri_sorting.dart b/pkg/api_summary/lib/src/uri_sorting.dart deleted file mode 100644 index 0ba179492a9..00000000000 --- a/pkg/api_summary/lib/src/uri_sorting.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'extensions.dart'; - -/// URI categorization used by [UriSortKey]. -enum UriCategory { inPackage, notInPackage } - -/// Sort key used to sort libraries in the output. -/// -/// Libraries in the specified package will be output first (sorted by URI), -/// followed by libraries not in the package. -class UriSortKey implements Comparable { - final UriCategory _category; - final String _uriString; - - UriSortKey(Uri uri, String pkgName) - : _category = uri.isIn(pkgName) - ? UriCategory.inPackage - : UriCategory.notInPackage, - _uriString = uri.toString(); - - @override - int compareTo(UriSortKey other) { - if (_category.index.compareTo(other._category.index) case var value - when value != 0) { - return value; - } - return _uriString.compareTo(other._uriString); - } -} diff --git a/pkg/api_summary/pubspec.yaml b/pkg/api_summary/pubspec.yaml deleted file mode 100644 index 5a65c1d3052..00000000000 --- a/pkg/api_summary/pubspec.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: api_summary -version: 0.1.0-wip -description: Creates an API summary for a package. -publish_to: none - -environment: - sdk: '^3.12.0-0' - -resolution: workspace - -# Use 'any' constraints here; we get our versions from the DEPS file. -dependencies: - analyzer: any - args: any - collection: any - path: any - yaml: any - -# Use 'any' constraints here; we get our versions from the DEPS file. -dev_dependencies: - analyzer_testing: any - dart_flutter_team_lints: any - test: any - test_reflective_loader: any diff --git a/pkg/api_summary/test/api_description_test.dart b/pkg/api_summary/test/api_description_test.dart deleted file mode 100644 index 36b7720dc22..00000000000 --- a/pkg/api_summary/test/api_description_test.dart +++ /dev/null @@ -1,793 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: non_constant_identifier_names - -import 'dart:core'; - -import 'package:analyzer/dart/analysis/analysis_context.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:api_summary/src/api_description.dart'; -import 'package:api_summary/src/api_summary_customizer.dart'; -import 'package:api_summary/src/node.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -import 'test_utils.dart'; - -void main() { - defineReflectiveSuite(() { - defineReflectiveTests(ApiDescriptionTest); - }); -} - -@reflectiveTest -class ApiDescriptionTest extends ApiSummaryTest { - @override - bool get addMetaPackageDep => true; - - @override - void setUp() { - newPackage('foo').addFile('lib/foo.dart', r''' -foo() {} -class Foo {} -'''); - super.setUp(); - } - - Future test_class_mixins() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -mixin M1 {} -mixin M2 {} -class C1 extends Object with M1 {} -class C2 extends Object with M2 implements M1 {} -''', - }); - expect(summary, ''' -package:test/file.dart: - C1 (class extends Object with M1): - new (constructor: C1 Function()) - C2 (class extends Object with M2 implements M1): - new (constructor: C2 Function()) - M1 (mixin on Object) - M2 (mixin on Object) -dart:core: - Object (referenced) -'''); - } - - Future test_class_modifiers() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class C {} -abstract class A {} -base class B {} -base mixin class BM {} -mixin class M {} -interface class I {} -final class F {} -abstract base class AB {} -abstract base mixin class ABM {} -abstract interface class AI {} -abstract final class AF {} -abstract mixin class AM {} -''', - }); - expect(summary, ''' -package:test/file.dart: - A (class extends Object, abstract): - new (constructor: A Function()) - AB (class extends Object, abstract, base): - new (constructor: AB Function()) - ABM (class extends Object, abstract, base, mixin): - new (constructor: ABM Function()) - AF (class extends Object, abstract, final) - AI (class extends Object, abstract, interface) - AM (class extends Object, abstract, mixin): - new (constructor: AM Function()) - B (class extends Object, base): - new (constructor: B Function()) - BM (class extends Object, base, mixin): - new (constructor: BM Function()) - C (class extends Object): - new (constructor: C Function()) - F (class extends Object, final): - new (constructor: F Function()) - I (class extends Object, interface): - new (constructor: I Function()) - M (class extends Object, mixin): - new (constructor: M Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_customize_shouldShowDetails() async { - var summary = await _build( - { - '$testPackageLibPath/public.dart': ''' -import 'src/private.dart'; - -void shown1(Shown2 x, Hidden2 y) {} -void hidden1(Shown3 x, Hidden3 y) {} -''', - '$testPackageLibPath/src/private.dart': ''' -class Shown2 {} -class Hidden2 {} -class Shown3 {} -class Hidden3 {} -''', - }, - createCustomizer: () => _ShouldShowDetailsCustomizer( - (e) => e.name!.toLowerCase().contains('shown'), - ), - ); - // Note: Shown2 and Hidden2 are included in the summary because they are - // referenced by shown1. Details are only shown for shown1 and Shown2. - expect(summary, ''' -package:test/public.dart: - hidden1 (non-public) - shown1 (function: void Function(Shown2, Hidden2)) -package:test/src/private.dart: - Hidden2 (non-public) - Shown2 (class extends Object): - new (constructor: Shown2 Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_field_deprecated() async { - // Marking a field as deprecated causes its corresponding getter and setter - // to be marked as deprecated in the summary. - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class C { - @deprecated - int x = 0; -} -''', - }); - expect(summary, ''' -package:test/file.dart: - C (class extends Object): - new (constructor: C Function()) - x (getter: int, deprecated) - x= (setter: int, deprecated) -dart:core: - Object (referenced) - int (referenced) -'''); - } - - Future test_field_experimental() async { - // Marking a field as experimental causes its corresponding getter and - // setter to be marked as experimental in the summary. - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -import 'package:meta/meta.dart'; - -class C { - @experimental - int x = 0; -} -''', - }); - expect(summary, ''' -package:test/file.dart: - C (class extends Object): - new (constructor: C Function()) - x (getter: int, experimental) - x= (setter: int, experimental) -dart:core: - Object (referenced) - int (referenced) -'''); - } - - Future test_member_field() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class C { - int x = 0; -} -''', - }); - // The summary output contains the getters and setters induced by the field, - // not the field itself. - expect(summary, ''' -package:test/file.dart: - C (class extends Object): - new (constructor: C Function()) - x (getter: int) - x= (setter: int) -dart:core: - Object (referenced) - int (referenced) -'''); - } - - Future test_member_getterSetterPair() async { - // This test verifies that even if a getter and a setter have the same name, - // both are included in the summary output. - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class C { - get x => 0; - set x(value) {} -} -''', - }); - expect(summary, ''' -package:test/file.dart: - C (class extends Object): - new (constructor: C Function()) - x (getter: dynamic) - x= (setter: dynamic) -dart:core: - Object (referenced) -'''); - } - - Future test_member_method() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class C { - void f() {} -} -''', - }); - expect(summary, ''' -package:test/file.dart: - C (class extends Object): - new (constructor: C Function()) - f (method: void Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_member_privateName() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class C { - f() { - _f(); - } - _f() {} -} -''', - }); - // The private member _f is not included in the summary output. - expect(summary, ''' -package:test/file.dart: - C (class extends Object): - new (constructor: C Function()) - f (method: dynamic Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_minimallyDescribesReferencedNamesInOtherPackages() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -import 'package:foo/foo.dart'; - -void f(Foo foo) {} -''', - }); - expect(summary, ''' -package:test/file.dart: - f (function: void Function(Foo)) -package:foo/foo.dart: - Foo (referenced) -'''); - } - - Future test_minimallyDescribesReferencedNonPublicNames() async { - var summary = await _build({ - '$testPackageLibPath/public.dart': ''' -import 'src/private.dart'; - -void f(Foo foo) {} -''', - '$testPackageLibPath/src/private.dart': 'class Foo {}', - }); - expect(summary, ''' -package:test/public.dart: - f (function: void Function(Foo)) -package:test/src/private.dart: - Foo (non-public) -'''); - } - - Future test_mixin_modifiers() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -mixin M {} -base mixin BM {} -''', - }); - expect(summary, ''' -package:test/file.dart: - BM (mixin on Object, base) - M (mixin on Object) -dart:core: - Object (referenced) -'''); - } - - Future test_nonConstructibleClass() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -abstract final class C1 {} -abstract interface class C2 {} -sealed class C3 {} -''', - }); - // These classes can't be constructed from outside the library, so their - // constructors aren't included in the summary output. - expect(summary, ''' -package:test/file.dart: - C1 (class extends Object, abstract, final) - C2 (class extends Object, abstract, interface) - C3 (class extends Object, sealed) -dart:core: - Object (referenced) -'''); - } - - Future test_sealedClass() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -sealed class C {} -// Note: immediate subinterfaces will be sorted in summary output -class C2 extends C {} -class C1 extends C {} -''', - }); - expect(summary, ''' -package:test/file.dart: - C (class extends Object, sealed (immediate subtypes: C1, C2)) - C1 (class extends C): - new (constructor: C1 Function()) - C2 (class extends C): - new (constructor: C2 Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_sealedClass_allKindsAndRelationships() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -sealed class S {} -class C1 extends S {} -class C2 implements S {} -mixin M1 on S {} -mixin M2 implements S {} -enum E1 implements S { v } -extension type T(C1 c) implements S {} -''', - }); - expect(summary, ''' -package:test/file.dart: - C1 (class extends S): - new (constructor: C1 Function()) - C2 (class extends Object implements S): - new (constructor: C2 Function()) - E1 (enum implements S): - v (static getter: E1) - values (static getter: List) - M1 (mixin on S) - M2 (mixin on Object implements S) - S (class extends Object, sealed (immediate subtypes: C1, C2, E1, M1, M2, T)) - T (extension type implements S): - new (constructor: T Function(C1)) - c (getter: C1) -dart:core: - List (referenced) - Object (referenced) -'''); - } - - Future test_topLevel_collapsesRedundantElements() async { - // When an element is exported by multiple libraries, it is only described - // once; later references use the text "(see above)". - var summary = await _build({ - '$testPackageLibPath/file1.dart': 'export "file2.dart";', - '$testPackageLibPath/file2.dart': 'class C {}', - '$testPackageLibPath/file3.dart': 'export "file2.dart";', - }); - expect(summary, ''' -package:test/file1.dart: - C (class extends Object): - new (constructor: C Function()) -package:test/file2.dart: - C (see above) -package:test/file3.dart: - C (see above) -dart:core: - Object (referenced) -'''); - } - - Future test_topLevel_disambiguatesNames() async { - // If two libraries declare top level elements with the same name, the names - // are disambiguated so that references are clear. - var summary = await _build({ - '$testPackageLibPath/file1.dart': ''' -class A {} -class B extends A {} -''', - '$testPackageLibPath/file2.dart': ''' -class A {} -class B extends A {} -''', - }); - expect(summary, ''' -package:test/file1.dart: - A@1 (class extends Object): - new (constructor: A@1 Function()) - B@1 (class extends A@1): - new (constructor: B@1 Function()) -package:test/file2.dart: - A@2 (class extends Object): - new (constructor: A@2 Function()) - B@2 (class extends A@2): - new (constructor: B@2 Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_topLevel_extension() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -extension E on int { - void f() {} -} -''', - }); - expect(summary, ''' -package:test/file.dart: - E (extension on int): - f (method: void Function()) -dart:core: - int (referenced) -'''); - } - - Future test_topLevel_filesInSrc() async { - var summary = await _build({ - '$testPackageLibPath/public.dart': 'export "src/private1.dart";', - '$testPackageLibPath/src/private1.dart': 'f() {}', - '$testPackageLibPath/src/private2.dart': 'g() {}', - }); - // `f` is considered part of the public API because it is exported by - // `public.dart`. - expect(summary, ''' -package:test/public.dart: - f (function: dynamic Function()) -'''); - } - - Future test_topLevel_getterSetterPair() async { - // This test verifies that even if getter and a setter have the same name, - // both are included in the summary output. - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -get x => 0; -set x(value) {} -''', - }); - expect(summary, ''' -package:test/file.dart: - x (static getter: dynamic) - x= (static setter: dynamic) -'''); - } - - Future test_topLevel_interfaceType() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -class I {} -class B {} -class C extends B implements I {} -enum E implements I { e1 } -mixin M on B implements I {} -extension type T(int i) {} -''', - }); - expect(summary, ''' -package:test/file.dart: - B (class extends Object): - new (constructor: B Function()) - C (class extends B implements I): - new (constructor: C Function()) - E (enum implements I): - e1 (static getter: E) - values (static getter: List) - I (class extends Object): - new (constructor: I Function()) - M (mixin on B implements I) - T (extension type): - new (constructor: T Function(int)) - i (getter: int) -dart:core: - List (referenced) - Object (referenced) - int (referenced) -'''); - } - - Future test_topLevel_nonDartFile() async { - var summary = await _build({'$testPackageLibPath/file.dar': 'f() {}'}); - expect(summary, ''); - } - - Future test_topLevel_otherPackagePublicApi() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -import 'package:foo/foo.dart'; - -main() { - foo(); -} -''', - }); - expect(summary, ''' -package:test/file.dart: - main (function: dynamic Function()) -'''); - } - - Future test_topLevel_partFile() async { - // Declarations in a part file are considered part of the public API of the - // containing library. - var summary = await _build({ - '$testPackageLibPath/lib.dart': 'part "part.dart";', - '$testPackageLibPath/part.dart': ''' -part of "lib.dart"; - -f() {} -''', - }); - expect(summary, ''' -package:test/lib.dart: - f (function: dynamic Function()) -'''); - } - - Future test_topLevel_privateName() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -f() { - _g(); -} - -_g() {} -''', - }); - // The private member _g is not included in the summary output. - expect(summary, ''' -package:test/file.dart: - f (function: dynamic Function()) -'''); - } - - Future test_topLevel_sorted() async { - // This test just verifies that sorting occurs. See `member_test.dart` for - // tests of the precise nature of the sort order. - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -g() {} -f() {} -get x => 0; -class C {} -''', - }); - expect(summary, ''' -package:test/file.dart: - x (static getter: dynamic) - f (function: dynamic Function()) - g (function: dynamic Function()) - C (class extends Object): - new (constructor: C Function()) -dart:core: - Object (referenced) -'''); - } - - Future test_topLevel_sortsLibrariesByUri() async { - var summary = await _build({ - '$testPackageLibPath/file2.dart': '', - '$testPackageLibPath/file1.dart': '', - '$testPackageLibPath/file3.dart': '', - }); - expect(summary, ''' -package:test/file1.dart: -package:test/file2.dart: -package:test/file3.dart: -'''); - } - - Future test_topLevel_typedef() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -typedef void oldStyleFunctionTypedef(); -typedef void oldStyleFunctionTypedefGeneric(T t); -typedef newStyleFunctionTypedef = void Function(); -typedef newStyleFunctionTypedefGeneric = void Function(T); -typedef nonFunctionTypedef = int; -''', - }); - expect(summary, ''' -package:test/file.dart: - newStyleFunctionTypedef (type alias for void Function()) - newStyleFunctionTypedefGeneric (type alias for void Function(T)) - nonFunctionTypedef (type alias for int) - oldStyleFunctionTypedef (type alias for void Function()) - oldStyleFunctionTypedefGeneric (type alias for void Function(T)) -dart:core: - int (referenced) -'''); - } - - Future test_types() async { - var summary = await _build({ - '$testPackageLibPath/file.dart': ''' -import 'dart:async'; - -// Dynamic type -dynamic get d => 0; - -// Null type -Null get n => null; - -// FutureOr type -FutureOr? get fo => null; - -// Function types -void Function(int requiredPositionalParam, [int? optionalPositionalParam]) - get f1 => throw ''; -void Function({ - // Note: named params will be sorted by name - required int requiredNamedParam, int? optionalNamedParam})? get f2 => null; -void f3(@deprecated int i, [@deprecated int? j]) {} -void f4({@deprecated int? i}) {} -void f5(T t1, T? t2) {} // Also tests type parameter types -void f6(T t) {} - -// Interface types -void f7(Map m1, Map? m2) {} - -// Record types -void f8((int, String) r1, (int, {String s})? r2, - // Note: named record fields will be sorted by name - ({String s, int i}) r3) {} -''', - }); - expect(summary, ''' -package:test/file.dart: - d (static getter: dynamic) - f1 (static getter: void Function(int, [int?])) - f2 (static getter: void Function({int? optionalNamedParam, required int requiredNamedParam})?) - fo (static getter: FutureOr?) - n (static getter: Null) - f3 (function: void Function(deprecated int, [deprecated int?])) - f4 (function: void Function({deprecated int? i})) - f5 (function: void Function(T, T?)) - f6 (function: void Function(T)) - f7 (function: void Function(Map, Map?)) - f8 (function: void Function((int, String), (int, {String s})?, ({int i, String s}))) -dart:async: - FutureOr (referenced) -dart:core: - Map (referenced) - Null (referenced) - String (referenced) - int (referenced) - num (referenced) -'''); - } - - Future _build( - Map files, { - _ValidatingCustomizer Function()? createCustomizer, - }) async { - // Create all the files. - files.forEach(newFile); - - // As a sanity check, make sure there are no errors in any of the files. - for (var file in files.keys) { - if (file.endsWith('.dart')) await assertNoDiagnosticsInFile(file); - } - - // Generate the API description. - var context = contextCollection.contextFor(convertPath(testPackageLibPath)); - var customizer = createCustomizer?.call() ?? _ValidatingCustomizer(); - var apiDescription = ApiDescription('test', customizer); - var stringBuffer = StringBuffer(); - var nodes = await apiDescription.build(context); - expect(customizer.initialScanCompleteCalled, isTrue); - printNodes(stringBuffer, nodes); - return stringBuffer.toString(); - } -} - -final class _ShouldShowDetailsCustomizer extends _ValidatingCustomizer { - final bool Function(Element) _shouldShowDetails; - - _ShouldShowDetailsCustomizer(this._shouldShowDetails); - - @override - bool shouldShowDetails(Element element) { - expect(initialScanCompleteCalled, isTrue); - return _shouldShowDetails(element); - } -} - -base class _ValidatingCustomizer extends ApiSummaryCustomizer { - bool topLevelPublicElementsCalled = false; - bool analysisContextCalled = false; - bool packageNameCalled = false; - bool publicApiLibrariesCalled = false; - bool initialScanCompleteCalled = false; - bool setupCompleteCalled = false; - - @override - set analysisContext(AnalysisContext value) { - expect(analysisContextCalled, isFalse); - analysisContextCalled = true; - super.analysisContext = value; - } - - @override - set packageName(String value) { - expect(packageNameCalled, isFalse); - packageNameCalled = true; - super.packageName = value; - } - - @override - set publicApiLibraries(Iterable value) { - expect(setupCompleteCalled, isTrue); - expect(publicApiLibrariesCalled, isFalse); - publicApiLibrariesCalled = true; - super.publicApiLibraries = value; - } - - @override - set topLevelPublicElements(Set value) { - expect(setupCompleteCalled, isTrue); - expect(topLevelPublicElementsCalled, isFalse); - topLevelPublicElementsCalled = true; - super.topLevelPublicElements = value; - } - - @override - Future initialScanComplete() async { - expect(topLevelPublicElementsCalled, isTrue); - expect(publicApiLibrariesCalled, isTrue); - initialScanCompleteCalled = true; - await super.initialScanComplete(); - } - - @override - Future setupComplete() async { - expect(packageNameCalled, isTrue); - expect(analysisContextCalled, isTrue); - setupCompleteCalled = true; - await super.setupComplete(); - } - - @override - bool shouldShowDetails(Element element) { - expect(initialScanCompleteCalled, isTrue); - return super.shouldShowDetails(element); - } -} diff --git a/pkg/api_summary/test/app_test.dart b/pkg/api_summary/test/app_test.dart deleted file mode 100644 index 2500cc5fa9a..00000000000 --- a/pkg/api_summary/test/app_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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:convert'; -import 'dart:io'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -void main() { - test( - 'api_summary output matches api_summary.txt', - timeout: const Timeout.factor(3), - () async { - final packageDir = _pkgDir(); - - final result = await Process.run(Platform.resolvedExecutable, [ - if (Platform.packageConfig != null) - '--packages=${Platform.packageConfig}', - p.join(packageDir, 'bin', 'api_summary.dart'), - '-p', - packageDir, - ], workingDirectory: packageDir); - - expect( - result.exitCode, - equals(0), - reason: 'CLI run failed with stderr:\n${result.stderr}', - ); - - final goldenFile = File(p.join(packageDir, 'api_summary.txt')); - final expectedOutput = LineSplitter.split( - goldenFile.readAsStringSync(), - ).join('\n'); - final actualOutput = LineSplitter.split( - result.stdout.toString(), - ).join('\n'); - - expect(actualOutput, equals(expectedOutput)); - }, - ); -} - -// Dynamically locate the api_summary package root -String _pkgDir() { - var packageDir = p.normalize(p.absolute(Directory.current.path)); - if (!_isApiSummaryDir(packageDir)) { - // We might be running from the SDK root - final candidate = p.join(packageDir, 'pkg', 'api_summary'); - if (_isApiSummaryDir(candidate)) { - packageDir = candidate; - } - } - - return packageDir; -} - -bool _isApiSummaryDir(String dir) { - final pubspec = File(p.join(dir, 'pubspec.yaml')); - if (!pubspec.existsSync()) return false; - return pubspec.readAsStringSync().contains('name: api_summary'); -} diff --git a/pkg/api_summary/test/extensions_test.dart b/pkg/api_summary/test/extensions_test.dart deleted file mode 100644 index eb76ad90326..00000000000 --- a/pkg/api_summary/test/extensions_test.dart +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: non_constant_identifier_names - -import 'package:api_summary/src/extensions.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -import 'test_utils.dart'; - -void main() { - defineReflectiveSuite(() { - defineReflectiveTests(ExtensionsTest); - }); -} - -@reflectiveTest -class ExtensionsTest extends ApiSummaryTest { - Future test_element_apiName_classMember() async { - var class_ = (await analyzeLibrary(''' -class C { - void method() {} - int get getter => 0; - set setter(int value) {} - int field = 0; - static const constant = 0; -} -''')).getClass('C')!; - expect(class_.getMethod('method')!.apiName, 'method'); - expect(class_.getGetter('getter')!.apiName, 'getter'); - expect(class_.getSetter('setter')!.apiName, 'setter='); - expect(class_.getField('field')!.apiName, 'field'); - expect(class_.getField('constant')!.apiName, 'constant'); - } - - Future test_element_apiName_topLevel() async { - var lib = await analyzeLibrary(''' -void function() {} -int get getter => 0; -set setter(int value) {} -int variable = 0; -const constant = 0; -class Class {} -mixin Mixin {} -enum Enum { e } -extension Extension on int {} -extension type ExtensionType(int i) {} -'''); - expect(lib.getTopLevelFunction('function')!.apiName, 'function'); - expect(lib.getGetter('getter')!.apiName, 'getter'); - expect(lib.getSetter('setter')!.apiName, 'setter='); - expect(lib.getTopLevelVariable('variable')!.apiName, 'variable'); - expect(lib.getTopLevelVariable('constant')!.apiName, 'constant'); - expect(lib.getClass('Class')!.apiName, 'Class'); - expect(lib.getMixin('Mixin')!.apiName, 'Mixin'); - expect(lib.getEnum('Enum')!.apiName, 'Enum'); - expect(lib.getExtension('Extension')!.apiName, 'Extension'); - expect(lib.getExtensionType('ExtensionType')!.apiName, 'ExtensionType'); - } - - Future test_formalParameterElement_isDeprecated() async { - var f = (await analyzeLibrary( - 'f({int? i, @deprecated int? j}) {}', - )).getTopLevelFunction('f')!; - expect(f.formalParameters[0].isDeprecated, isFalse); - expect(f.formalParameters[1].isDeprecated, isTrue); - } - - void test_iterableIterable_separatedBy() { - expect( - [ - ['a', 'b'], - ['c', 'd'], - ].separatedBy(), - ['', 'a', 'b', ', ', 'c', 'd', ''], - ); - expect( - [ - ['a', 'b'], - ['c', 'd'], - ].separatedBy(prefix: '[', separator: '|', suffix: ']'), - ['[', 'a', 'b', '|', 'c', 'd', ']'], - ); - expect( - >[].separatedBy( - prefix: '[', - separator: '|', - suffix: ']', - ), - ['[', ']'], - ); - } - - void test_string_isPublic() { - expect('_'.isPublic, isFalse); - expect('foo'.isPublic, isTrue); - expect('_foo'.isPublic, isFalse); - } - - void test_uri_isIn() { - expect(Uri.parse('package:foo/bar.dart').isIn('foo'), isTrue); - expect(Uri.parse('package:foo/bar.dart').isIn('bar.dart'), isFalse); - expect(Uri.parse('dart:core').isIn('foo'), isFalse); - expect(Uri.parse('dart:core').isIn('dart'), isFalse); - expect(Uri.parse('dart:core').isIn('core'), isFalse); - } - - void test_uri_isInPublicLibOf() { - expect(Uri.parse('package:foo/bar.dart').isInPublicLibOf('foo'), isTrue); - expect( - Uri.parse('package:foo/bar.dart').isInPublicLibOf('bar.dart'), - isFalse, - ); - expect( - Uri.parse('package:foo/src/bar.dart').isInPublicLibOf('foo'), - isFalse, - ); - expect( - Uri.parse('package:foo/src/bar.dart').isInPublicLibOf('src'), - isFalse, - ); - expect(Uri.parse('dart:core').isInPublicLibOf('foo'), isFalse); - expect(Uri.parse('dart:core').isInPublicLibOf('dart'), isFalse); - expect(Uri.parse('dart:core').isInPublicLibOf('core'), isFalse); - } -} diff --git a/pkg/api_summary/test/member_sorting_test.dart b/pkg/api_summary/test/member_sorting_test.dart deleted file mode 100644 index fe1d8f793b3..00000000000 --- a/pkg/api_summary/test/member_sorting_test.dart +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: non_constant_identifier_names - -import 'package:analyzer/dart/element/element.dart'; -import 'package:api_summary/src/extensions.dart'; -import 'package:api_summary/src/member_sorting.dart'; -import 'package:collection/collection.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -import 'test_utils.dart'; - -void main() { - defineReflectiveSuite(() { - defineReflectiveTests(MemberTest); - }); -} - -@reflectiveTest -class MemberTest extends ApiSummaryTest { - Future test_sortOrder_member_categoryBeforeName() async { - _checkSorting( - elements: (await analyzeLibrary(''' -class C { - C.a1(); - get a2 => 0; - a3() {} - C.z1(); - get z2 => 0; - z3() {} - } -''')).getClass('C')!.childrenExcludingPropertyInducingElements, - expectedOrder: ['a1', 'z1', 'a2', 'z2', 'a3', 'z3'], - ); - } - - Future test_sortOrder_member_gettersAndSettersTogether() async { - // Note that it's not good enough for the implementation to sort by apiName, - // because `9` is ASCII 0x39 and `=` is ASCII 0x3d, so sorting by apiName - // would put `a9` and `a9=` between `a` and `a=`. - _checkSorting( - elements: (await analyzeLibrary(''' -class C { - get a => 0; - get a9 => 0; - get aA => 0; - set a(value) {} - set a9(value) {} - set aA(value) {} -} -''')).getClass('C')!.childrenExcludingPropertyInducingElements, - expectedOrder: ['new', 'a', 'a=', 'a9', 'a9=', 'aA', 'aA='], - ); - } - - Future test_sortOrder_member_staticBeforeInstance() async { - _checkSorting( - elements: (await analyzeLibrary(''' -class C { - C.a1(); - C.z1(); - get a2 => 0; - get z2 => 0; - static get a3 => 0; - static get z3 => 0; - a4() {} - z4() {} - static a5() {} - static z5() {} -} -''')).getClass('C')!.childrenExcludingPropertyInducingElements, - expectedOrder: [ - 'a3', - 'z3', - 'a5', - 'z5', - 'a1', - 'z1', - 'a2', - 'z2', - 'a4', - 'z4', - ], - ); - } - - Future test_sortOrder_member_unnamedConstructorBeforeOthers() async { - // Note that it's not good enough for the implementation to sort by apiName, - // because that would put `new` after `A`. - _checkSorting( - elements: (await analyzeLibrary(''' -class C { - C(); - C.A(); - C.z(); -} -''')).getClass('C')!.childrenExcludingPropertyInducingElements, - expectedOrder: ['new', 'A', 'z'], - ); - } - - Future test_sortOrder_topLevel_categoryBeforeName() async { - _checkSorting( - elements: (await analyzeLibrary(''' -get a1 => 0; -a2() {} -class a3 {} -extension a4 on int {} -typedef a5 = int; -get z1 => 0; -z2() {} -class z3 {} -extension z4 on int {} -typedef z5 = int; -''')).childrenExcludingPropertyInducingElements, - expectedOrder: [ - 'a1', - 'z1', - 'a2', - 'z2', - 'a3', - 'z3', - 'a4', - 'z4', - 'a5', - 'z5', - ], - ); - } - - Future test_sortOrder_topLevel_gettersAndSettersTogether() async { - // Note that it's not good enough for the implementation to sort by apiName, - // because `9` is ASCII 0x39 and `=` is ASCII 0x3d, so sorting by apiName - // would put `a9` and `a9=` between `a` and `a=`. - _checkSorting( - elements: (await analyzeLibrary(''' -get a => 0; -get a9 => 0; -get aA => 0; -set a(value) {} -set a9(value) {} -set aA(value) {} -''')).childrenExcludingPropertyInducingElements, - expectedOrder: ['a', 'a=', 'a9', 'a9=', 'aA', 'aA='], - ); - } - - Future test_sortOrder_topLevel_interfaceTypesTogether() async { - _checkSorting( - elements: (await analyzeLibrary(''' -class A1 {} -class Z1 {} -mixin A2 {} -mixin Z2 {} -enum A3 { v } -enum Z3 { v } -extension type A4(int i) {} -extension type Z4(int i) {} -''')).childrenExcludingPropertyInducingElements, - expectedOrder: ['A1', 'A2', 'A3', 'A4', 'Z1', 'Z2', 'Z3', 'Z4'], - ); - } - - Future test_sortOrder_topLevel_oldAndNewTypedefsTogether() async { - _checkSorting( - elements: (await analyzeLibrary(''' -typedef void A1(); -typedef void Z1(); -typedef A2 = void Function(); -typedef Z2 = void Function(); -typedef A3 = int; -typedef Z3 = int; -''')).childrenExcludingPropertyInducingElements, - expectedOrder: ['A1', 'A2', 'A3', 'Z1', 'Z2', 'Z3'], - ); - } - - void _checkSorting({ - required List elements, - required List expectedOrder, - }) { - expect( - elements.sortedBy(MemberSortKey.new).map((e) => e.apiName).toList(), - expectedOrder, - ); - expect( - elements.reversed - .sortedBy(MemberSortKey.new) - .map((e) => e.apiName) - .toList(), - expectedOrder, - ); - } -} - -extension on Element { - /// All children of `this` excluding [PropertyInducingElement]s. - /// - /// This is used for testing the sort order of class members, since the API - /// summary only considers getters and setters; it ignores the fields and top - /// level variables that induce them. - List get childrenExcludingPropertyInducingElements => - children.whereNot((e) => e is PropertyInducingElement).toList(); -} diff --git a/pkg/api_summary/test/node_test.dart b/pkg/api_summary/test/node_test.dart deleted file mode 100644 index 90879d0cffd..00000000000 --- a/pkg/api_summary/test/node_test.dart +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: non_constant_identifier_names - -import 'package:api_summary/src/node.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -void main() { - defineReflectiveSuite(() { - defineReflectiveTests(NodeTest); - }); -} - -@reflectiveTest -class NodeTest { - void test_printNodes_indentChildNodes() { - var buf = StringBuffer(); - printNodes(buf, [ - ( - 1, - _SimpleNode('one', [ - (2, _SimpleNode('two')), - (3, _SimpleNode('three')), - ]), - ), - ( - 4, - _SimpleNode('four', [ - (5, _SimpleNode('five')), - (6, _SimpleNode('six')), - ]), - ), - ]); - expect(buf.toString(), ''' -one - two - three -four - five - six -'''); - } - - void test_printNodes_joinTextStrings() { - var buf = StringBuffer(); - printNodes(buf, [ - (1, Node()..text.addAll(['x', 0])), - ]); - expect(buf.toString(), ''' -x0 -'''); - } - - void test_printNodes_sortChildNodesByKey() { - var buf = StringBuffer(); - printNodes(buf, [ - ( - 0, - _SimpleNode('zero', [ - (2, _SimpleNode('two')), - (1, _SimpleNode('one')), - (3, _SimpleNode('three')), - ]), - ), - ]); - expect(buf.toString(), ''' -zero - one - two - three -'''); - } - - void test_printNodes_sortedByKey() { - var buf = StringBuffer(); - printNodes(buf, [ - (2, _SimpleNode('two')), - (1, _SimpleNode('one')), - (3, _SimpleNode('three')), - ]); - expect(buf.toString(), ''' -one -two -three -'''); - } -} - -class _SimpleNode extends Node { - _SimpleNode(String text, [List<(num, Node)> childNodes = const []]) { - this.text.add(text); - this.childNodes.addAll(childNodes); - } -} diff --git a/pkg/api_summary/test/test_utils.dart b/pkg/api_summary/test/test_utils.dart deleted file mode 100644 index 215193565de..00000000000 --- a/pkg/api_summary/test/test_utils.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/diagnostic/diagnostic.dart'; -// TODO(paulberry): move pub_package_resolution.dart out of src -import 'package:analyzer_testing/src/analysis_rule/pub_package_resolution.dart'; -import 'package:test/test.dart'; - -class ApiSummaryTest extends PubPackageResolutionTest { - Future analyzeLibrary( - String content, { - String pathWithinLib = 'test.dart', - }) async { - var file = newFile('$testPackageLibPath/$pathWithinLib', content); - var resolvedUnitResult = await resolveFile(file.path); - expect( - resolvedUnitResult.diagnostics.where( - (diagnostic) => diagnostic.severity == Severity.error, - ), - isEmpty, - ); - return resolvedUnitResult.libraryElement; - } -} diff --git a/pkg/api_summary/test/unique_namer_test.dart b/pkg/api_summary/test/unique_namer_test.dart deleted file mode 100644 index 80df390143d..00000000000 --- a/pkg/api_summary/test/unique_namer_test.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: non_constant_identifier_names - -import 'package:api_summary/src/unique_namer.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -import 'test_utils.dart'; - -void main() { - defineReflectiveSuite(() { - defineReflectiveTests(UniqueNamerTest); - }); -} - -@reflectiveTest -class UniqueNamerTest extends ApiSummaryTest { - Future test_collidingNamesAreDisambiguated() async { - var f1 = (await analyzeLibrary( - pathWithinLib: 'file1.dart', - 'f() {}', - )).getTopLevelFunction('f')!; - var f2 = (await analyzeLibrary( - pathWithinLib: 'file2.dart', - 'f() {}', - )).getTopLevelFunction('f')!; - var uniqueNamer = UniqueNamer(); - var f1Name = uniqueNamer.name(f1); - var f2Name = uniqueNamer.name(f2); - expect(f1Name.toString(), 'f@1'); - expect(f2Name.toString(), 'f@2'); - } - - Future test_name_returnsSameNameOnSuccessiveCalls() async { - var f = (await analyzeLibrary('f() {}')).getTopLevelFunction('f')!; - var uniqueNamer = UniqueNamer(); - var name1 = uniqueNamer.name(f); - var name2 = uniqueNamer.name(f); - expect(name1, same(name2)); - } - - Future test_nonCollidingNamesAreNotDisambiguated() async { - var f = (await analyzeLibrary( - pathWithinLib: 'file1.dart', - 'f() {}', - )).getTopLevelFunction('f')!; - var g = (await analyzeLibrary( - pathWithinLib: 'file2.dart', - 'g() {}', - )).getTopLevelFunction('g')!; - var uniqueNamer = UniqueNamer(); - var fName = uniqueNamer.name(f); - var gName = uniqueNamer.name(g); - expect(fName.toString(), 'f'); - expect(gName.toString(), 'g'); - } - - Future test_three_collisions() async { - var f1 = (await analyzeLibrary( - pathWithinLib: 'file1.dart', - 'f() {}', - )).getTopLevelFunction('f')!; - var f2 = (await analyzeLibrary( - pathWithinLib: 'file2.dart', - 'f() {}', - )).getTopLevelFunction('f')!; - var f3 = (await analyzeLibrary( - pathWithinLib: 'file3.dart', - 'f() {}', - )).getTopLevelFunction('f')!; - var uniqueNamer = UniqueNamer(); - var f1Name = uniqueNamer.name(f1); - var f2Name = uniqueNamer.name(f2); - var f3Name = uniqueNamer.name(f3); - expect(f1Name.toString(), 'f@1'); - expect(f2Name.toString(), 'f@2'); - expect(f3Name.toString(), 'f@3'); - } -} diff --git a/pkg/api_summary/test/uri_sorting_test.dart b/pkg/api_summary/test/uri_sorting_test.dart deleted file mode 100644 index 3d7a541a93b..00000000000 --- a/pkg/api_summary/test/uri_sorting_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: non_constant_identifier_names - -import 'package:api_summary/src/uri_sorting.dart'; -import 'package:collection/collection.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -void main() { - defineReflectiveSuite(() { - defineReflectiveTests(UriTest); - }); -} - -@reflectiveTest -class UriTest { - void test_sortOrder_inOrOutOfPackageBeforeName() { - _checkSorting( - uris: [ - Uri.parse('package:a/a.dart'), - Uri.parse('package:b/b.dart'), - Uri.parse('package:c/c.dart'), - ], - expectedOrder: [ - 'package:b/b.dart', - 'package:a/a.dart', - 'package:c/c.dart', - ], - packageName: 'b', - ); - } - - void _checkSorting({ - required List uris, - required List expectedOrder, - required String packageName, - }) { - expect( - uris - .sortedBy((e) => UriSortKey(e, packageName)) - .map((e) => e.toString()) - .toList(), - expectedOrder, - ); - expect( - uris.reversed - .sortedBy((e) => UriSortKey(e, packageName)) - .map((e) => e.toString()) - .toList(), - expectedOrder, - ); - } -} diff --git a/pubspec.yaml b/pubspec.yaml index d379263029b..ec6bbb50706 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,7 +19,6 @@ workspace: - pkg/analysis_server_client - pkg/analysis_server_plugin - pkg/analyzer - - pkg/api_summary - pkg/analyzer_cli - pkg/analyzer_plugin - pkg/analyzer_testing @@ -106,6 +105,8 @@ workspace: # All third_party packages are retrieved via the DEPS-file and overridden here. dependency_overrides: + api_summary: + path: third_party/pkg/tools/pkgs/api_summary args: path: third_party/pkg/core/pkgs/args async: diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index b8168ab5bf2..01bd0c83ff8 100644 --- a/tools/bots/test_matrix.json +++ b/tools/bots/test_matrix.json @@ -2970,7 +2970,7 @@ "name": "unit tests", "arguments": [ "-nanalyzer-unittest-asserts-${mode}-${system}", - "pkg/(analyzer|analysis_server|analysis_server_plugin|analyzer_cli|analyzer_plugin|api_summary)" + "pkg/(analyzer|analysis_server|analysis_server_plugin|analyzer_cli|analyzer_plugin)" ], "shards": 9, "fileset": "analyzer_unit_tests" @@ -3053,13 +3053,6 @@ "pkg/analyzer_plugin" ] }, - { - "name": "api_summary unit tests", - "arguments": [ - "-nanalyzer-unittest-asserts-${mode}-${system}", - "pkg/api_summary" - ] - }, { "name": "benchmark analysis server", "script": "out/ReleaseX64/dart-sdk/bin/dart",