Skip to content

Commit

Permalink
Version 3.2.0-21.0.dev
Browse files Browse the repository at this point in the history
Merge d9363a6 into dev
  • Loading branch information
Dart CI committed Aug 1, 2023
2 parents 9f1225e + d9363a6 commit 45405dd
Show file tree
Hide file tree
Showing 48 changed files with 688 additions and 657 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
`ObjectToJSExportedDartObject` and `JSExportedDartObjectToObject` are renamed
to `ObjectToJSBoxedDartObject` and `JSBoxedDartObjectToObject` in order to
avoid confusion with `@JSExport`.
- **Type parameters in external APIs**:
Type parameters must now be bound to a static interop type or one of the
`dart:js_interop` types like `JSNumber` when used in an external API. This
only affects `dart:js_interop` classes and not `package:js` or other forms of
JS interop.

## 3.1.0

Expand Down
6 changes: 3 additions & 3 deletions DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ vars = {
"fixnum_rev": "00fa1207768bd07d04c895cbe0f1fe99af14e727",
"glob_rev": "5b243935154daf53c54981b98f625bace90b2112",
"html_rev": "4060496b0443451c38f8b789db2e44c0d7966171",
"http_rev": "1a42b4a16636e86b5fed60666b0de91219c5110c",
"http_rev": "4289e8b9dbdbebaa26c28f30b461018a191b6e73",
"http_multi_server_rev": "aa128cfaf6ef1c9c1ace962ca2dcf6e5dddad441",
"http_parser_rev": "c14fbf6aa7ada5e8912eab4581eb26ff4d101452",
"intl_rev": "5d65e3808ce40e6282e40881492607df4e35669f",
Expand All @@ -158,7 +158,7 @@ vars = {
"matcher_rev": "ce8f40934c90e12992071172795b3bca29fac295",
"mime_rev": "799b398140817fdb134f639d84e91c552e129136",
"mockito_rev": "b4217750cbab5cdd2a773106abb476a7ea4aefb2",
"native_rev": "2598ac66148f5b6a44d8f6bf01643c6b1c49e590",
"native_rev": "f0dc3e9b26084c6be820348b3748bcb7315e0da8",
"package_config_rev": "981c49dfec1e3e3e90f336dcd7c225923d2fd321",
"path_rev": "282dd18bd9ae2e265ea40a29b2c637194e9be8b7",
"pool_rev": "77001024a16126cc5718e654ea3e57bbf6e7fac3",
Expand All @@ -179,7 +179,7 @@ vars = {
"test_descriptor_rev": "36d8617fafccbe36dfcf74ad4921c61911a6a411",
"test_process_rev": "b360784a9149b15888aed8d7cf167bb46fe733d5",
"test_reflective_loader_rev": "0bfaad91ed308ce9da11b48395c8210d7542c16b",
"tools_rev": "600ea0a46c79bc457cc00f7558cbdc9bf041c846",
"tools_rev": "ba55fd692377ec398b61198c602c5302bf65226d",
"typed_data_rev": "a20be901e11eddcbd6e5735fb01b64d28c94c49d",
"usage_rev": "09bb8472fdafff2c48a19aabbcf57b3af0f43934",
"vector_math_rev": "88bada3c32ba3f1d53073a003085131d60b09213",
Expand Down
12 changes: 6 additions & 6 deletions pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8182,18 +8182,18 @@ const MessageCode messageJsInteropOperatorsNotSupported = const MessageCode(

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null>
codeJsInteropStaticInteropExternalExtensionMembersWithTypeParameters =
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters;
codeJsInteropStaticInteropExternalMemberWithInvalidTypeParameters =
messageJsInteropStaticInteropExternalMemberWithInvalidTypeParameters;

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters =
messageJsInteropStaticInteropExternalMemberWithInvalidTypeParameters =
const MessageCode(
"JsInteropStaticInteropExternalExtensionMembersWithTypeParameters",
"JsInteropStaticInteropExternalMemberWithInvalidTypeParameters",
problemMessage:
r"""`@staticInterop` classes cannot have external extension members with type parameters.""",
r"""External static interop members can only use type parameters that extend either a static interop type or one of the 'dart:js_interop' types.""",
correctionMessage:
r"""Try using a Dart extension member if you need type parameters instead.""");
r"""Try adding a valid bound to the type parameters used in this member.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropStaticInteropGenerativeConstructor =
Expand Down
22 changes: 0 additions & 22 deletions pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1407,23 +1407,6 @@ class ForwardingListener implements Listener {
listener?.handleMixinWithClause(withKeyword);
}

@override
void handleCommentReference(
Token? newKeyword,
Token? firstToken,
Token? firstPeriod,
Token? secondToken,
Token? secondPeriod,
Token thirdToken) {
listener?.handleCommentReference(newKeyword, firstToken, firstPeriod,
secondToken, secondPeriod, thirdToken);
}

@override
void handleCommentReferenceText(String referenceSource, int referenceOffset) {
listener?.handleCommentReferenceText(referenceSource, referenceOffset);
}

@override
void handleConditionalExpressionColon() {
listener?.handleConditionalExpressionColon();
Expand Down Expand Up @@ -1752,11 +1735,6 @@ class ForwardingListener implements Listener {
listener?.handleNoArguments(token);
}

@override
void handleNoCommentReference() {
listener?.handleNoCommentReference();
}

@override
void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
listener?.handleNoConstructorReferenceContinuationAfterTypeArguments(token);
Expand Down
33 changes: 0 additions & 33 deletions pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2287,39 +2287,6 @@ class Listener implements UnescapeErrorListener {
logEvent("Script");
}

/// A single comment reference has been found
/// where [referenceSource] is the text between the `[` and `]`
/// and [referenceOffset] is the character offset in the token stream.
///
/// This event is generated by the parser when the parser's
/// `parseCommentReferences` method is called. For further processing,
/// a listener may scan the [referenceSource] and then pass the resulting
/// token stream to the parser's `parseOneCommentReference` method.
void handleCommentReferenceText(String referenceSource, int referenceOffset) {
logEvent("CommentReferenceText");
}

/// A single comment reference has been parsed.
/// * [newKeyword] may be null.
/// * [firstToken] and [firstPeriod] are either both tokens or both
/// `null`.
/// * [secondToken] and [secondPeriod] are either both tokens or both `null`.
/// * [thirdToken] can be an identifier or an operator.
///
/// This event is generated by the parser when the parser's
/// `parseOneCommentReference` method is called.
void handleCommentReference(
Token? newKeyword,
Token? firstToken,
Token? firstPeriod,
Token? secondToken,
Token? secondPeriod,
Token thirdToken) {}

/// This event is generated by the parser when the parser's
/// `parseOneCommentReference` method is called.
void handleNoCommentReference() {}

/// An expression was encountered consisting of type arguments applied to a
/// subexpression. This could validly represent any of the following:
/// - A type literal (`var x = List<int>;`)
Expand Down
93 changes: 62 additions & 31 deletions pkg/_js_interop_checks/lib/js_interop_checks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageJsInteropNonExternalMember,
messageJsInteropOperatorCannotBeRenamed,
messageJsInteropOperatorsNotSupported,
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters,
messageJsInteropStaticInteropExternalMemberWithInvalidTypeParameters,
messageJsInteropStaticInteropGenerativeConstructor,
messageJsInteropStaticInteropParameterInitializersAreIgnored,
messageJsInteropStaticInteropSyntheticConstructor,
Expand Down Expand Up @@ -68,7 +68,7 @@ class JsInteropChecks extends RecursiveVisitor {
final Map<String, Class> _nativeClasses;
final JsInteropDiagnosticReporter _reporter;
final StatefulStaticTypeContext _staticTypeContext;
final _TypeParameterVisitor _typeParameterVisitor = _TypeParameterVisitor();
late _TypeParameterBoundChecker _typeParameterBoundChecker;
bool _classHasJSAnnotation = false;
bool _classHasAnonymousAnnotation = false;
bool _classHasStaticInteropAnnotation = false;
Expand Down Expand Up @@ -151,6 +151,8 @@ class JsInteropChecks extends RecursiveVisitor {
TypeEnvironment(_coreTypes, hierarchy)) {
_inlineExtensionIndex =
InlineExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
_typeParameterBoundChecker =
_TypeParameterBoundChecker(_inlineExtensionIndex);
}

/// Verifies given [member] is an external extension member on a static
Expand Down Expand Up @@ -385,23 +387,29 @@ class JsInteropChecks extends RecursiveVisitor {
(hasDartJSInteropAnnotation(node) ||
_libraryHasDartJSInteropAnnotation)) {
_checkNoParamInitializersForStaticInterop(node.function);
if (node.isExtensionMember) {
final annotatable =
_inlineExtensionIndex.getExtensionAnnotatable(node);
late Annotatable? annotatable;
if (node.isInlineClassMember) {
annotatable = _inlineExtensionIndex.getInlineClass(node);
} else if (node.isExtensionMember) {
annotatable = _inlineExtensionIndex.getExtensionAnnotatable(node);
if (annotatable != null) {
// If a @staticInterop member, check that it uses no type
// parameters.
if (hasStaticInteropAnnotation(annotatable) &&
!isAllowedCustomStaticInteropImplementation(node)) {
_checkStaticInteropMemberUsesNoTypeParameters(node);
}
// We do not support external extension members with the 'static'
// keyword currently.
if (_inlineExtensionIndex.getExtensionDescriptor(node)!.isStatic) {
report(
messageJsInteropExternalExtensionMemberWithStaticDisallowed);
}
}
} else {
annotatable = node.enclosingClass;
}
if (!isAllowedCustomStaticInteropImplementation(node)) {
if (annotatable == null ||
((hasDartJSInteropAnnotation(annotatable) ||
annotatable is InlineClass))) {
// Only restrict type parameters for dart:js_interop.
_checkStaticInteropMemberUsesValidTypeParameters(node);
}
}
}
}
Expand Down Expand Up @@ -839,18 +847,10 @@ class JsInteropChecks extends RecursiveVisitor {
}
}

void _checkStaticInteropMemberUsesNoTypeParameters(Procedure node) {
// If the extension has type parameters of its own, it copies those type
// parameters to the procedure's type parameters (in the front) as well.
// Ignore these for the analysis.
final extensionTypeParams =
_inlineExtensionIndex.getExtension(node)!.typeParameters;
final procedureTypeParams = List.from(node.function.typeParameters);
procedureTypeParams.removeRange(0, extensionTypeParams.length);
if (procedureTypeParams.isNotEmpty ||
_typeParameterVisitor.usesTypeParameters(node)) {
void _checkStaticInteropMemberUsesValidTypeParameters(Procedure node) {
if (_typeParameterBoundChecker.containsInvalidTypeBound(node)) {
_reporter.report(
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters,
messageJsInteropStaticInteropExternalMemberWithInvalidTypeParameters,
node.fileOffset,
node.name.text.length,
node.fileUri);
Expand Down Expand Up @@ -935,7 +935,8 @@ class JsInteropChecks extends RecursiveVisitor {
(type is InterfaceType &&
hasStaticInteropAnnotation(type.classNode)) ||
(type is InlineType &&
hasDartJSInteropAnnotation(type.inlineClass)))) {
_inlineExtensionIndex
.isInteropInlineClass(type.inlineClass)))) {
_reporter.report(
templateJsInteropStrictModeViolation.withArguments(type, true),
node.fileOffset,
Expand All @@ -952,19 +953,49 @@ class JsInteropChecks extends RecursiveVisitor {
_reportIfNotJSType(type, node, node.name, node.location?.file);
}

/// Visitor used to check if a particular node uses a type parameter type.
class _TypeParameterVisitor extends RecursiveVisitor {
bool _visitedTypeParameterType = false;
/// Visitor used to check that all usages of type parameter types of an external
/// static interop member is a valid static interop type.
class _TypeParameterBoundChecker extends RecursiveVisitor {
final InlineExtensionIndex _inlineExtensionIndex;

_TypeParameterBoundChecker(this._inlineExtensionIndex);

bool _containsInvalidTypeBound = false;

bool containsInvalidTypeBound(Procedure node) {
_containsInvalidTypeBound = false;
final function = node.function;
for (final param in function.positionalParameters) {
param.accept(this);
}
function.returnType.accept(this);
return _containsInvalidTypeBound;
}

@override
void visitInterfaceType(InterfaceType node) {
final cls = node.classNode;
if (hasStaticInteropAnnotation(cls)) return;
super.visitInterfaceType(node);
}

bool usesTypeParameters(Node node) {
_visitedTypeParameterType = false;
node.accept(this);
return _visitedTypeParameterType;
@override
void visitInlineType(InlineType node) {
if (_inlineExtensionIndex.isInteropInlineClass(node.inlineClass)) return;
super.visitInlineType(node);
}

@override
void visitTypeParameterType(TypeParameterType node) {
_visitedTypeParameterType = true;
final bound = node.bound;
if (bound is InlineType &&
!_inlineExtensionIndex.isInteropInlineClass(bound.inlineClass)) {
_containsInvalidTypeBound = true;
}
if (bound is InterfaceType &&
!hasStaticInteropAnnotation(bound.classNode)) {
_containsInvalidTypeBound = true;
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion pkg/analysis_server/lib/src/computer/computer_hover.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class DartUnitHoverComputer {
locationEntity = node.name;
} else if (node is PatternFieldName) {
locationEntity = node.name;
} else if (node is WildcardPattern) {
locationEntity = node.name;
}
if (locationEntity == null) {
return null;
Expand Down Expand Up @@ -89,7 +91,8 @@ class DartUnitHoverComputer {
node is DeclaredIdentifier ||
node is VariableDeclaration ||
node is VariablePattern ||
node is PatternFieldName)) {
node is PatternFieldName ||
node is DartPattern)) {
// For constructors, the location should cover the type name and
// constructor name (for both calls and declarations).
HoverInformation hover;
Expand Down Expand Up @@ -184,6 +187,8 @@ class DartUnitHoverComputer {
}
} else if (node is PatternFieldName && parent is PatternField) {
staticType = parent.pattern.matchedValueType;
} else if (node is DartPattern) {
staticType = node.matchedValueType;
}
hover.staticType = _typeDisplayString(staticType);
}
Expand Down
23 changes: 22 additions & 1 deletion pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ class ReferencesHandler
ReferenceParams params,
ResolvedUnitResult unit,
OperationPerformanceImpl performance) async {
final node = NodeLocator(offset).searchWithin(result.unit);
var node = NodeLocator(offset).searchWithin(result.unit);
node = _getReferenceTargetNode(node);
var element = server.getElementOfNode(node);
if (element == null) {
return success(null);
Expand Down Expand Up @@ -104,4 +105,24 @@ class ReferencesHandler

return success(referenceResults);
}

/// Gets the nearest node that should be used for finding references.
///
/// This is usually the same node but allows some adjustments such as
/// considering the offset between a type name and type arguments as part
/// of the type.
AstNode? _getReferenceTargetNode(AstNode? node) {
// Consider the angle brackets for type arguments part of the leading type,
// otherwise we don't navigate in the common situation of having the type
// name selected, where VS Code provides the end of the selection as the
// position to search.
//
// In `A^<String>` node will be `TypeParameterList` and we will not find any
// references.
if (node is TypeParameterList) {
node = node.parent;
}

return node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class DartSnippetRequest {
tokenType == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
return SnippetContext.inString;
}
} else if (entity is NamedExpression &&
target.offset >= entity.name.offset &&
target.offset <= entity.name.end) {
return SnippetContext.inName;
}

AstNode? node = target.containingNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ enum SnippetContext {
inQualifiedMemberAccess,
inStatement,
inString,
inName,
}
Loading

0 comments on commit 45405dd

Please sign in to comment.