Skip to content

Commit

Permalink
Add APIs for using analyzer element model 2. (#3775)
Browse files Browse the repository at this point in the history
* Add APIs for using analyzer element model 2.

* Update CHANGELOG.md
  • Loading branch information
scheglov authored Dec 14, 2024
1 parent fbdfb67 commit 1865a35
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 34 deletions.
2 changes: 1 addition & 1 deletion build/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
- Bump the min sdk to 3.6.0-228.0.dev.
- Remove some unnecessary casts and non-null assertions now that we have private
field promotion.
- Require analyzer ^6.9.0.
- Require analyzer ^7.0.0.
- Fix analyzer deprecations.

## 2.4.1
Expand Down
56 changes: 56 additions & 0 deletions build/lib/src/analyzer/resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/error/error.dart';

import '../asset/id.dart';
Expand All @@ -29,6 +30,17 @@ abstract class Resolver {
/// instance because due to imports or exports.
Stream<LibraryElement> get libraries;

/// All libraries resolved by this resolver.
///
/// This includes the following libraries:
/// - The primary input of this resolver (in other words, the
/// [BuildStep.inputId] of a build step).
/// - Libraries resolved with a direct [libraryFor] call.
/// - Every public `dart:` library part of the SDK.
/// - All libraries recursively accessible from the mentioned sources, for
/// instance because due to imports or exports.
Stream<LibraryElement2> get libraries2;

/// Returns the parsed [AstNode] for [Element].
///
/// This should always be preferred over using the [AnalysisSession]
Expand All @@ -42,6 +54,19 @@ abstract class Resolver {
/// reason.
Future<AstNode?> astNodeFor(Element element, {bool resolve = false});

/// Returns the parsed [AstNode] for [Element].
///
/// This should always be preferred over using the [AnalysisSession]
/// directly, because it avoids [InconsistentAnalysisException] issues.
///
/// If [resolve] is `true` then you will get a resolved ast node, otherwise
/// it will only be a parsed ast node.
///
/// Returns `null` if the ast node can not be found. This can happen if an
/// element is coming from a summary, or is unavailable for some other
/// reason.
Future<AstNode?> astNodeFor2(Fragment element, {bool resolve = false});

/// Returns a parsed AST structor representing the file defined in [assetId].
///
/// * If the [assetId] has syntax errors, and [allowSyntaxErrors] is set to
Expand All @@ -60,6 +85,14 @@ abstract class Resolver {
Future<LibraryElement> libraryFor(AssetId assetId,
{bool allowSyntaxErrors = false});

/// Returns a resolved library representing the file defined in [assetId].
///
/// * Throws [NonLibraryAssetException] if [assetId] is not a Dart library.
/// * If the [assetId] has syntax errors, and [allowSyntaxErrors] is set to
/// `false` (the default), throws a [SyntaxErrorInAssetException].
Future<LibraryElement2> libraryFor2(AssetId assetId,
{bool allowSyntaxErrors = false});

/// Returns the first resolved library identified by [libraryName].
///
/// A library is resolved if it's recursively accessible from the entry point
Expand All @@ -72,6 +105,19 @@ abstract class Resolver {
/// being unique.
Future<LibraryElement?> findLibraryByName(String libraryName);

/// Returns the first resolved library identified by [libraryName].
///
/// A library is resolved if it's recursively accessible from the entry point
/// or subsequent calls to [libraryFor]. In other words, this searches for
/// libraries in [libraries].
/// If no library can be found, returns `null`.
///
/// **NOTE**: In general, its recommended to use [libraryFor] with an absolute
/// asset id instead of a named identifier that has the possibility of not
/// being unique.
Future<LibraryElement2?> findLibraryByName2(
String libraryName);

/// Returns the [AssetId] of the Dart library or part declaring [element].
///
/// If [element] is defined in the SDK or in a summary throws
Expand All @@ -81,6 +127,16 @@ abstract class Resolver {
/// The returned asset is not necessarily the asset that should be imported to
/// use the element, it may be a part file instead of the library.
Future<AssetId> assetIdForElement(Element element);

/// Returns the [AssetId] of the Dart library or part declaring [element].
///
/// If [element] is defined in the SDK or in a summary throws
/// `UnresolvableAssetException`, although a non-throwing return here does not
/// guarantee that the asset is readable.
///
/// The returned asset is not necessarily the asset that should be imported to
/// use the element, it may be a part file instead of the library.
Future<AssetId> assetIdForElement2(Element2 element);
}

/// A resolver that should be manually released at the end of a build step.
Expand Down
16 changes: 16 additions & 0 deletions build/lib/src/builder/build_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:async';
import 'dart:convert';

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config_types.dart';

Expand Down Expand Up @@ -39,6 +40,21 @@ abstract class BuildStep implements AssetReader, AssetWriter {
/// ```
Future<LibraryElement> get inputLibrary;

/// Resolved library defined by [inputId].
///
/// Throws [NonLibraryAssetException] if [inputId] is not a Dart library file.
/// Throws [SyntaxErrorInAssetException] if [inputId] contains syntax errors.
/// If you want to support libraries with syntax errors, resolve the library
/// manually instead of using [inputLibrary]:
/// ```dart
/// Future<void> build(BuildStep step) async {
/// // Resolve the input library, allowing syntax errors
/// final inputLibrary =
/// await step.resolver.libraryFor(step.inputId, allowSyntaxErrors: true);
/// }
/// ```
Future<LibraryElement2> get inputLibrary2;

/// Gets an instance provided by [resource] which is guaranteed to be unique
/// within a single build, and may be reused across build steps within a
/// build if the implementation allows.
Expand Down
32 changes: 32 additions & 0 deletions build/lib/src/builder/build_step_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:convert';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:async/async.dart';
import 'package:crypto/crypto.dart';
import 'package:glob/glob.dart';
Expand Down Expand Up @@ -39,6 +40,12 @@ class BuildStepImpl implements BuildStep {
return resolver.libraryFor(inputId);
}

@override
Future<LibraryElement2> get inputLibrary2 async {
if (_isComplete) throw BuildStepCompletedException();
return resolver.libraryFor2(inputId);
}

/// The list of all outputs which are expected/allowed to be output from this
/// step.
@override
Expand Down Expand Up @@ -220,10 +227,21 @@ class _DelayedResolver implements Resolver {
return completer.stream;
}

@override
Stream<LibraryElement2> get libraries2 {
var completer = StreamCompleter<LibraryElement2>();
_delegate.then((r) => completer.setSourceStream(r.libraries2));
return completer.stream;
}

@override
Future<AstNode?> astNodeFor(Element element, {bool resolve = false}) async =>
(await _delegate).astNodeFor(element, resolve: resolve);

@override
Future<AstNode?> astNodeFor2(Fragment fragment, {bool resolve = false}) async =>
(await _delegate).astNodeFor2(fragment, resolve: resolve);

@override
Future<CompilationUnit> compilationUnitFor(AssetId assetId,
{bool allowSyntaxErrors = false}) async =>
Expand All @@ -236,11 +254,25 @@ class _DelayedResolver implements Resolver {
(await _delegate)
.libraryFor(assetId, allowSyntaxErrors: allowSyntaxErrors);

@override
Future<LibraryElement2> libraryFor2(AssetId assetId,
{bool allowSyntaxErrors = false}) async =>
(await _delegate)
.libraryFor2(assetId, allowSyntaxErrors: allowSyntaxErrors);

@override
Future<LibraryElement?> findLibraryByName(String libraryName) async =>
(await _delegate).findLibraryByName(libraryName);

@override
Future<LibraryElement2?> findLibraryByName2(String libraryName) async =>
(await _delegate).findLibraryByName2(libraryName);

@override
Future<AssetId> assetIdForElement(Element element) async =>
(await _delegate).assetIdForElement(element);

@override
Future<AssetId> assetIdForElement2(Element2 element) async =>
(await _delegate).assetIdForElement2(element);
}
2 changes: 1 addition & 1 deletion build/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ environment:
sdk: ^3.6.0-228.0.dev

dependencies:
analyzer: ^6.9.0
analyzer: ^7.0.0
async: ^2.5.0
convert: ^3.0.0
crypto: ^3.0.0
Expand Down
1 change: 1 addition & 0 deletions build_resolvers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Fix SDK summary reads when multiple isolates are using build resolvers (not
recommended).
- Fix analyzer deprecations.
- Require analyzer ^7.0.0.

## 2.4.2

Expand Down
Loading

0 comments on commit 1865a35

Please sign in to comment.