forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge commit '78b7fc5ac19d6c6550438aa5ecdbd19983c69c91' into 'dev'
- Loading branch information
Showing
63 changed files
with
1,492 additions
and
1,219 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
198 changes: 198 additions & 0 deletions
198
pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
// Copyright (c) 2021, 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/ast/ast.dart'; | ||
import 'package:analyzer/dart/element/element.dart'; | ||
import 'package:analyzer/dart/element/type.dart'; | ||
import 'package:analyzer/src/dart/ast/ast.dart'; | ||
import 'package:analyzer/src/dart/element/type_provider.dart'; | ||
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart'; | ||
import 'package:analyzer/src/generated/resolver.dart'; | ||
|
||
class CommentReferenceResolver { | ||
final TypeProviderImpl _typeProvider; | ||
|
||
final ResolverVisitor _resolver; | ||
|
||
/// Helper for resolving properties on types. | ||
final TypePropertyResolver _typePropertyResolver; | ||
|
||
CommentReferenceResolver(this._typeProvider, this._resolver) | ||
: _typePropertyResolver = _resolver.typePropertyResolver; | ||
|
||
/// Resolves [commentReference]. | ||
void resolve(CommentReference commentReference) { | ||
var expression = commentReference.expression; | ||
if (expression is SimpleIdentifierImpl) { | ||
_resolveSimpleIdentifierReference(expression, | ||
hasNewKeyword: commentReference.newKeyword != null); | ||
} else if (expression is PrefixedIdentifierImpl) { | ||
_resolvePrefixedIdentifierReference(expression, | ||
hasNewKeyword: commentReference.newKeyword != null); | ||
} else if (expression is PropertyAccessImpl) { | ||
_resolvePropertyAccessReference(expression, | ||
hasNewKeyword: commentReference.newKeyword != null); | ||
} | ||
} | ||
|
||
void _resolvePrefixedIdentifierReference( | ||
PrefixedIdentifierImpl expression, { | ||
required bool hasNewKeyword, | ||
}) { | ||
var prefix = expression.prefix; | ||
var prefixElement = _resolveSimpleIdentifier(prefix); | ||
prefix.staticElement = prefixElement; | ||
|
||
if (prefixElement == null) { | ||
return; | ||
} | ||
|
||
var name = expression.identifier; | ||
|
||
if (prefixElement is PrefixElement) { | ||
var prefixScope = prefixElement.scope; | ||
var lookupResult = prefixScope.lookup(name.name); | ||
var element = lookupResult.getter ?? lookupResult.setter; | ||
element = _resolver.toLegacyElement(element); | ||
name.staticElement = element; | ||
return; | ||
} | ||
|
||
if (!hasNewKeyword) { | ||
if (prefixElement is ClassElement) { | ||
name.staticElement = prefixElement.getMethod(name.name) ?? | ||
prefixElement.getGetter(name.name) ?? | ||
prefixElement.getSetter(name.name) ?? | ||
prefixElement.getNamedConstructor(name.name); | ||
} else if (prefixElement is ExtensionElement) { | ||
name.staticElement = prefixElement.getMethod(name.name) ?? | ||
prefixElement.getGetter(name.name) ?? | ||
prefixElement.getSetter(name.name); | ||
} else { | ||
// TODO(brianwilkerson) Report this error. | ||
} | ||
} else if (prefixElement is ClassElement) { | ||
var constructor = prefixElement.getNamedConstructor(name.name); | ||
if (constructor == null) { | ||
// TODO(brianwilkerson) Report this error. | ||
} else { | ||
name.staticElement = constructor; | ||
} | ||
} else { | ||
// TODO(brianwilkerson) Report this error. | ||
} | ||
} | ||
|
||
void _resolvePropertyAccessReference( | ||
PropertyAccessImpl expression, { | ||
required bool hasNewKeyword, | ||
}) { | ||
var target = expression.target; | ||
if (target is! PrefixedIdentifierImpl) { | ||
// A PropertyAccess with a target more complex than a | ||
// [PrefixedIdentifier] is not a valid comment reference. | ||
return; | ||
} | ||
|
||
var prefix = target.prefix; | ||
var prefixElement = _resolveSimpleIdentifier(prefix); | ||
prefix.staticElement = prefixElement; | ||
|
||
if (prefixElement is! PrefixElement) { | ||
// The only valid prefixElement is a PrefixElement; otherwise, this is | ||
// not a comment reference. | ||
return; | ||
} | ||
|
||
var name = target.identifier; | ||
var prefixScope = prefixElement.scope; | ||
var lookupResult = prefixScope.lookup(name.name); | ||
var element = lookupResult.getter ?? lookupResult.setter; | ||
element = _resolver.toLegacyElement(element); | ||
name.staticElement = element; | ||
|
||
var propertyName = expression.propertyName; | ||
if (element is ClassElement) { | ||
propertyName.staticElement = element.getMethod(propertyName.name) ?? | ||
element.getGetter(propertyName.name) ?? | ||
element.getSetter(propertyName.name) ?? | ||
element.getNamedConstructor(propertyName.name); | ||
} else if (element is ExtensionElement) { | ||
propertyName.staticElement = element.getMethod(propertyName.name) ?? | ||
element.getGetter(propertyName.name) ?? | ||
element.getSetter(propertyName.name); | ||
} | ||
} | ||
|
||
/// Resolves the given simple [identifier] if possible. | ||
/// | ||
/// Returns the resolved element, or `null` if the identifier could not be | ||
/// resolved. This does not record the results of the resolution. | ||
Element? _resolveSimpleIdentifier(SimpleIdentifierImpl identifier) { | ||
var lookupResult = identifier.scopeLookupResult!; | ||
|
||
var element = _resolver.toLegacyElement(lookupResult.getter) ?? | ||
_resolver.toLegacyElement(lookupResult.setter); | ||
|
||
if (element == null) { | ||
InterfaceType enclosingType; | ||
var enclosingClass = _resolver.enclosingClass; | ||
if (enclosingClass != null) { | ||
enclosingType = enclosingClass.thisType; | ||
} else { | ||
var enclosingExtension = _resolver.enclosingExtension; | ||
if (enclosingExtension == null) { | ||
return null; | ||
} | ||
var extendedType = enclosingExtension.extendedType | ||
.resolveToBound(_typeProvider.objectType); | ||
if (extendedType is InterfaceType) { | ||
enclosingType = extendedType; | ||
} else if (extendedType is FunctionType) { | ||
enclosingType = _typeProvider.functionType; | ||
} else { | ||
return null; | ||
} | ||
} | ||
var result = _typePropertyResolver.resolve( | ||
receiver: null, | ||
receiverType: enclosingType, | ||
name: identifier.name, | ||
propertyErrorEntity: identifier, | ||
nameErrorEntity: identifier, | ||
); | ||
if (identifier.parent is CommentReference) { | ||
// TODO(srawlins): Why is the setter preferred? This seems very flawed | ||
// as it will only use the setter for a [SimpleIdentifier] comment | ||
// reference, and not a [PrefixedIdentifier] or a [PropertyAccess]. | ||
element = result.setter; | ||
} | ||
element ??= result.getter; | ||
} | ||
return element; | ||
} | ||
|
||
void _resolveSimpleIdentifierReference( | ||
SimpleIdentifierImpl expression, { | ||
required bool hasNewKeyword, | ||
}) { | ||
var element = _resolveSimpleIdentifier(expression); | ||
if (element == null) { | ||
return; | ||
} | ||
expression.staticElement = element; | ||
if (hasNewKeyword) { | ||
if (element is ClassElement) { | ||
var constructor = element.unnamedConstructor; | ||
if (constructor == null) { | ||
// TODO(brianwilkerson) Report this error. | ||
} else { | ||
expression.staticElement = constructor; | ||
} | ||
} else { | ||
// TODO(brianwilkerson) Report this error. | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.