Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(626)

Unified Diff: pkg/analyzer_experimental/lib/src/generated/resolver.dart

Issue 16337007: Version 0.5.13.1 . (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer_experimental/lib/src/generated/resolver.dart
===================================================================
--- pkg/analyzer_experimental/lib/src/generated/resolver.dart (revision 23549)
+++ pkg/analyzer_experimental/lib/src/generated/resolver.dart (working copy)
@@ -13,26 +13,22 @@
import 'utilities_dart.dart';
import 'ast.dart';
import 'parser.dart' show Parser, ParserErrorCode;
-import 'sdk.dart' show DartSdk;
-import 'element.dart' hide HideCombinator, ShowCombinator;
+import 'sdk.dart' show DartSdk, SdkLibrary;
+import 'element.dart' hide Annotation, HideCombinator, ShowCombinator;
import 'html.dart' as ht;
import 'engine.dart';
import 'constant.dart';
import 'element.dart' as __imp_combi show HideCombinator, ShowCombinator;
+
/**
* Instances of the class {@code CompilationUnitBuilder} build an element model for a single
* compilation unit.
* @coverage dart.engine.resolver
*/
class CompilationUnitBuilder {
+
/**
- * Initialize a newly created compilation unit element builder.
- * @param analysisContext the analysis context in which the element model will be built
- */
- CompilationUnitBuilder() : super() {
- }
- /**
* Build the compilation unit element for the given source.
* @param source the source describing the compilation unit
* @param unit the AST structure representing the compilation unit
@@ -57,28 +53,34 @@
return element;
}
}
+
/**
* Instances of the class {@code ElementBuilder} traverse an AST structure and build the element
* model representing the AST structure.
* @coverage dart.engine.resolver
*/
class ElementBuilder extends RecursiveASTVisitor<Object> {
+
/**
* The element holder associated with the element that is currently being built.
*/
ElementHolder _currentHolder;
+
/**
* A flag indicating whether a variable declaration is in the context of a field declaration.
*/
bool _inFieldContext = false;
+
/**
* A flag indicating whether a variable declaration is within the body of a method or function.
*/
bool _inFunction = false;
+
/**
* A flag indicating whether the class currently being visited can be used as a mixin.
*/
bool _isValidMixin = false;
+
/**
* Initialize a newly created element builder to build the elements for a compilation unit.
* @param initialHolder the element holder associated with the compilation unit being built
@@ -123,12 +125,7 @@
element.type = interfaceType;
List<ConstructorElement> constructors2 = holder.constructors;
if (constructors2.length == 0) {
- ConstructorElementImpl constructor = new ConstructorElementImpl(null);
- constructor.synthetic = true;
- FunctionTypeImpl type = new FunctionTypeImpl.con1(constructor);
- type.returnType = interfaceType;
- constructor.type = type;
- constructors2 = <ConstructorElement> [constructor];
+ constructors2 = createDefaultConstructors(interfaceType);
}
element.abstract = node.abstractKeyword != null;
element.accessors = holder.accessors;
@@ -153,6 +150,7 @@
InterfaceTypeImpl interfaceType = new InterfaceTypeImpl.con1(element);
interfaceType.typeArguments = createTypeVariableTypes(typeVariables2);
element.type = interfaceType;
+ element.constructors = createDefaultConstructors(interfaceType);
_currentHolder.addType(element);
className.element = element;
return null;
@@ -248,7 +246,6 @@
SimpleIdentifier parameterName = node.identifier;
FieldFormalParameterElementImpl parameter = new FieldFormalParameterElementImpl(parameterName);
parameter.const3 = node.isConst();
- parameter.initializingFormal = true;
parameter.final2 = node.isFinal();
parameter.parameterKind = node.kind;
_currentHolder.addParameter(parameter);
@@ -290,6 +287,7 @@
if (field == null) {
field = new FieldElementImpl.con2(node.name.name);
field.final2 = true;
+ field.static = true;
_currentHolder.addField(field);
}
if (matches(property, sc.Keyword.GET)) {
@@ -299,6 +297,7 @@
getter.localVariables = holder.localVariables;
getter.variable = field;
getter.getter = true;
+ getter.static = true;
field.getter = getter;
_currentHolder.addAccessor(getter);
propertyNameNode.element = getter;
@@ -310,6 +309,7 @@
setter.parameters = holder.parameters;
setter.variable = field;
setter.setter = true;
+ setter.static = true;
field.setter = setter;
field.final2 = false;
_currentHolder.addAccessor(setter);
@@ -395,6 +395,7 @@
} finally {
_inFunction = wasInFunction;
}
+ bool isStatic2 = node.isStatic();
sc.Token property = node.propertyKeyword;
if (property == null) {
SimpleIdentifier methodName = node.name;
@@ -408,7 +409,7 @@
element.labels = holder.labels;
element.localVariables = holder.localVariables;
element.parameters = holder.parameters;
- element.static = node.isStatic();
+ element.static = isStatic2;
_currentHolder.addMethod(element);
methodName.element = element;
} else {
@@ -418,7 +419,7 @@
if (field == null) {
field = new FieldElementImpl.con2(node.name.name);
field.final2 = true;
- field.static = matches(node.modifierKeyword, sc.Keyword.STATIC);
+ field.static = isStatic2;
_currentHolder.addField(field);
}
if (matches(property, sc.Keyword.GET)) {
@@ -427,7 +428,9 @@
getter.labels = holder.labels;
getter.localVariables = holder.localVariables;
getter.variable = field;
+ getter.abstract = node.body is EmptyFunctionBody && node.externalKeyword == null;
getter.getter = true;
+ getter.static = isStatic2;
field.getter = getter;
_currentHolder.addAccessor(getter);
propertyNameNode.element = getter;
@@ -438,7 +441,9 @@
setter.localVariables = holder.localVariables;
setter.parameters = holder.parameters;
setter.variable = field;
+ setter.abstract = node.body is EmptyFunctionBody && !matches(node.externalKeyword, sc.Keyword.EXTERNAL);
setter.setter = true;
+ setter.static = isStatic2;
field.setter = setter;
field.final2 = false;
_currentHolder.addAccessor(setter);
@@ -554,22 +559,38 @@
}
if (element is PropertyInducingElementImpl) {
PropertyInducingElementImpl variable = element as PropertyInducingElementImpl;
+ if (_inFieldContext) {
+ ((variable as FieldElementImpl)).static = matches(((node.parent.parent as FieldDeclaration)).keyword, sc.Keyword.STATIC);
+ }
PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.con2(variable);
getter.getter = true;
+ getter.static = variable.isStatic();
_currentHolder.addAccessor(getter);
variable.getter = getter;
if (!isFinal) {
PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.con2(variable);
setter.setter = true;
+ setter.static = variable.isStatic();
_currentHolder.addAccessor(setter);
variable.setter = setter;
}
- if (_inFieldContext) {
- ((variable as FieldElementImpl)).static = matches(((node.parent.parent as FieldDeclaration)).keyword, sc.Keyword.STATIC);
- }
}
return null;
}
+
+ /**
+ * Creates the {@link ConstructorElement}s array with the single default constructor element.
+ * @param interfaceType the interface type for which to create a default constructor
+ * @return the {@link ConstructorElement}s array with the single default constructor element
+ */
+ List<ConstructorElement> createDefaultConstructors(InterfaceTypeImpl interfaceType) {
+ ConstructorElementImpl constructor = new ConstructorElementImpl(null);
+ constructor.synthetic = true;
+ FunctionTypeImpl type = new FunctionTypeImpl.con1(constructor);
+ type.returnType = interfaceType;
+ constructor.type = type;
+ return <ConstructorElement> [constructor];
+ }
List<Type2> createTypeVariableTypes(List<TypeVariableElement> typeVariables) {
int typeVariableCount = typeVariables.length;
List<Type2> typeArguments = new List<Type2>(typeVariableCount);
@@ -581,6 +602,7 @@
}
return typeArguments;
}
+
/**
* Return the body of the function that contains the given parameter, or {@code null} if no
* function body could be found.
@@ -599,6 +621,7 @@
}
return null;
}
+
/**
* Return {@code true} if the given token is a token for the given keyword.
* @param token the token being tested
@@ -606,6 +629,7 @@
* @return {@code true} if the given token is a token for the given keyword
*/
bool matches(sc.Token token, sc.Keyword keyword2) => token != null && identical(token.type, sc.TokenType.KEYWORD) && identical(((token as sc.KeywordToken)).keyword, keyword2);
+
/**
* Make the given holder be the current holder while visiting the given node.
* @param holder the holder that will gather elements that are built while visiting the children
@@ -622,6 +646,7 @@
}
}
}
+
/**
* Make the given holder be the current holder while visiting the children of the given node.
* @param holder the holder that will gather elements that are built while visiting the children
@@ -639,6 +664,7 @@
}
}
}
+
/**
* Instances of the class {@code ElementHolder} hold on to elements created while traversing an AST
* structure so that they can be accessed when creating their enclosing element.
@@ -657,11 +683,6 @@
List<VariableElement> _topLevelVariables = new List<VariableElement>();
List<ClassElement> _types = new List<ClassElement>();
List<TypeVariableElement> _typeVariables = new List<TypeVariableElement>();
- /**
- * Initialize a newly created element holder.
- */
- ElementHolder() : super() {
- }
void addAccessor(PropertyAccessorElement element) {
_accessors.add(element);
}
@@ -779,6 +800,7 @@
return new List.from(_typeVariables);
}
}
+
/**
* Instances of the class {@code HtmlUnitBuilder} build an element model for a single HTML unit.
*/
@@ -788,35 +810,51 @@
static String _SCRIPT = "script";
static String _SRC = "src";
static String _TYPE = "type";
+
/**
* The analysis context in which the element model will be built.
*/
InternalAnalysisContext _context;
+
/**
* The error listener to which errors will be reported.
*/
- AnalysisErrorListener _errorListener;
+ RecordingErrorListener _errorListener;
+
/**
* The line information associated with the source for which an element is being built, or{@code null} if we are not building an element.
*/
LineInfo _lineInfo;
+
/**
* The HTML element being built.
*/
HtmlElementImpl _htmlElement;
+
/**
+ * The elements in the path from the HTML unit to the current tag node.
+ */
+ List<ht.XmlTagNode> _parentNodes;
+
+ /**
* The script elements being built.
*/
List<HtmlScriptElement> _scripts;
+
/**
+ * A set of the libraries that were resolved while resolving the HTML unit.
+ */
+ Set<Library> _resolvedLibraries = new Set<Library>();
+
+ /**
* Initialize a newly created HTML unit builder.
* @param context the analysis context in which the element model will be built
- * @param errorListener the error listener to which errors will be reported
*/
- HtmlUnitBuilder(InternalAnalysisContext context, AnalysisErrorListener errorListener) {
+ HtmlUnitBuilder(InternalAnalysisContext context) {
this._context = context;
- this._errorListener = errorListener;
+ this._errorListener = new RecordingErrorListener();
}
+
/**
* Build the HTML element for the given source.
* @param source the source describing the compilation unit
@@ -824,6 +862,7 @@
* @throws AnalysisException if the analysis could not be performed
*/
HtmlElementImpl buildHtmlElement(Source source) => buildHtmlElement2(source, _context.parseHtmlUnit(source));
+
/**
* Build the HTML element for the given source.
* @param source the source describing the compilation unit
@@ -840,62 +879,107 @@
unit.element = result;
return result;
}
+
+ /**
+ * Return the listener to which analysis errors will be reported.
+ * @return the listener to which analysis errors will be reported
+ */
+ RecordingErrorListener get errorListener => _errorListener;
+
+ /**
+ * Return an array containing information about all of the libraries that were resolved.
+ * @return an array containing the libraries that were resolved
+ */
+ Set<Library> get resolvedLibraries => _resolvedLibraries;
Object visitHtmlUnit(ht.HtmlUnit node) {
+ _parentNodes = new List<ht.XmlTagNode>();
_scripts = new List<HtmlScriptElement>();
- node.visitChildren(this);
- _htmlElement.scripts = new List.from(_scripts);
- _scripts = null;
+ try {
+ node.visitChildren(this);
+ _htmlElement.scripts = new List.from(_scripts);
+ } finally {
+ _scripts = null;
+ _parentNodes = null;
+ }
return null;
}
Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
Object visitXmlTagNode(ht.XmlTagNode node) {
- if (isScriptNode(node)) {
- Source htmlSource = _htmlElement.source;
- ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
- String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute.text;
- if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePath == null) {
- EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
- String contents = node.content;
- int attributeEnd2 = node.attributeEnd.end;
- LineInfo_Location location = _lineInfo.getLocation(attributeEnd2);
- sc.StringScanner scanner = new sc.StringScanner(htmlSource, contents, _errorListener);
- scanner.setSourceStart(location.lineNumber, location.columnNumber, attributeEnd2);
- sc.Token firstToken = scanner.tokenize();
- List<int> lineStarts2 = scanner.lineStarts;
- Parser parser = new Parser(null, _errorListener);
- CompilationUnit unit = parser.parseCompilationUnit(firstToken);
- unit.lineInfo = new LineInfo(lineStarts2);
- try {
- CompilationUnitBuilder builder = new CompilationUnitBuilder();
- CompilationUnitElementImpl elem = builder.buildCompilationUnit(htmlSource, unit);
- LibraryElementImpl library = new LibraryElementImpl(_context, null);
- library.definingCompilationUnit = elem;
- script.scriptLibrary = library;
- } on AnalysisException catch (exception) {
- print(exception);
+ if (_parentNodes.contains(node)) {
+ JavaStringBuilder builder = new JavaStringBuilder();
+ builder.append("Found circularity in XML nodes: ");
+ bool first = true;
+ for (ht.XmlTagNode pathNode in _parentNodes) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(", ");
}
- _scripts.add(script);
- } else {
- ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
- if (scriptSourcePath != null) {
+ String tagName = pathNode.tag.lexeme;
+ if (identical(pathNode, node)) {
+ builder.append("*");
+ builder.append(tagName);
+ builder.append("*");
+ } else {
+ builder.append(tagName);
+ }
+ }
+ AnalysisEngine.instance.logger.logError(builder.toString());
+ return null;
+ }
+ _parentNodes.add(node);
+ try {
+ if (isScriptNode(node)) {
+ Source htmlSource = _htmlElement.source;
+ ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
+ String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute.text;
+ if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePath == null) {
+ EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
+ String contents = node.content;
+ int attributeEnd2 = node.attributeEnd.end;
+ LineInfo_Location location = _lineInfo.getLocation(attributeEnd2);
+ sc.StringScanner scanner = new sc.StringScanner(htmlSource, contents, _errorListener);
+ scanner.setSourceStart(location.lineNumber, location.columnNumber, attributeEnd2);
+ sc.Token firstToken = scanner.tokenize();
+ List<int> lineStarts2 = scanner.lineStarts;
+ Parser parser = new Parser(htmlSource, _errorListener);
+ CompilationUnit unit = parser.parseCompilationUnit(firstToken);
+ unit.lineInfo = new LineInfo(lineStarts2);
try {
- Uri.parse(scriptSourcePath);
- Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
- script.scriptSource = scriptSource;
- if (!scriptSource.exists()) {
- reportError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute.offset + 1, scriptSourcePath.length, []);
+ LibraryResolver resolver = new LibraryResolver(_context);
+ LibraryElementImpl library = resolver.resolveEmbeddedLibrary(htmlSource, unit, true) as LibraryElementImpl;
+ script.scriptLibrary = library;
+ _resolvedLibraries.addAll(resolver.resolvedLibraries);
+ _errorListener.addAll(resolver.errorListener);
+ } on AnalysisException catch (exception) {
+ AnalysisEngine.instance.logger.logError3(exception);
+ }
+ _scripts.add(script);
+ } else {
+ ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
+ if (scriptSourcePath != null) {
+ try {
+ parseUriWithException(scriptSourcePath);
+ Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
+ script.scriptSource = scriptSource;
+ if (!scriptSource.exists()) {
+ reportError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute.offset + 1, scriptSourcePath.length, [scriptSourcePath]);
+ }
+ } on URISyntaxException catch (exception) {
+ reportError(HtmlWarningCode.INVALID_URI, scriptAttribute.offset + 1, scriptSourcePath.length, [scriptSourcePath]);
}
- } on URISyntaxException catch (exception) {
- reportError(HtmlWarningCode.INVALID_URI, scriptAttribute.offset + 1, scriptSourcePath.length, []);
}
+ _scripts.add(script);
}
- _scripts.add(script);
+ } else {
+ node.visitChildren(this);
}
- } else {
- node.visitChildren(this);
+ } finally {
+ _parentNodes.remove(node);
}
return null;
}
+
/**
* Return the first source attribute for the given tag node, or {@code null} if it does not exist.
* @param node the node containing attributes
@@ -909,6 +993,7 @@
}
return null;
}
+
/**
* Determine if the specified node is a Dart script.
* @param node the node to be tested (not {@code null})
@@ -931,6 +1016,7 @@
}
return false;
}
+
/**
* Report an error with the given error code at the given location. Use the given arguments to
* compose the error message.
@@ -943,41 +1029,43 @@
_errorListener.onError(new AnalysisError.con2(_htmlElement.source, offset, length, errorCode, arguments));
}
}
+
/**
* Instances of the class {@code DeclarationResolver} are used to resolve declarations in an AST
* structure to already built elements.
*/
class DeclarationResolver extends RecursiveASTVisitor<Object> {
+
/**
* The compilation unit containing the AST nodes being visited.
*/
CompilationUnitElement _enclosingUnit;
+
/**
* The function type alias containing the AST nodes being visited, or {@code null} if we are not
* in the scope of a function type alias.
*/
FunctionTypeAliasElement _enclosingAlias;
+
/**
* The class containing the AST nodes being visited, or {@code null} if we are not in the scope of
* a class.
*/
ClassElement _enclosingClass;
+
/**
* The method or function containing the AST nodes being visited, or {@code null} if we are not in
* the scope of a method or function.
*/
ExecutableElement _enclosingExecutable;
+
/**
* The parameter containing the AST nodes being visited, or {@code null} if we are not in the
* scope of a parameter.
*/
ParameterElement _enclosingParameter;
+
/**
- * Initialize a newly created resolver.
- */
- DeclarationResolver() : super() {
- }
- /**
* Resolve the declarations within the given compilation unit to the elements rooted at the given
* element.
* @param unit the compilation unit to be resolved
@@ -1297,6 +1385,7 @@
}
return super.visitVariableDeclaration(node);
}
+
/**
* Append the value of the given string literal to the given string builder.
* @param builder the builder to which the string's value is to be appended
@@ -1315,6 +1404,7 @@
throw new IllegalArgumentException();
}
}
+
/**
* Return the element for the part with the given source, or {@code null} if there is no element
* for the given source.
@@ -1330,6 +1420,7 @@
}
return null;
}
+
/**
* Return the element in the given array of elements that was created for the declaration at the
* given offset. This method should only be used when there is no name
@@ -1338,6 +1429,7 @@
* @return the element at the given offset
*/
Element find2(List<Element> elements, int offset) => find4(elements, "", offset);
+
/**
* Return the element in the given array of elements that was created for the declaration with the
* given name.
@@ -1350,6 +1442,7 @@
identifier.element = element;
return element;
}
+
/**
* Return the element in the given array of elements that was created for the declaration with the
* given name at the given offset.
@@ -1358,14 +1451,15 @@
* @param offset the offset of the name of the element to be returned
* @return the element with the given name and offset
*/
- Element find4(List<Element> elements, String name2, int offset) {
+ Element find4(List<Element> elements, String name, int offset) {
for (Element element in elements) {
- if (element.name == name2 && element.nameOffset == offset) {
+ if (element.displayName == name && element.nameOffset == offset) {
return element;
}
}
return null;
}
+
/**
* Return the export element from the given array whose library has the given source, or{@code null} if there is no such export.
* @param exports the export elements being searched
@@ -1381,6 +1475,7 @@
}
return null;
}
+
/**
* Return the import element from the given array whose library has the given source and that has
* the given prefix, or {@code null} if there is no such import.
@@ -1399,7 +1494,7 @@
return element;
}
} else {
- if (prefixElement != null && prefix2.name == prefixElement.name) {
+ if (prefixElement != null && prefix2.name == prefixElement.displayName) {
return element;
}
}
@@ -1407,6 +1502,7 @@
}
return null;
}
+
/**
* Return the value of the given string literal, or {@code null} if the string is not a constant
* string without any string interpolation.
@@ -1426,6 +1522,7 @@
return builder.toString().trim();
}
}
+
/**
* Instances of the class {@code ElementResolver} are used by instances of {@link ResolverVisitor}to resolve references within the AST structure to the elements being referenced. The requirements
* for the element resolver are:
@@ -1474,11 +1571,75 @@
* @coverage dart.engine.resolver
*/
class ElementResolver extends SimpleASTVisitor<Object> {
+
/**
+ * @return {@code true} if the given identifier is the return type of a constructor declaration.
+ */
+ static bool isConstructorReturnType(SimpleIdentifier node) {
+ ASTNode parent2 = node.parent;
+ if (parent2 is ConstructorDeclaration) {
+ ConstructorDeclaration constructor = parent2 as ConstructorDeclaration;
+ return identical(constructor.returnType, node);
+ }
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the given identifier is the return type of a factory constructor
+ * declaration.
+ */
+ static bool isFactoryConstructorReturnType(SimpleIdentifier node) {
+ ASTNode parent2 = node.parent;
+ if (parent2 is ConstructorDeclaration) {
+ ConstructorDeclaration constructor = parent2 as ConstructorDeclaration;
+ return identical(constructor.returnType, node) && constructor.factoryKeyword != null;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the given 'super' expression is used in the valid context.
+ * @param node the 'super' expression to analyze
+ * @return {@code true} if the given 'super' expression is in the valid context
+ */
+ static bool isSuperInValidContext(SuperExpression node) {
+ for (ASTNode n = node; n != null; n = n.parent) {
+ if (n is CompilationUnit) {
+ return false;
+ }
+ if (n is ConstructorDeclaration) {
+ ConstructorDeclaration constructor = n as ConstructorDeclaration;
+ return constructor.factoryKeyword == null;
+ }
+ if (n is ConstructorFieldInitializer) {
+ return false;
+ }
+ if (n is MethodDeclaration) {
+ MethodDeclaration method = n as MethodDeclaration;
+ return !method.isStatic();
+ }
+ }
+ return false;
+ }
+
+ /**
* The resolver driving this participant.
*/
ResolverVisitor _resolver;
+
/**
+ * The name of the method that can be implemented by a class to allow its instances to be invoked
+ * as if they were a function.
+ */
+ static String CALL_METHOD_NAME = "call";
+
+ /**
+ * The name of the method that will be invoked if an attempt is made to invoke an undefined method
+ * on an object.
+ */
+ static String _NO_SUCH_METHOD_METHOD_NAME = "noSuchMethod";
+
+ /**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param resolver the resolver driving this participant
*/
@@ -1486,18 +1647,21 @@
this._resolver = resolver;
}
Object visitAssignmentExpression(AssignmentExpression node) {
- sc.TokenType operator2 = node.operator.type;
- if (operator2 != sc.TokenType.EQ) {
- operator2 = operatorFromCompoundAssignment(operator2);
- Expression leftNode = node.leftHandSide;
- if (leftNode != null) {
- Type2 leftType = getType(leftNode);
- if (leftType != null) {
- MethodElement method = lookUpMethod(leftType, operator2.lexeme);
- if (method != null) {
- node.element = method;
- } else {
- }
+ sc.Token operator2 = node.operator;
+ sc.TokenType operatorType = operator2.type;
+ if (operatorType != sc.TokenType.EQ) {
+ operatorType = operatorFromCompoundAssignment(operatorType);
+ Expression leftHandSide2 = node.leftHandSide;
+ if (leftHandSide2 != null) {
+ String methodName = operatorType.lexeme;
+ Type2 staticType = getStaticType(leftHandSide2);
+ MethodElement staticMethod = lookUpMethod(leftHandSide2, staticType, methodName);
+ node.staticElement = staticMethod;
+ Type2 propagatedType = getPropagatedType(leftHandSide2);
+ MethodElement propagatedMethod = lookUpMethod(leftHandSide2, propagatedType, methodName);
+ node.element = select3(staticMethod, propagatedMethod);
+ if (shouldReportMissingMember(staticType, staticMethod) && (propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
+ _resolver.reportError6(StaticTypeWarningCode.UNDEFINED_METHOD, operator2, [methodName, staticType.displayName]);
}
}
}
@@ -1506,19 +1670,19 @@
Object visitBinaryExpression(BinaryExpression node) {
sc.Token operator2 = node.operator;
if (operator2.isUserDefinableOperator()) {
- Type2 leftType = getType(node.leftOperand);
- if (leftType == null || leftType.isDynamic()) {
- return null;
- } else if (leftType is FunctionType) {
- leftType = _resolver.typeProvider.functionType;
+ Expression leftOperand2 = node.leftOperand;
+ if (leftOperand2 != null) {
+ String methodName = operator2.lexeme;
+ Type2 staticType = getStaticType(leftOperand2);
+ MethodElement staticMethod = lookUpMethod(leftOperand2, staticType, methodName);
+ node.staticElement = staticMethod;
+ Type2 propagatedType = getPropagatedType(leftOperand2);
+ MethodElement propagatedMethod = lookUpMethod(leftOperand2, propagatedType, methodName);
+ node.element = select3(staticMethod, propagatedMethod);
+ if (shouldReportMissingMember(staticType, staticMethod) && (propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
+ _resolver.reportError6(StaticTypeWarningCode.UNDEFINED_OPERATOR, operator2, [methodName, staticType.displayName]);
+ }
}
- String methodName = operator2.lexeme;
- MethodElement member = lookUpMethod(leftType, methodName);
- if (member == null) {
- _resolver.reportError3(StaticWarningCode.UNDEFINED_OPERATOR, operator2, [methodName, leftType.name]);
- } else {
- node.element = member;
- }
}
return null;
}
@@ -1530,19 +1694,37 @@
}
return null;
}
+ Object visitClassDeclaration(ClassDeclaration node) {
+ setMetadata(node.element, node);
+ return null;
+ }
+ Object visitClassTypeAlias(ClassTypeAlias node) {
+ setMetadata(node.element, node);
+ return null;
+ }
Object visitCommentReference(CommentReference node) {
Identifier identifier2 = node.identifier;
if (identifier2 is SimpleIdentifier) {
SimpleIdentifier simpleIdentifier = identifier2 as SimpleIdentifier;
- visitSimpleIdentifier(simpleIdentifier);
- Element element2 = simpleIdentifier.element;
- if (element2 != null) {
- if (element2.library != _resolver.definingLibrary) {
+ Element element = resolveSimpleIdentifier(simpleIdentifier);
+ if (element == null) {
+ element = findImportWithoutPrefix(simpleIdentifier);
+ if (element is MultiplyDefinedElement) {
+ element = null;
}
+ }
+ if (element == null) {
+ } else {
+ if (element.library != _resolver.definingLibrary) {
+ }
+ recordResolution(simpleIdentifier, element);
if (node.newKeyword != null) {
- if (element2 is ClassElement) {
- ConstructorElement constructor = ((element2 as ClassElement)).unnamedConstructor;
- recordResolution(simpleIdentifier, constructor);
+ if (element is ClassElement) {
+ ConstructorElement constructor = ((element as ClassElement)).unnamedConstructor;
+ if (constructor == null) {
+ } else {
+ recordResolution(simpleIdentifier, constructor);
+ }
} else {
}
}
@@ -1551,33 +1733,41 @@
PrefixedIdentifier prefixedIdentifier = identifier2 as PrefixedIdentifier;
SimpleIdentifier prefix2 = prefixedIdentifier.prefix;
SimpleIdentifier name = prefixedIdentifier.identifier;
- visitSimpleIdentifier(prefix2);
- Element element3 = prefix2.element;
- if (element3 != null) {
- if (element3 is PrefixElement) {
- element3 = _resolver.nameScope.lookup(identifier2, _resolver.definingLibrary);
- recordResolution(name, element3);
+ Element element = resolveSimpleIdentifier(prefix2);
+ if (element == null) {
+ } else {
+ if (element is PrefixElement) {
+ recordResolution(prefix2, element);
+ element = _resolver.nameScope.lookup(identifier2, _resolver.definingLibrary);
+ recordResolution(name, element);
return null;
}
- if (element3.library != _resolver.definingLibrary) {
+ LibraryElement library2 = element.library;
+ if (library2 == null) {
+ AnalysisEngine.instance.logger.logError("Found element with null library: ${element.name}");
+ } else if (library2 != _resolver.definingLibrary) {
}
+ recordResolution(name, element);
if (node.newKeyword == null) {
- if (element3 is ClassElement) {
- Element memberElement = lookupGetterOrMethod(((element3 as ClassElement)).type, name.name);
+ if (element is ClassElement) {
+ Element memberElement = lookupGetterOrMethod(((element as ClassElement)).type, name.name);
if (memberElement == null) {
- memberElement = ((element3 as ClassElement)).getNamedConstructor(name.name);
+ memberElement = ((element as ClassElement)).getNamedConstructor(name.name);
+ if (memberElement == null) {
+ memberElement = lookUpSetter(prefix2, ((element as ClassElement)).type, name.name);
+ }
}
if (memberElement == null) {
- reportGetterOrSetterNotFound(prefixedIdentifier, name, element3.name);
} else {
recordResolution(name, memberElement);
}
} else {
}
} else {
- if (element3 is ClassElement) {
- ConstructorElement constructor = ((element3 as ClassElement)).getNamedConstructor(name.name);
- if (constructor != null) {
+ if (element is ClassElement) {
+ ConstructorElement constructor = ((element as ClassElement)).getNamedConstructor(name.name);
+ if (constructor == null) {
+ } else {
recordResolution(name, constructor);
}
} else {
@@ -1587,24 +1777,41 @@
}
return null;
}
+ Object visitConstructorDeclaration(ConstructorDeclaration node) {
+ super.visitConstructorDeclaration(node);
+ ConstructorElement element2 = node.element;
+ if (element2 is ConstructorElementImpl) {
+ ConstructorElementImpl constructorElement = element2 as ConstructorElementImpl;
+ ConstructorName redirectedNode = node.redirectedConstructor;
+ if (redirectedNode != null) {
+ ConstructorElement redirectedElement = redirectedNode.element;
+ constructorElement.redirectedConstructor = redirectedElement;
+ }
+ for (ConstructorInitializer initializer in node.initializers) {
+ if (initializer is RedirectingConstructorInvocation) {
+ ConstructorElement redirectedElement = ((initializer as RedirectingConstructorInvocation)).element;
+ constructorElement.redirectedConstructor = redirectedElement;
+ }
+ }
+ setMetadata(constructorElement, node);
+ }
+ return null;
+ }
Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
- FieldElement fieldElement = null;
SimpleIdentifier fieldName2 = node.fieldName;
ClassElement enclosingClass2 = _resolver.enclosingClass;
- fieldElement = ((enclosingClass2 as ClassElementImpl)).getField(fieldName2.name);
- if (fieldElement == null) {
+ FieldElement fieldElement = ((enclosingClass2 as ClassElementImpl)).getField(fieldName2.name);
+ recordResolution(fieldName2, fieldElement);
+ if (fieldElement == null || fieldElement.isSynthetic()) {
_resolver.reportError(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName2]);
- } else if (!fieldElement.isSynthetic()) {
- recordResolution(fieldName2, fieldElement);
- if (fieldElement.isStatic()) {
- _resolver.reportError(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName2]);
- }
+ } else if (fieldElement.isStatic()) {
+ _resolver.reportError(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName2]);
}
return null;
}
Object visitConstructorName(ConstructorName node) {
Type2 type2 = node.type.type;
- if (type2 is DynamicTypeImpl) {
+ if (type2 != null && type2.isDynamic()) {
return null;
} else if (type2 is! InterfaceType) {
ASTNode parent2 = node.parent;
@@ -1616,15 +1823,18 @@
}
return null;
}
- ClassElement classElement = ((type2 as InterfaceType)).element;
ConstructorElement constructor;
SimpleIdentifier name2 = node.name;
+ InterfaceType interfaceType = type2 as InterfaceType;
+ LibraryElement definingLibrary2 = _resolver.definingLibrary;
if (name2 == null) {
- constructor = classElement.unnamedConstructor;
+ constructor = interfaceType.lookUpConstructor(null, definingLibrary2);
} else {
- constructor = classElement.getNamedConstructor(name2.name);
+ constructor = interfaceType.lookUpConstructor(name2.name, definingLibrary2);
+ name2.staticElement = constructor;
name2.element = constructor;
}
+ node.staticElement = constructor;
node.element = constructor;
return null;
}
@@ -1636,10 +1846,15 @@
}
return null;
}
+ Object visitDeclaredIdentifier(DeclaredIdentifier node) {
+ setMetadata(node.element, node);
+ return null;
+ }
Object visitExportDirective(ExportDirective node) {
Element element2 = node.element;
if (element2 is ExportElement) {
resolveCombinators(((element2 as ExportElement)).exportedLibrary, node.combinators);
+ setMetadata(element2, node);
}
return null;
}
@@ -1648,37 +1863,51 @@
ClassElement classElement = _resolver.enclosingClass;
if (classElement != null) {
FieldElement fieldElement = ((classElement as ClassElementImpl)).getField(fieldName);
- if (fieldElement != null) {
- if (!fieldElement.isSynthetic()) {
- ParameterElement parameterElement = node.element;
- if (parameterElement is FieldFormalParameterElementImpl) {
- FieldFormalParameterElementImpl fieldFormal = parameterElement as FieldFormalParameterElementImpl;
- fieldFormal.field = fieldElement;
- Type2 declaredType = fieldFormal.type;
- Type2 fieldType = fieldElement.type;
- if (node.type == null) {
- fieldFormal.type = fieldType;
- }
- if (fieldElement.isStatic()) {
- _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
- } else if (declaredType != null && fieldType != null && !declaredType.isAssignableTo(fieldType)) {
- _resolver.reportError(StaticWarningCode.FIELD_INITIALIZER_WITH_INVALID_TYPE, node, [declaredType.name, fieldType.name]);
- }
+ if (fieldElement == null) {
+ _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ } else {
+ ParameterElement parameterElement = node.element;
+ if (parameterElement is FieldFormalParameterElementImpl) {
+ FieldFormalParameterElementImpl fieldFormal = parameterElement as FieldFormalParameterElementImpl;
+ fieldFormal.field = fieldElement;
+ Type2 declaredType = fieldFormal.type;
+ Type2 fieldType = fieldElement.type;
+ if (node.type == null) {
+ fieldFormal.type = fieldType;
}
+ if (fieldElement.isSynthetic()) {
+ _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ } else if (fieldElement.isStatic()) {
+ _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
+ } else if (declaredType != null && fieldType != null && !declaredType.isAssignableTo(fieldType)) {
+ _resolver.reportError(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
+ }
+ } else {
+ if (fieldElement.isSynthetic()) {
+ _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ } else if (fieldElement.isStatic()) {
+ _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
+ }
}
- } else {
- _resolver.reportError(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
}
}
return super.visitFieldFormalParameter(node);
}
+ Object visitFunctionDeclaration(FunctionDeclaration node) {
+ setMetadata(node.element, node);
+ return null;
+ }
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) => null;
+ Object visitFunctionTypeAlias(FunctionTypeAlias node) {
+ setMetadata(node.element, node);
+ return null;
+ }
Object visitImportDirective(ImportDirective node) {
SimpleIdentifier prefixNode = node.prefix;
if (prefixNode != null) {
String prefixName = prefixNode.name;
for (PrefixElement prefixElement in _resolver.definingLibrary.prefixes) {
- if (prefixElement.name == prefixName) {
+ if (prefixElement.displayName == prefixName) {
recordResolution(prefixNode, prefixElement);
break;
}
@@ -1686,177 +1915,160 @@
}
Element element2 = node.element;
if (element2 is ImportElement) {
- resolveCombinators(((element2 as ImportElement)).importedLibrary, node.combinators);
+ ImportElement importElement = element2 as ImportElement;
+ LibraryElement library = importElement.importedLibrary;
+ if (library != null) {
+ resolveCombinators(library, node.combinators);
+ }
+ setMetadata(element2, node);
}
return null;
}
Object visitIndexExpression(IndexExpression node) {
- Type2 arrayType = getType(node.realTarget);
- if (arrayType == null || arrayType.isDynamic()) {
- return null;
+ Expression target = node.realTarget;
+ Type2 staticType = getStaticType(target);
+ Type2 propagatedType = getPropagatedType(target);
+ if (node.inGetterContext()) {
+ String methodName = sc.TokenType.INDEX.lexeme;
+ bool error = lookUpCheckIndexOperator(node, target, methodName, staticType, propagatedType);
+ if (error) {
+ return null;
+ }
}
- String operator;
if (node.inSetterContext()) {
- operator = sc.TokenType.INDEX_EQ.lexeme;
- } else {
- operator = sc.TokenType.INDEX.lexeme;
+ String methodName = sc.TokenType.INDEX_EQ.lexeme;
+ lookUpCheckIndexOperator(node, target, methodName, staticType, propagatedType);
}
- MethodElement member = lookUpMethod(arrayType, operator);
- if (member == null) {
- _resolver.reportError(StaticWarningCode.UNDEFINED_OPERATOR, node, [operator, arrayType.name]);
- } else {
- node.element = member;
- }
return null;
}
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
ConstructorElement invokedConstructor = node.constructorName.element;
+ node.staticElement = invokedConstructor;
node.element = invokedConstructor;
- resolveNamedArguments(node.argumentList, invokedConstructor);
+ resolveArgumentsToParameters(node.isConst(), node.argumentList, invokedConstructor);
return null;
}
+ Object visitLibraryDirective(LibraryDirective node) {
+ setMetadata(node.element, node);
+ return null;
+ }
+ Object visitMethodDeclaration(MethodDeclaration node) {
+ setMetadata(node.element, node);
+ return null;
+ }
Object visitMethodInvocation(MethodInvocation node) {
SimpleIdentifier methodName2 = node.methodName;
Expression target = node.realTarget;
- Element element;
+ Element staticElement;
+ Element propagatedElement;
+ if (target is SuperExpression && !isSuperInValidContext((target as SuperExpression))) {
+ return null;
+ }
if (target == null) {
- element = _resolver.nameScope.lookup(methodName2, _resolver.definingLibrary);
- if (element == null) {
- ClassElement enclosingClass2 = _resolver.enclosingClass;
- if (enclosingClass2 != null) {
- InterfaceType enclosingType = enclosingClass2.type;
- element = lookUpMethod(enclosingType, methodName2.name);
- if (element == null) {
- PropertyAccessorElement getter = lookUpGetter(enclosingType, methodName2.name);
- if (getter != null) {
- FunctionType getterType = getter.type;
- if (getterType != null) {
- Type2 returnType2 = getterType.returnType;
- if (!isExecutableType(returnType2)) {
- _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
- }
- }
- recordResolution(methodName2, getter);
- return null;
- }
+ staticElement = resolveInvokedElement2(methodName2);
+ propagatedElement = null;
+ } else {
+ Type2 targetType = getStaticType(target);
+ staticElement = resolveInvokedElement(target, targetType, methodName2);
+ propagatedElement = resolveInvokedElement(target, getPropagatedType(target), methodName2);
+ }
+ staticElement = convertSetterToGetter(staticElement);
+ propagatedElement = convertSetterToGetter(propagatedElement);
+ Element recordedElement = recordResolution2(methodName2, staticElement, propagatedElement);
+ if (recordedElement is PropertyAccessorElement) {
+ FunctionType getterType = ((recordedElement as PropertyAccessorElement)).type;
+ if (getterType != null) {
+ Type2 getterReturnType = getterType.returnType;
+ if (getterReturnType is InterfaceType) {
+ MethodElement callMethod = ((getterReturnType as InterfaceType)).lookUpMethod(CALL_METHOD_NAME, _resolver.definingLibrary);
+ if (callMethod != null) {
+ resolveArgumentsToParameters(false, node.argumentList, callMethod);
}
+ } else if (getterReturnType is FunctionType) {
+ Element functionElement = ((getterReturnType as FunctionType)).element;
+ if (functionElement is ExecutableElement) {
+ resolveArgumentsToParameters(false, node.argumentList, (functionElement as ExecutableElement));
+ }
}
}
- } else {
- Type2 targetType = getType(target);
- if (targetType is InterfaceType) {
- InterfaceType classType = targetType as InterfaceType;
- element = lookUpMethod(classType, methodName2.name);
- if (element == null) {
- PropertyAccessorElement accessor = classType.getGetter(methodName2.name);
- if (accessor != null) {
- Type2 returnType3 = accessor.type.returnType;
- if (!isExecutableType(returnType3)) {
- _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
- return null;
- }
- element = accessor;
- }
+ } else if (recordedElement is ExecutableElement) {
+ resolveArgumentsToParameters(false, node.argumentList, (recordedElement as ExecutableElement));
+ } else if (recordedElement is VariableElement) {
+ VariableElement variable = recordedElement as VariableElement;
+ Type2 type2 = variable.type;
+ if (type2 is FunctionType) {
+ FunctionType functionType = type2 as FunctionType;
+ List<ParameterElement> parameters2 = functionType.parameters;
+ resolveArgumentsToParameters2(false, node.argumentList, parameters2);
+ } else if (type2 is InterfaceType) {
+ MethodElement callMethod = ((type2 as InterfaceType)).lookUpMethod(CALL_METHOD_NAME, _resolver.definingLibrary);
+ if (callMethod != null) {
+ List<ParameterElement> parameters3 = callMethod.parameters;
+ resolveArgumentsToParameters2(false, node.argumentList, parameters3);
}
- if (element == null && target is SuperExpression) {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, methodName2, [methodName2.name, targetType.element.name]);
- return null;
- }
- } else if (target is SimpleIdentifier) {
- Element targetElement = ((target as SimpleIdentifier)).element;
- if (targetElement is PrefixElement) {
- String name3 = "${((target as SimpleIdentifier)).name}.${methodName2}";
- Identifier functionName = new Identifier_8(name3);
- element = _resolver.nameScope.lookup(functionName, _resolver.definingLibrary);
- } else {
- return null;
- }
- } else {
- return null;
}
}
- ExecutableElement invokedMethod = null;
- if (element is PropertyAccessorElement) {
- PropertyAccessorElement getter = element as PropertyAccessorElement;
- FunctionType getterType = getter.type;
- if (getterType != null) {
- Type2 returnType4 = getterType.returnType;
- if (!isExecutableType(returnType4)) {
- _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
- }
+ ErrorCode errorCode;
+ if (staticElement == null) {
+ if (propagatedElement == null) {
+ errorCode = checkForInvocationError(target, staticElement);
+ } else {
+ errorCode = checkForInvocationError(target, propagatedElement);
}
- recordResolution(methodName2, element);
- return null;
- } else if (element is ExecutableElement) {
- invokedMethod = element as ExecutableElement;
} else {
- if (element is PropertyInducingElement) {
- PropertyAccessorElement getter2 = ((element as PropertyInducingElement)).getter;
- FunctionType getterType = getter2.type;
- if (getterType != null) {
- Type2 returnType5 = getterType.returnType;
- if (!isExecutableType(returnType5)) {
- _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
- }
- }
- recordResolution(methodName2, element);
- return null;
- } else if (element is VariableElement) {
- Type2 variableType = _resolver.overrideManager.getType(element);
- if (variableType == null) {
- variableType = ((element as VariableElement)).type;
- }
- if (!isExecutableType(variableType)) {
- _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
- }
- recordResolution(methodName2, element);
- return null;
+ errorCode = checkForInvocationError(target, staticElement);
+ if (propagatedElement != null) {
+ ErrorCode propagatedError = checkForInvocationError(target, propagatedElement);
+ errorCode = select(errorCode, propagatedError);
+ }
+ }
+ if (identical(errorCode, StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION)) {
+ _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
+ } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_FUNCTION)) {
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_FUNCTION, methodName2, [methodName2.name]);
+ } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
+ String targetTypeName;
+ if (target == null) {
+ ClassElement enclosingClass2 = _resolver.enclosingClass;
+ targetTypeName = enclosingClass2.displayName;
} else {
- if (target == null) {
- ClassElement enclosingClass3 = _resolver.enclosingClass;
- if (enclosingClass3 == null) {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_FUNCTION, methodName2, [methodName2.name]);
- } else if (element == null) {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_METHOD, methodName2, [methodName2.name, enclosingClass3.name]);
- } else {
- _resolver.reportError(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName2, [methodName2.name]);
- }
- } else {
- Type2 targetType = getType(target);
- String targetTypeName = targetType == null ? null : targetType.name;
- if (targetTypeName == null) {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_FUNCTION, methodName2, [methodName2.name]);
- } else {
- if (!doesClassDeclareNoSuchMethod(targetType.element)) {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_METHOD, methodName2, [methodName2.name, targetTypeName]);
- }
- }
+ Type2 targetType = getPropagatedType(target);
+ if (targetType == null) {
+ targetType = getStaticType(target);
}
- return null;
+ targetTypeName = targetType == null ? null : targetType.displayName;
}
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_METHOD, methodName2, [methodName2.name, targetTypeName]);
+ } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_SUPER_METHOD)) {
+ Type2 targetType = getPropagatedType(target);
+ if (targetType == null) {
+ targetType = getStaticType(target);
+ }
+ String targetTypeName = targetType == null ? null : targetType.name;
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, methodName2, [methodName2.name, targetTypeName]);
}
- recordResolution(methodName2, invokedMethod);
- resolveNamedArguments(node.argumentList, invokedMethod);
return null;
}
+ Object visitPartDirective(PartDirective node) {
+ setMetadata(node.element, node);
+ return null;
+ }
+ Object visitPartOfDirective(PartOfDirective node) {
+ setMetadata(node.element, node);
+ return null;
+ }
Object visitPostfixExpression(PostfixExpression node) {
- sc.Token operator2 = node.operator;
- Type2 operandType = getType(node.operand);
- if (operandType == null || operandType.isDynamic()) {
- return null;
+ Expression operand2 = node.operand;
+ String methodName = getPostfixOperator(node);
+ Type2 staticType = getStaticType(operand2);
+ MethodElement staticMethod = lookUpMethod(operand2, staticType, methodName);
+ node.staticElement = staticMethod;
+ Type2 propagatedType = getPropagatedType(operand2);
+ MethodElement propagatedMethod = lookUpMethod(operand2, propagatedType, methodName);
+ node.element = select3(staticMethod, propagatedMethod);
+ if (shouldReportMissingMember(staticType, staticMethod) && (propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
+ _resolver.reportError6(StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [methodName, staticType.displayName]);
}
- String methodName;
- if (identical(operator2.type, sc.TokenType.PLUS_PLUS)) {
- methodName = sc.TokenType.PLUS.lexeme;
- } else {
- methodName = sc.TokenType.MINUS.lexeme;
- }
- MethodElement member = lookUpMethod(operandType, methodName);
- if (member == null) {
- _resolver.reportError3(StaticWarningCode.UNDEFINED_OPERATOR, operator2, [methodName, operandType.name]);
- } else {
- node.element = member;
- }
return null;
}
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
@@ -1868,138 +2080,46 @@
if (element == null) {
return null;
}
- recordResolution(identifier2, element);
- return null;
- }
- if (prefixElement is ClassElement) {
- Element memberElement;
- if (node.identifier.inSetterContext()) {
- memberElement = ((prefixElement as ClassElementImpl)).getSetter(identifier2.name);
- } else {
- memberElement = ((prefixElement as ClassElementImpl)).getGetter(identifier2.name);
- }
- if (memberElement == null) {
- MethodElement methodElement = lookUpMethod(((prefixElement as ClassElement)).type, identifier2.name);
- if (methodElement != null) {
- recordResolution(identifier2, methodElement);
- return null;
+ if (element is PropertyAccessorElement && identifier2.inSetterContext()) {
+ PropertyInducingElement variable2 = ((element as PropertyAccessorElement)).variable;
+ if (variable2 != null) {
+ PropertyAccessorElement setter2 = variable2.setter;
+ if (setter2 != null) {
+ element = setter2;
+ }
}
}
- if (memberElement == null) {
- reportGetterOrSetterNotFound(node, identifier2, prefixElement.name);
- } else {
- recordResolution(identifier2, memberElement);
- }
+ recordResolution(identifier2, element);
return null;
}
- Type2 variableType;
- if (prefixElement is PropertyAccessorElement) {
- PropertyAccessorElement accessor = prefixElement as PropertyAccessorElement;
- FunctionType type2 = accessor.type;
- if (type2 == null) {
- return null;
- }
- if (accessor.isGetter()) {
- variableType = type2.returnType;
- } else {
- variableType = type2.normalParameterTypes[0];
- }
- if (variableType == null || variableType.isDynamic()) {
- return null;
- }
- } else if (prefixElement is VariableElement) {
- variableType = _resolver.overrideManager.getType(prefixElement);
- if (variableType == null) {
- variableType = ((prefixElement as VariableElement)).type;
- }
- if (variableType == null || variableType.isDynamic()) {
- return null;
- }
- } else {
- return null;
- }
- PropertyAccessorElement memberElement = null;
- if (node.identifier.inSetterContext()) {
- memberElement = lookUpSetter(variableType, identifier2.name);
- }
- if (memberElement == null && node.identifier.inGetterContext()) {
- memberElement = lookUpGetter(variableType, identifier2.name);
- }
- if (memberElement == null) {
- MethodElement methodElement = lookUpMethod(variableType, identifier2.name);
- if (methodElement != null) {
- recordResolution(identifier2, methodElement);
- return null;
- }
- }
- if (memberElement == null) {
- reportGetterOrSetterNotFound(node, identifier2, variableType.element.name);
- } else {
- recordResolution(identifier2, memberElement);
- }
+ resolvePropertyAccess(prefix2, identifier2);
return null;
}
Object visitPrefixExpression(PrefixExpression node) {
sc.Token operator2 = node.operator;
sc.TokenType operatorType = operator2.type;
if (operatorType.isUserDefinableOperator() || identical(operatorType, sc.TokenType.PLUS_PLUS) || identical(operatorType, sc.TokenType.MINUS_MINUS)) {
- Type2 operandType = getType(node.operand);
- if (operandType == null || operandType.isDynamic()) {
- return null;
+ Expression operand2 = node.operand;
+ String methodName = getPrefixOperator(node);
+ Type2 staticType = getStaticType(operand2);
+ MethodElement staticMethod = lookUpMethod(operand2, staticType, methodName);
+ node.staticElement = staticMethod;
+ Type2 propagatedType = getPropagatedType(operand2);
+ MethodElement propagatedMethod = lookUpMethod(operand2, propagatedType, methodName);
+ node.element = select3(staticMethod, propagatedMethod);
+ if (shouldReportMissingMember(staticType, staticMethod) && (propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
+ _resolver.reportError6(StaticTypeWarningCode.UNDEFINED_OPERATOR, operator2, [methodName, staticType.displayName]);
}
- String methodName;
- if (identical(operatorType, sc.TokenType.PLUS_PLUS)) {
- methodName = sc.TokenType.PLUS.lexeme;
- } else if (identical(operatorType, sc.TokenType.MINUS_MINUS)) {
- methodName = sc.TokenType.MINUS.lexeme;
- } else if (identical(operatorType, sc.TokenType.MINUS)) {
- methodName = "unary-";
- } else {
- methodName = operator2.lexeme;
- }
- MethodElement member = lookUpMethod(operandType, methodName);
- if (member == null) {
- _resolver.reportError3(StaticWarningCode.UNDEFINED_OPERATOR, operator2, [methodName, operandType.name]);
- } else {
- node.element = member;
- }
}
return null;
}
Object visitPropertyAccess(PropertyAccess node) {
- Type2 targetType = getType(node.realTarget);
- if (targetType is! InterfaceType) {
+ Expression target = node.realTarget;
+ if (target is SuperExpression && !isSuperInValidContext((target as SuperExpression))) {
return null;
}
- SimpleIdentifier identifier = node.propertyName;
- PropertyAccessorElement memberElement = null;
- if (identifier.inSetterContext()) {
- memberElement = lookUpSetter(targetType, identifier.name);
- }
- if (memberElement == null && identifier.inGetterContext()) {
- memberElement = lookUpGetter(targetType, identifier.name);
- }
- if (memberElement == null) {
- MethodElement methodElement = lookUpMethod(targetType, identifier.name);
- if (methodElement != null) {
- recordResolution(identifier, methodElement);
- return null;
- }
- }
- if (memberElement == null) {
- if (!doesClassDeclareNoSuchMethod(targetType.element)) {
- if (identifier.inSetterContext()) {
- _resolver.reportError(StaticWarningCode.UNDEFINED_SETTER, identifier, [identifier.name, targetType.name]);
- } else if (identifier.inGetterContext()) {
- _resolver.reportError(StaticWarningCode.UNDEFINED_GETTER, identifier, [identifier.name, targetType.name]);
- } else {
- print("two ${identifier.name}");
- _resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, identifier, [identifier.name]);
- }
- }
- } else {
- recordResolution(identifier, memberElement);
- }
+ SimpleIdentifier propertyName2 = node.propertyName;
+ resolvePropertyAccess(target, propertyName2);
return null;
}
Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
@@ -2020,39 +2140,22 @@
if (name != null) {
recordResolution(name, element);
}
+ node.staticElement = element;
node.element = element;
- resolveNamedArguments(node.argumentList, element);
+ resolveArgumentsToParameters(false, node.argumentList, element);
return null;
}
Object visitSimpleIdentifier(SimpleIdentifier node) {
if (node.element != null) {
return null;
}
- Element element = _resolver.nameScope.lookup(node, _resolver.definingLibrary);
- if (element is PropertyAccessorElement && node.inSetterContext()) {
- PropertyInducingElement variable2 = ((element as PropertyAccessorElement)).variable;
- if (variable2 != null) {
- PropertyAccessorElement setter2 = variable2.setter;
- if (setter2 != null) {
- element = setter2;
- }
- }
- }
- ClassElement enclosingClass2 = _resolver.enclosingClass;
- if (element == null && enclosingClass2 != null) {
- InterfaceType enclosingType = enclosingClass2.type;
- if (element == null && node.inSetterContext()) {
- element = lookUpSetter(enclosingType, node.name);
- }
- if (element == null && node.inGetterContext()) {
- element = lookUpGetter(enclosingType, node.name);
- }
- if (element == null) {
- element = lookUpMethod(enclosingType, node.name);
- }
- }
- if (element == null) {
- if (!doesClassDeclareNoSuchMethod(enclosingClass2)) {
+ Element element = resolveSimpleIdentifier(node);
+ if (isFactoryConstructorReturnType(node) && element != _resolver.enclosingClass) {
+ _resolver.reportError(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node, []);
+ } else if (element == null) {
+ if (isConstructorReturnType(node)) {
+ _resolver.reportError(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
+ } else if (!classDeclaresNoSuchMethod(_resolver.enclosingClass)) {
_resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
}
}
@@ -2076,15 +2179,31 @@
element = superclass.getNamedConstructor(name.name);
}
if (element == null) {
+ if (name != null) {
+ _resolver.reportError(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [superclass.name, name]);
+ } else {
+ _resolver.reportError(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, node, [superclass.name]);
+ }
return null;
+ } else {
+ if (element.isFactory()) {
+ _resolver.reportError(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
+ }
}
if (name != null) {
recordResolution(name, element);
}
+ node.staticElement = element;
node.element = element;
- resolveNamedArguments(node.argumentList, element);
+ resolveArgumentsToParameters(false, node.argumentList, element);
return null;
}
+ Object visitSuperExpression(SuperExpression node) {
+ if (!isSuperInValidContext(node)) {
+ _resolver.reportError(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node, []);
+ }
+ return super.visitSuperExpression(node);
+ }
Object visitTypeParameter(TypeParameter node) {
TypeName bound2 = node.bound;
if (bound2 != null) {
@@ -2093,48 +2212,216 @@
variable.bound = bound2.type;
}
}
+ setMetadata(node.element, node);
return null;
}
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ setMetadata(node.element, node);
+ return null;
+ }
+
/**
- * Return {@code true} if the passed {@link Element} is a {@link ClassElement} that declares a
- * method "noSuchMethod".
- * @param element the {@link Element} to evaluate
- * @return {@code true} if the passed {@link Element} is a {@link ClassElement} that declares a
- * method "noSuchMethod"
+ * Generate annotation elements for each of the annotations in the given node list and add them to
+ * the given list of elements.
+ * @param annotationList the list of elements to which new elements are to be added
+ * @param annotations the AST nodes used to generate new elements
*/
- bool doesClassDeclareNoSuchMethod(Element element) {
- if (element == null) {
- return false;
+ void addAnnotations(List<AnnotationImpl> annotationList, NodeList<Annotation> annotations) {
+ for (Annotation annotationNode in annotations) {
+ Element resolvedElement = annotationNode.element;
+ if (resolvedElement != null) {
+ annotationList.add(new AnnotationImpl(resolvedElement));
+ }
}
- if (element is! ClassElementImpl) {
- return false;
+ }
+
+ /**
+ * Given that we have found code to invoke the given element, return the error code that should be
+ * reported, or {@code null} if no error should be reported.
+ * @param target the target of the invocation, or {@code null} if there was no target
+ * @param element the element to be invoked
+ * @return the error code that should be reported
+ */
+ ErrorCode checkForInvocationError(Expression target, Element element2) {
+ if (element2 is PropertyAccessorElement) {
+ FunctionType getterType = ((element2 as PropertyAccessorElement)).type;
+ if (getterType != null) {
+ Type2 returnType2 = getterType.returnType;
+ if (!isExecutableType(returnType2)) {
+ return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
+ }
+ }
+ } else if (element2 is ExecutableElement) {
+ return null;
+ } else if (element2 == null && target is SuperExpression) {
+ return StaticTypeWarningCode.UNDEFINED_SUPER_METHOD;
+ } else {
+ if (element2 is PropertyInducingElement) {
+ PropertyAccessorElement getter2 = ((element2 as PropertyInducingElement)).getter;
+ FunctionType getterType = getter2.type;
+ if (getterType != null) {
+ Type2 returnType3 = getterType.returnType;
+ if (!isExecutableType(returnType3)) {
+ return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
+ }
+ }
+ } else if (element2 is VariableElement) {
+ Type2 variableType = _resolver.overrideManager.getType(element2);
+ if (variableType == null) {
+ variableType = ((element2 as VariableElement)).type;
+ }
+ if (!isExecutableType(variableType)) {
+ return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
+ }
+ } else {
+ if (target == null) {
+ ClassElement enclosingClass2 = _resolver.enclosingClass;
+ if (enclosingClass2 == null) {
+ return StaticTypeWarningCode.UNDEFINED_FUNCTION;
+ } else if (element2 == null) {
+ if (!classDeclaresNoSuchMethod(enclosingClass2)) {
+ return StaticTypeWarningCode.UNDEFINED_METHOD;
+ }
+ } else {
+ return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
+ }
+ } else {
+ Type2 targetType = getStaticType(target);
+ if (targetType == null) {
+ return StaticTypeWarningCode.UNDEFINED_FUNCTION;
+ } else if (!targetType.isDynamic() && !classDeclaresNoSuchMethod2(targetType.element)) {
+ return StaticTypeWarningCode.UNDEFINED_METHOD;
+ }
+ }
+ }
}
- ClassElementImpl classElement = element as ClassElementImpl;
- MethodElement method = classElement.lookUpMethod("noSuchMethod", _resolver.definingLibrary);
- if (method == null) {
+ return null;
+ }
+
+ /**
+ * Return {@code true} if the given class declares a method named "noSuchMethod" and is not the
+ * class 'Object'.
+ * @param element the class being tested
+ * @return {@code true} if the given class declares a method named "noSuchMethod"
+ */
+ bool classDeclaresNoSuchMethod(ClassElement classElement) {
+ if (classElement == null) {
return false;
}
- return true;
+ MethodElement methodElement = classElement.lookUpMethod(_NO_SUCH_METHOD_METHOD_NAME, _resolver.definingLibrary);
+ return methodElement != null && methodElement.enclosingElement.supertype != null;
}
+
/**
- * Search through the array of parameters for a parameter whose name matches the given name.
- * Return the parameter with the given name, or {@code null} if there is no such parameter.
- * @param parameters the parameters being searched
- * @param name the name being searched for
- * @return the parameter with the given name
+ * Return {@code true} if the given element represents a class that declares a method named
+ * "noSuchMethod" and is not the class 'Object'.
+ * @param element the element being tested
+ * @return {@code true} if the given element represents a class that declares a method named
+ * "noSuchMethod"
*/
- ParameterElement findNamedParameter(List<ParameterElement> parameters, String name2) {
- for (ParameterElement parameter in parameters) {
- if (identical(parameter.parameterKind, ParameterKind.NAMED)) {
- String parameteName = parameter.name;
- if (parameteName != null && parameteName == name2) {
- return parameter;
+ bool classDeclaresNoSuchMethod2(Element element) {
+ if (element is ClassElement) {
+ return classDeclaresNoSuchMethod((element as ClassElement));
+ }
+ return false;
+ }
+
+ /**
+ * If the given element is a setter, return the getter associated with it. Otherwise, return the
+ * element unchanged.
+ * @param element the element to be normalized
+ * @return a non-setter element derived from the given element
+ */
+ Element convertSetterToGetter(Element element) {
+ if (element is PropertyAccessorElement) {
+ return ((element as PropertyAccessorElement)).variable.getter;
+ }
+ return element;
+ }
+
+ /**
+ * Look for any declarations of the given identifier that are imported using a prefix. Return the
+ * element that was found, or {@code null} if the name is not imported using a prefix.
+ * @param identifier the identifier that might have been imported using a prefix
+ * @return the element that was found
+ */
+ Element findImportWithoutPrefix(SimpleIdentifier identifier) {
+ Element element = null;
+ Scope nameScope2 = _resolver.nameScope;
+ LibraryElement definingLibrary2 = _resolver.definingLibrary;
+ for (ImportElement importElement in definingLibrary2.imports) {
+ PrefixElement prefixElement = importElement.prefix;
+ if (prefixElement != null) {
+ Identifier prefixedIdentifier = new ElementResolver_SyntheticIdentifier("${prefixElement.name}.${identifier.name}");
+ Element importedElement = nameScope2.lookup(prefixedIdentifier, definingLibrary2);
+ if (importedElement != null) {
+ if (element == null) {
+ element = importedElement;
+ } else {
+ element = new MultiplyDefinedElementImpl(definingLibrary2.context, element, importedElement);
+ }
}
}
}
- return null;
+ return element;
}
+
/**
+ * Return the name of the method invoked by the given postfix expression.
+ * @param node the postfix expression being invoked
+ * @return the name of the method invoked by the expression
+ */
+ String getPostfixOperator(PostfixExpression node) => (identical(node.operator.type, sc.TokenType.PLUS_PLUS)) ? sc.TokenType.PLUS.lexeme : sc.TokenType.MINUS.lexeme;
+
+ /**
+ * Return the name of the method invoked by the given postfix expression.
+ * @param node the postfix expression being invoked
+ * @return the name of the method invoked by the expression
+ */
+ String getPrefixOperator(PrefixExpression node) {
+ sc.Token operator2 = node.operator;
+ sc.TokenType operatorType = operator2.type;
+ if (identical(operatorType, sc.TokenType.PLUS_PLUS)) {
+ return sc.TokenType.PLUS.lexeme;
+ } else if (identical(operatorType, sc.TokenType.MINUS_MINUS)) {
+ return sc.TokenType.MINUS.lexeme;
+ } else if (identical(operatorType, sc.TokenType.MINUS)) {
+ return "unary-";
+ } else {
+ return operator2.lexeme;
+ }
+ }
+
+ /**
+ * Return the propagated type of the given expression that is to be used for type analysis.
+ * @param expression the expression whose type is to be returned
+ * @return the type of the given expression
+ */
+ Type2 getPropagatedType(Expression expression) {
+ Type2 propagatedType2 = resolveTypeVariable(expression.propagatedType);
+ if (propagatedType2 is FunctionType) {
+ propagatedType2 = _resolver.typeProvider.functionType;
+ }
+ return propagatedType2;
+ }
+
+ /**
+ * Return the static type of the given expression that is to be used for type analysis.
+ * @param expression the expression whose type is to be returned
+ * @return the type of the given expression
+ */
+ Type2 getStaticType(Expression expression) {
+ if (expression is NullLiteral) {
+ return _resolver.typeProvider.objectType;
+ }
+ Type2 staticType2 = resolveTypeVariable(expression.staticType);
+ if (staticType2 is FunctionType) {
+ staticType2 = _resolver.typeProvider.functionType;
+ }
+ return staticType2;
+ }
+
+ /**
* Return the element representing the superclass of the given class.
* @param targetClass the class whose superclass is to be returned
* @return the element representing the superclass of the given class
@@ -2146,18 +2433,8 @@
}
return superType.element;
}
+
/**
- * Return the type of the given expression that is to be used for type analysis.
- * @param expression the expression whose type is to be returned
- * @return the type of the given expression
- */
- Type2 getType(Expression expression) {
- if (expression is NullLiteral) {
- return _resolver.typeProvider.objectType;
- }
- return expression.staticType;
- }
- /**
* Return {@code true} if the given type represents an object that could be invoked using the call
* operator '()'.
* @param type the type being tested
@@ -2168,51 +2445,105 @@
return true;
} else if (type is InterfaceType) {
ClassElement classElement = ((type as InterfaceType)).element;
- MethodElement methodElement = classElement.lookUpMethod("call", _resolver.definingLibrary);
+ MethodElement methodElement = classElement.lookUpMethod(CALL_METHOD_NAME, _resolver.definingLibrary);
return methodElement != null;
}
return false;
}
+
/**
+ * Return {@code true} if the given element is a static element.
+ * @param element the element being tested
+ * @return {@code true} if the given element is a static element
+ */
+ bool isStatic(Element element) {
+ if (element is ExecutableElement) {
+ return ((element as ExecutableElement)).isStatic();
+ } else if (element is PropertyInducingElement) {
+ return ((element as PropertyInducingElement)).isStatic();
+ }
+ return false;
+ }
+
+ /**
+ * Looks up the method element with the given name for index expression, reports{@link StaticWarningCode#UNDEFINED_OPERATOR} if not found.
+ * @param node the index expression to resolve
+ * @param target the target of the expression
+ * @param methodName the name of the operator associated with the context of using of the given
+ * index expression
+ * @return {@code true} if and only if an error code is generated on the passed node
+ */
+ bool lookUpCheckIndexOperator(IndexExpression node, Expression target, String methodName, Type2 staticType, Type2 propagatedType) {
+ MethodElement staticMethod = lookUpMethod(target, staticType, methodName);
+ MethodElement propagatedMethod = lookUpMethod(target, propagatedType, methodName);
+ node.staticElement = staticMethod;
+ node.element = select3(staticMethod, propagatedMethod);
+ if (shouldReportMissingMember(staticType, staticMethod) && (propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
+ sc.Token leftBracket2 = node.leftBracket;
+ sc.Token rightBracket2 = node.rightBracket;
+ if (leftBracket2 == null || rightBracket2 == null) {
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_OPERATOR, node, [methodName, staticType.displayName]);
+ return true;
+ } else {
+ int offset2 = leftBracket2.offset;
+ int length = rightBracket2.offset - offset2 + 1;
+ _resolver.reportError5(StaticTypeWarningCode.UNDEFINED_OPERATOR, offset2, length, [methodName, staticType.displayName]);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Look up the getter with the given name in the given type. Return the element representing the
* getter that was found, or {@code null} if there is no getter with the given name.
+ * @param target the target of the invocation, or {@code null} if there is no target
* @param type the type in which the getter is defined
* @param getterName the name of the getter being looked up
* @return the element representing the getter that was found
*/
- PropertyAccessorElement lookUpGetter(Type2 type, String getterName) {
+ PropertyAccessorElement lookUpGetter(Expression target, Type2 type, String getterName) {
type = resolveTypeVariable(type);
if (type is InterfaceType) {
InterfaceType interfaceType = type as InterfaceType;
- PropertyAccessorElement accessor = interfaceType.lookUpGetter(getterName, _resolver.definingLibrary);
+ PropertyAccessorElement accessor;
+ if (target is SuperExpression) {
+ accessor = interfaceType.lookUpGetterInSuperclass(getterName, _resolver.definingLibrary);
+ } else {
+ accessor = interfaceType.lookUpGetter(getterName, _resolver.definingLibrary);
+ }
if (accessor != null) {
return accessor;
}
- return lookUpGetterInInterfaces(interfaceType, getterName, new Set<ClassElement>());
+ return lookUpGetterInInterfaces(interfaceType, false, getterName, new Set<ClassElement>());
}
return null;
}
+
/**
* Look up the getter with the given name in the interfaces implemented by the given type, either
* directly or indirectly. Return the element representing the getter that was found, or{@code null} if there is no getter with the given name.
* @param targetType the type in which the getter might be defined
+ * @param includeTargetType {@code true} if the search should include the target type
* @param getterName the name of the getter being looked up
* @param visitedInterfaces a set containing all of the interfaces that have been examined, used
* to prevent infinite recursion and to optimize the search
* @return the element representing the getter that was found
*/
- PropertyAccessorElement lookUpGetterInInterfaces(InterfaceType targetType, String getterName, Set<ClassElement> visitedInterfaces) {
+ PropertyAccessorElement lookUpGetterInInterfaces(InterfaceType targetType, bool includeTargetType, String getterName, Set<ClassElement> visitedInterfaces) {
ClassElement targetClass = targetType.element;
if (visitedInterfaces.contains(targetClass)) {
return null;
}
javaSetAdd(visitedInterfaces, targetClass);
- PropertyAccessorElement getter = targetType.getGetter(getterName);
- if (getter != null) {
- return getter;
+ if (includeTargetType) {
+ PropertyAccessorElement getter = targetType.getGetter(getterName);
+ if (getter != null) {
+ return getter;
+ }
}
for (InterfaceType interfaceType in targetType.interfaces) {
- getter = lookUpGetterInInterfaces(interfaceType, getterName, visitedInterfaces);
+ PropertyAccessorElement getter = lookUpGetterInInterfaces(interfaceType, true, getterName, visitedInterfaces);
if (getter != null) {
return getter;
}
@@ -2221,8 +2552,9 @@
if (superclass2 == null) {
return null;
}
- return lookUpGetterInInterfaces(superclass2, getterName, visitedInterfaces);
+ return lookUpGetterInInterfaces(superclass2, true, getterName, visitedInterfaces);
}
+
/**
* Look up the method or getter with the given name in the given type. Return the element
* representing the method or getter that was found, or {@code null} if there is no method or
@@ -2243,36 +2575,40 @@
if (member != null) {
return member;
}
- return lookUpGetterOrMethodInInterfaces(interfaceType, memberName, new Set<ClassElement>());
+ return lookUpGetterOrMethodInInterfaces(interfaceType, false, memberName, new Set<ClassElement>());
}
return null;
}
+
/**
* Look up the method or getter with the given name in the interfaces implemented by the given
* type, either directly or indirectly. Return the element representing the method or getter that
* was found, or {@code null} if there is no method or getter with the given name.
* @param targetType the type in which the method or getter might be defined
+ * @param includeTargetType {@code true} if the search should include the target type
* @param memberName the name of the method or getter being looked up
* @param visitedInterfaces a set containing all of the interfaces that have been examined, used
* to prevent infinite recursion and to optimize the search
* @return the element representing the method or getter that was found
*/
- ExecutableElement lookUpGetterOrMethodInInterfaces(InterfaceType targetType, String memberName, Set<ClassElement> visitedInterfaces) {
+ ExecutableElement lookUpGetterOrMethodInInterfaces(InterfaceType targetType, bool includeTargetType, String memberName, Set<ClassElement> visitedInterfaces) {
ClassElement targetClass = targetType.element;
if (visitedInterfaces.contains(targetClass)) {
return null;
}
javaSetAdd(visitedInterfaces, targetClass);
- ExecutableElement member = targetType.getMethod(memberName);
- if (member != null) {
- return member;
+ if (includeTargetType) {
+ ExecutableElement member = targetType.getMethod(memberName);
+ if (member != null) {
+ return member;
+ }
+ member = targetType.getGetter(memberName);
+ if (member != null) {
+ return member;
+ }
}
- member = targetType.getGetter(memberName);
- if (member != null) {
- return member;
- }
for (InterfaceType interfaceType in targetType.interfaces) {
- member = lookUpGetterOrMethodInInterfaces(interfaceType, memberName, visitedInterfaces);
+ ExecutableElement member = lookUpGetterOrMethodInInterfaces(interfaceType, true, memberName, visitedInterfaces);
if (member != null) {
return member;
}
@@ -2281,8 +2617,9 @@
if (superclass2 == null) {
return null;
}
- return lookUpGetterInInterfaces(superclass2, memberName, visitedInterfaces);
+ return lookUpGetterOrMethodInInterfaces(superclass2, true, memberName, visitedInterfaces);
}
+
/**
* Find the element corresponding to the given label node in the current label scope.
* @param parentNode the node containing the given label
@@ -2321,46 +2658,57 @@
}
return labelElement;
}
+
/**
* Look up the method with the given name in the given type. Return the element representing the
* method that was found, or {@code null} if there is no method with the given name.
+ * @param target the target of the invocation, or {@code null} if there is no target
* @param type the type in which the method is defined
* @param methodName the name of the method being looked up
* @return the element representing the method that was found
*/
- MethodElement lookUpMethod(Type2 type, String methodName) {
+ MethodElement lookUpMethod(Expression target, Type2 type, String methodName) {
type = resolveTypeVariable(type);
if (type is InterfaceType) {
InterfaceType interfaceType = type as InterfaceType;
- MethodElement method = interfaceType.lookUpMethod(methodName, _resolver.definingLibrary);
+ MethodElement method;
+ if (target is SuperExpression) {
+ method = interfaceType.lookUpMethodInSuperclass(methodName, _resolver.definingLibrary);
+ } else {
+ method = interfaceType.lookUpMethod(methodName, _resolver.definingLibrary);
+ }
if (method != null) {
return method;
}
- return lookUpMethodInInterfaces(interfaceType, methodName, new Set<ClassElement>());
+ return lookUpMethodInInterfaces(interfaceType, false, methodName, new Set<ClassElement>());
}
return null;
}
+
/**
* Look up the method with the given name in the interfaces implemented by the given type, either
* directly or indirectly. Return the element representing the method that was found, or{@code null} if there is no method with the given name.
* @param targetType the type in which the member might be defined
+ * @param includeTargetType {@code true} if the search should include the target type
* @param methodName the name of the method being looked up
* @param visitedInterfaces a set containing all of the interfaces that have been examined, used
* to prevent infinite recursion and to optimize the search
* @return the element representing the method that was found
*/
- MethodElement lookUpMethodInInterfaces(InterfaceType targetType, String methodName, Set<ClassElement> visitedInterfaces) {
+ MethodElement lookUpMethodInInterfaces(InterfaceType targetType, bool includeTargetType, String methodName, Set<ClassElement> visitedInterfaces) {
ClassElement targetClass = targetType.element;
if (visitedInterfaces.contains(targetClass)) {
return null;
}
javaSetAdd(visitedInterfaces, targetClass);
- MethodElement method = targetType.getMethod(methodName);
- if (method != null) {
- return method;
+ if (includeTargetType) {
+ MethodElement method = targetType.getMethod(methodName);
+ if (method != null) {
+ return method;
+ }
}
for (InterfaceType interfaceType in targetType.interfaces) {
- method = lookUpMethodInInterfaces(interfaceType, methodName, visitedInterfaces);
+ MethodElement method = lookUpMethodInInterfaces(interfaceType, true, methodName, visitedInterfaces);
if (method != null) {
return method;
}
@@ -2369,48 +2717,59 @@
if (superclass2 == null) {
return null;
}
- return lookUpMethodInInterfaces(superclass2, methodName, visitedInterfaces);
+ return lookUpMethodInInterfaces(superclass2, true, methodName, visitedInterfaces);
}
+
/**
* Look up the setter with the given name in the given type. Return the element representing the
* setter that was found, or {@code null} if there is no setter with the given name.
+ * @param target the target of the invocation, or {@code null} if there is no target
* @param type the type in which the setter is defined
* @param setterName the name of the setter being looked up
* @return the element representing the setter that was found
*/
- PropertyAccessorElement lookUpSetter(Type2 type, String setterName) {
+ PropertyAccessorElement lookUpSetter(Expression target, Type2 type, String setterName) {
type = resolveTypeVariable(type);
if (type is InterfaceType) {
InterfaceType interfaceType = type as InterfaceType;
- PropertyAccessorElement accessor = interfaceType.lookUpSetter(setterName, _resolver.definingLibrary);
+ PropertyAccessorElement accessor;
+ if (target is SuperExpression) {
+ accessor = interfaceType.lookUpSetterInSuperclass(setterName, _resolver.definingLibrary);
+ } else {
+ accessor = interfaceType.lookUpSetter(setterName, _resolver.definingLibrary);
+ }
if (accessor != null) {
return accessor;
}
- return lookUpSetterInInterfaces(interfaceType, setterName, new Set<ClassElement>());
+ return lookUpSetterInInterfaces(interfaceType, false, setterName, new Set<ClassElement>());
}
return null;
}
+
/**
* Look up the setter with the given name in the interfaces implemented by the given type, either
* directly or indirectly. Return the element representing the setter that was found, or{@code null} if there is no setter with the given name.
* @param targetType the type in which the setter might be defined
+ * @param includeTargetType {@code true} if the search should include the target type
* @param setterName the name of the setter being looked up
* @param visitedInterfaces a set containing all of the interfaces that have been examined, used
* to prevent infinite recursion and to optimize the search
* @return the element representing the setter that was found
*/
- PropertyAccessorElement lookUpSetterInInterfaces(InterfaceType targetType, String setterName, Set<ClassElement> visitedInterfaces) {
+ PropertyAccessorElement lookUpSetterInInterfaces(InterfaceType targetType, bool includeTargetType, String setterName, Set<ClassElement> visitedInterfaces) {
ClassElement targetClass = targetType.element;
if (visitedInterfaces.contains(targetClass)) {
return null;
}
javaSetAdd(visitedInterfaces, targetClass);
- PropertyAccessorElement setter = targetType.getGetter(setterName);
- if (setter != null) {
- return setter;
+ if (includeTargetType) {
+ PropertyAccessorElement setter = targetType.getSetter(setterName);
+ if (setter != null) {
+ return setter;
+ }
}
for (InterfaceType interfaceType in targetType.interfaces) {
- setter = lookUpSetterInInterfaces(interfaceType, setterName, visitedInterfaces);
+ PropertyAccessorElement setter = lookUpSetterInInterfaces(interfaceType, true, setterName, visitedInterfaces);
if (setter != null) {
return setter;
}
@@ -2419,8 +2778,9 @@
if (superclass2 == null) {
return null;
}
- return lookUpSetterInInterfaces(superclass2, setterName, visitedInterfaces);
+ return lookUpSetterInInterfaces(superclass2, true, setterName, visitedInterfaces);
}
+
/**
* Return the binary operator that is invoked by the given compound assignment operator.
* @param operator the assignment operator being mapped
@@ -2456,33 +2816,112 @@
AnalysisEngine.instance.logger.logError("Failed to map ${operator.lexeme} to it's corresponding operator");
return operator;
}
+
/**
* Record the fact that the given AST node was resolved to the given element.
* @param node the AST node that was resolved
* @param element the element to which the AST node was resolved
*/
void recordResolution(SimpleIdentifier node, Element element2) {
- if (element2 != null) {
- node.element = element2;
- }
+ node.staticElement = element2;
+ node.element = element2;
}
+
/**
- * Report the {@link StaticTypeWarningCode}s <code>UNDEFINED_SETTER</code> and <code>UNDEFINED_GETTER</code>.
- * @param node the prefixed identifier that gives the context to determine if the error on the
- * undefined identifier is a getter or a setter
- * @param identifier the identifier in the passed prefix identifier
- * @param typeName the name of the type of the left hand side of the passed prefixed identifier
+ * Record the fact that the given AST node was resolved to the given elements.
+ * @param node the AST node that was resolved
+ * @param staticElement the element to which the AST node was resolved using static type
+ * information
+ * @param propagatedElement the element to which the AST node was resolved using propagated type
+ * information
+ * @return the element that was associated with the node
*/
- void reportGetterOrSetterNotFound(PrefixedIdentifier node, SimpleIdentifier identifier2, String typeName) {
- Type2 targetType = getType(node);
- if (targetType != null && doesClassDeclareNoSuchMethod(targetType.element)) {
+ Element recordResolution2(SimpleIdentifier node, Element staticElement2, Element propagatedElement) {
+ node.staticElement = staticElement2;
+ Element element = propagatedElement == null ? staticElement2 : propagatedElement;
+ node.element = element;
+ return element;
+ }
+
+ /**
+ * Given a list of arguments and the element that will be invoked using those argument, compute
+ * the list of parameters that correspond to the list of arguments.
+ * @param reportError if {@code true} then compile-time error should be reported; if {@code false}then compile-time warning
+ * @param argumentList the list of arguments being passed to the element
+ * @param executableElement the element that will be invoked with the arguments
+ */
+ void resolveArgumentsToParameters(bool reportError, ArgumentList argumentList, ExecutableElement executableElement) {
+ if (executableElement == null) {
return;
}
- bool isSetterContext = node.identifier.inSetterContext();
- ErrorCode errorCode = isSetterContext ? StaticTypeWarningCode.UNDEFINED_SETTER : StaticTypeWarningCode.UNDEFINED_GETTER;
- _resolver.reportError(errorCode, identifier2, [identifier2.name, typeName]);
+ List<ParameterElement> parameters2 = executableElement.parameters;
+ resolveArgumentsToParameters2(reportError, argumentList, parameters2);
}
+
/**
+ * Given a list of arguments and the element that will be invoked using those argument, compute
+ * the list of parameters that correspond to the list of arguments.
+ * @param reportError if {@code true} then compile-time error should be reported; if {@code false}then compile-time warning
+ * @param argumentList the list of arguments being passed to the element
+ * @param parameters the of the function that will be invoked with the arguments
+ */
+ void resolveArgumentsToParameters2(bool reportError2, ArgumentList argumentList, List<ParameterElement> parameters) {
+ List<ParameterElement> requiredParameters = new List<ParameterElement>();
+ List<ParameterElement> positionalParameters = new List<ParameterElement>();
+ Map<String, ParameterElement> namedParameters = new Map<String, ParameterElement>();
+ for (ParameterElement parameter in parameters) {
+ ParameterKind kind = parameter.parameterKind;
+ if (identical(kind, ParameterKind.REQUIRED)) {
+ requiredParameters.add(parameter);
+ } else if (identical(kind, ParameterKind.POSITIONAL)) {
+ positionalParameters.add(parameter);
+ } else {
+ namedParameters[parameter.name] = parameter;
+ }
+ }
+ List<ParameterElement> unnamedParameters = new List<ParameterElement>.from(requiredParameters);
+ unnamedParameters.addAll(positionalParameters);
+ int unnamedParameterCount = unnamedParameters.length;
+ int unnamedIndex = 0;
+ NodeList<Expression> arguments2 = argumentList.arguments;
+ int argumentCount = arguments2.length;
+ List<ParameterElement> resolvedParameters = new List<ParameterElement>(argumentCount);
+ int positionalArgumentCount = 0;
+ Set<String> usedNames = new Set<String>();
+ for (int i = 0; i < argumentCount; i++) {
+ Expression argument = arguments2[i];
+ if (argument is NamedExpression) {
+ SimpleIdentifier nameNode = ((argument as NamedExpression)).name.label;
+ String name2 = nameNode.name;
+ ParameterElement element = namedParameters[name2];
+ if (element == null) {
+ ErrorCode errorCode = reportError2 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER : StaticWarningCode.UNDEFINED_NAMED_PARAMETER;
+ _resolver.reportError(errorCode, nameNode, [name2]);
+ } else {
+ resolvedParameters[i] = element;
+ recordResolution(nameNode, element);
+ }
+ if (!javaSetAdd(usedNames, name2)) {
+ _resolver.reportError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name2]);
+ }
+ } else {
+ positionalArgumentCount++;
+ if (unnamedIndex < unnamedParameterCount) {
+ resolvedParameters[i] = unnamedParameters[unnamedIndex++];
+ }
+ }
+ }
+ if (positionalArgumentCount < requiredParameters.length) {
+ ErrorCode errorCode = reportError2 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS;
+ _resolver.reportError(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
+ } else if (positionalArgumentCount > unnamedParameterCount) {
+ ErrorCode errorCode = reportError2 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS;
+ _resolver.reportError(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
+ }
+ argumentList.correspondingParameters = resolvedParameters;
+ }
+
+ /**
* Resolve the names in the given combinators in the scope of the given library.
* @param library the library that defines the names
* @param combinators the combinators containing the names to be resolved
@@ -2491,7 +2930,7 @@
if (library == null) {
return;
}
- Namespace namespace = new NamespaceBuilder().createExportNamespace(library);
+ Namespace namespace = new NamespaceBuilder().createExportNamespace2(library);
for (Combinator combinator in combinators) {
NodeList<SimpleIdentifier> names;
if (combinator is HideCombinator) {
@@ -2507,29 +2946,158 @@
}
}
}
+
/**
- * Resolve the names associated with any named arguments to the parameter elements named by the
- * argument.
- * @param argumentList the arguments to be resolved
- * @param invokedMethod the method or function defining the parameters to which the named
- * arguments are to be resolved
+ * Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the element being invoked.
+ * If the returned element is a method, then the method will be invoked. If the returned element
+ * is a getter, the getter will be invoked without arguments and the result of that invocation
+ * will then be invoked with the arguments.
+ * @param target the target of the invocation ('e')
+ * @param targetType the type of the target
+ * @param methodName the name of the method being invoked ('m')
+ * @return the element being invoked
*/
- void resolveNamedArguments(ArgumentList argumentList, ExecutableElement invokedMethod) {
- if (invokedMethod == null) {
- return;
+ Element resolveInvokedElement(Expression target, Type2 targetType, SimpleIdentifier methodName) {
+ if (targetType is InterfaceType) {
+ InterfaceType classType = targetType as InterfaceType;
+ Element element = lookUpMethod(target, classType, methodName.name);
+ if (element == null) {
+ element = classType.getGetter(methodName.name);
+ }
+ return element;
+ } else if (target is SimpleIdentifier) {
+ Element targetElement = ((target as SimpleIdentifier)).element;
+ if (targetElement is PrefixElement) {
+ String name2 = "${((target as SimpleIdentifier)).name}.${methodName}";
+ Identifier functionName = new ElementResolver_SyntheticIdentifier(name2);
+ Element element = _resolver.nameScope.lookup(functionName, _resolver.definingLibrary);
+ if (element != null) {
+ return element;
+ }
+ }
}
- List<ParameterElement> parameters2 = invokedMethod.parameters;
- for (Expression argument in argumentList.arguments) {
- if (argument is NamedExpression) {
- SimpleIdentifier name2 = ((argument as NamedExpression)).name.label;
- ParameterElement parameter = findNamedParameter(parameters2, name2.name);
- if (parameter != null) {
- recordResolution(name2, parameter);
+ return null;
+ }
+
+ /**
+ * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the element being invoked. If
+ * the returned element is a method, then the method will be invoked. If the returned element is a
+ * getter, the getter will be invoked without arguments and the result of that invocation will
+ * then be invoked with the arguments.
+ * @param methodName the name of the method being invoked ('m')
+ * @return the element being invoked
+ */
+ Element resolveInvokedElement2(SimpleIdentifier methodName) {
+ Element element = _resolver.nameScope.lookup(methodName, _resolver.definingLibrary);
+ if (element == null) {
+ ClassElement enclosingClass2 = _resolver.enclosingClass;
+ if (enclosingClass2 != null) {
+ InterfaceType enclosingType = enclosingClass2.type;
+ element = lookUpMethod(null, enclosingType, methodName.name);
+ if (element == null) {
+ element = lookUpGetter(null, enclosingType, methodName.name);
}
}
}
+ return element;
}
+
/**
+ * Given that we are accessing a property of the given type with the given name, return the
+ * element that represents the property.
+ * @param target the target of the invocation ('e')
+ * @param targetType the type in which the search for the property should begin
+ * @param propertyName the name of the property being accessed
+ * @return the element that represents the property
+ */
+ ExecutableElement resolveProperty(Expression target, Type2 targetType, SimpleIdentifier propertyName) {
+ ExecutableElement memberElement = null;
+ if (propertyName.inSetterContext()) {
+ memberElement = lookUpSetter(target, targetType, propertyName.name);
+ }
+ if (memberElement == null) {
+ memberElement = lookUpGetter(target, targetType, propertyName.name);
+ }
+ if (memberElement == null) {
+ memberElement = lookUpMethod(target, targetType, propertyName.name);
+ }
+ return memberElement;
+ }
+ void resolvePropertyAccess(Expression target, SimpleIdentifier propertyName) {
+ Type2 staticType = getStaticType(target);
+ ExecutableElement staticElement = resolveProperty(target, staticType, propertyName);
+ propertyName.staticElement = staticElement;
+ Type2 propagatedType = getPropagatedType(target);
+ ExecutableElement propagatedElement = resolveProperty(target, propagatedType, propertyName);
+ Element selectedElement = select2(staticElement, propagatedElement);
+ propertyName.element = selectedElement;
+ if (shouldReportMissingMember(staticType, staticElement) && (propagatedType == null || shouldReportMissingMember(propagatedType, propagatedElement))) {
+ bool staticNoSuchMethod = staticType != null && classDeclaresNoSuchMethod2(staticType.element);
+ bool propagatedNoSuchMethod = propagatedType != null && classDeclaresNoSuchMethod2(propagatedType.element);
+ if (!staticNoSuchMethod && !propagatedNoSuchMethod) {
+ bool isStaticProperty = isStatic(selectedElement);
+ if (propertyName.inSetterContext()) {
+ if (isStaticProperty) {
+ _resolver.reportError(StaticWarningCode.UNDEFINED_SETTER, propertyName, [propertyName.name, staticType.displayName]);
+ } else {
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_SETTER, propertyName, [propertyName.name, staticType.displayName]);
+ }
+ } else if (propertyName.inGetterContext()) {
+ if (isStaticProperty) {
+ _resolver.reportError(StaticWarningCode.UNDEFINED_GETTER, propertyName, [propertyName.name, staticType.displayName]);
+ } else {
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_GETTER, propertyName, [propertyName.name, staticType.displayName]);
+ }
+ } else {
+ _resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, [propertyName.name]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Resolve the given simple identifier if possible. Return the element to which it could be
+ * resolved, or {@code null} if it could not be resolved. This does not record the results of the
+ * resolution.
+ * @param node the identifier to be resolved
+ * @return the element to which the identifier could be resolved
+ */
+ Element resolveSimpleIdentifier(SimpleIdentifier node) {
+ Element element = _resolver.nameScope.lookup(node, _resolver.definingLibrary);
+ if (element is PropertyAccessorElement && node.inSetterContext()) {
+ PropertyInducingElement variable2 = ((element as PropertyAccessorElement)).variable;
+ if (variable2 != null) {
+ PropertyAccessorElement setter2 = variable2.setter;
+ if (setter2 == null) {
+ ClassElement enclosingClass2 = _resolver.enclosingClass;
+ if (enclosingClass2 != null) {
+ setter2 = lookUpSetter(null, enclosingClass2.type, node.name);
+ }
+ }
+ if (setter2 != null) {
+ element = setter2;
+ }
+ }
+ } else if (element == null && node.inSetterContext()) {
+ element = _resolver.nameScope.lookup(new ElementResolver_SyntheticIdentifier("${node.name}="), _resolver.definingLibrary);
+ }
+ ClassElement enclosingClass3 = _resolver.enclosingClass;
+ if (element == null && enclosingClass3 != null) {
+ InterfaceType enclosingType = enclosingClass3.type;
+ if (element == null && node.inSetterContext()) {
+ element = lookUpSetter(null, enclosingType, node.name);
+ }
+ if (element == null && node.inGetterContext()) {
+ element = lookUpGetter(null, enclosingType, node.name);
+ }
+ if (element == null) {
+ element = lookUpMethod(null, enclosingType, node.name);
+ }
+ }
+ return element;
+ }
+
+ /**
* If the given type is a type variable, resolve it to the type that should be used when looking
* up members. Otherwise, return the original type.
* @param type the type that is to be resolved if it is a type variable
@@ -2546,62 +3114,621 @@
}
return type;
}
+
+ /**
+ * Given two possible error codes for the same piece of code, one computed using static type
+ * information and the other using propagated type information, return the error code that should
+ * be reported, or {@code null} if no error should be reported.
+ * @param staticError the error code computed using static type information
+ * @param propagatedError the error code computed using propagated type information
+ * @return the error code that should be reported
+ */
+ ErrorCode select(ErrorCode staticError, ErrorCode propagatedError) {
+ if (staticError == null || propagatedError == null) {
+ return null;
+ }
+ return propagatedError;
+ }
+
+ /**
+ * Return the propagated element if it is not {@code null}, or the static element if it is.
+ * @param staticElement the element computed using static type information
+ * @param propagatedElement the element computed using propagated type information
+ * @return the more specific of the two elements
+ */
+ ExecutableElement select2(ExecutableElement staticElement, ExecutableElement propagatedElement) => propagatedElement != null ? propagatedElement : staticElement;
+
+ /**
+ * Return the propagated method if it is not {@code null}, or the static method if it is.
+ * @param staticMethod the method computed using static type information
+ * @param propagatedMethod the method computed using propagated type information
+ * @return the more specific of the two methods
+ */
+ MethodElement select3(MethodElement staticMethod, MethodElement propagatedMethod) => propagatedMethod != null ? propagatedMethod : staticMethod;
+
+ /**
+ * Given a node that can have annotations associated with it and the element to which that node
+ * has been resolved, create the annotations in the element model representing the annotations on
+ * the node.
+ * @param element the element to which the node has been resolved
+ * @param node the node that can have annotations associated with it
+ */
+ void setMetadata(Element element, AnnotatedNode node) {
+ if (element is! ElementImpl) {
+ return;
+ }
+ List<AnnotationImpl> annotationList = new List<AnnotationImpl>();
+ addAnnotations(annotationList, node.metadata);
+ if (node is VariableDeclaration && node.parent is VariableDeclarationList) {
+ VariableDeclarationList list = node.parent as VariableDeclarationList;
+ addAnnotations(annotationList, list.metadata);
+ if (list.parent is FieldDeclaration) {
+ FieldDeclaration fieldDeclaration = list.parent as FieldDeclaration;
+ addAnnotations(annotationList, fieldDeclaration.metadata);
+ } else if (list.parent is TopLevelVariableDeclaration) {
+ TopLevelVariableDeclaration variableDeclaration = list.parent as TopLevelVariableDeclaration;
+ addAnnotations(annotationList, variableDeclaration.metadata);
+ }
+ }
+ if (!annotationList.isEmpty) {
+ ((element as ElementImpl)).metadata = new List.from(annotationList);
+ }
+ }
+
+ /**
+ * Return {@code true} if we should report an error as a result of looking up a member in the
+ * given type and not finding any member.
+ * @param type the type in which we attempted to perform the look-up
+ * @param member the result of the look-up
+ * @return {@code true} if we should report an error
+ */
+ bool shouldReportMissingMember(Type2 type, ExecutableElement member) {
+ if (member != null || type == null || type.isDynamic()) {
+ return false;
+ }
+ if (type is InterfaceType) {
+ return !classDeclaresNoSuchMethod(((type as InterfaceType)).element);
+ }
+ return true;
+ }
}
-class Identifier_8 extends Identifier {
- String name3;
- Identifier_8(this.name3) : super();
+
+/**
+ * Instances of the class {@code SyntheticIdentifier} implement an identifier that can be used to
+ * look up names in the lexical scope when there is no identifier in the AST structure. There is
+ * no identifier in the AST when the parser could not distinguish between a method invocation and
+ * an invocation of a top-level function imported with a prefix.
+ */
+class ElementResolver_SyntheticIdentifier extends Identifier {
+
+ /**
+ * The name of the synthetic identifier.
+ */
+ String _name;
+
+ /**
+ * Initialize a newly created synthetic identifier to have the given name.
+ * @param name the name of the synthetic identifier
+ */
+ ElementResolver_SyntheticIdentifier(String name) {
+ this._name = name;
+ }
accept(ASTVisitor visitor) => null;
sc.Token get beginToken => null;
Element get element => null;
sc.Token get endToken => null;
- String get name => name3;
+ String get name => _name;
+ Element get staticElement => null;
void visitChildren(ASTVisitor<Object> visitor) {
}
}
+
/**
+ * Instances of the class {@code InheritanceManager} manage the knowledge of where class members
+ * (methods, getters & setters) are inherited from.
+ * @coverage dart.engine.resolver
+ */
+class InheritanceManager {
+
+ /**
+ * The {@link LibraryElement} that is managed by this manager.
+ */
+ LibraryElement _library;
+
+ /**
+ * This is a mapping between each {@link ClassElement} and a map between the {@link String} member
+ * names and the associated {@link ExecutableElement} in the mixin and superclass chain.
+ */
+ Map<ClassElement, Map<String, ExecutableElement>> _classLookup;
+
+ /**
+ * This is a mapping between each {@link ClassElement} and a map between the {@link String} member
+ * names and the associated {@link ExecutableElement} in the interface set.
+ */
+ Map<ClassElement, Map<String, ExecutableElement>> _interfaceLookup;
+
+ /**
+ * A map between each visited {@link ClassElement} and the set of {@link AnalysisError}s found on
+ * the class element.
+ */
+ Map<ClassElement, Set<AnalysisError>> _errorsInClassElement = new Map<ClassElement, Set<AnalysisError>>();
+
+ /**
+ * Initialize a newly created inheritance manager.
+ * @param library the library element context that the inheritance mappings are being generated
+ */
+ InheritanceManager(LibraryElement library) {
+ this._library = library;
+ _classLookup = new Map<ClassElement, Map<String, ExecutableElement>>();
+ _interfaceLookup = new Map<ClassElement, Map<String, ExecutableElement>>();
+ }
+
+ /**
+ * Return the set of {@link AnalysisError}s found on the passed {@link ClassElement}, or{@code null} if there are none.
+ * @param classElt the class element to query
+ * @return the set of {@link AnalysisError}s found on the passed {@link ClassElement}, or{@code null} if there are none
+ */
+ Set<AnalysisError> getErrors(ClassElement classElt) => _errorsInClassElement[classElt];
+
+ /**
+ * Get and return a mapping between the set of all string names of the members inherited from the
+ * passed {@link ClassElement} superclass hierarchy, and the associated {@link ExecutableElement}.
+ * @param classElt the class element to query
+ * @return a mapping between the set of all members inherited from the passed {@link ClassElement}superclass hierarchy, and the associated {@link ExecutableElement}
+ */
+ Map<String, ExecutableElement> getMapOfMembersInheritedFromClasses(ClassElement classElt) => computeClassChainLookupMap(classElt, new Set<ClassElement>());
+
+ /**
+ * Get and return a mapping between the set of all string names of the members inherited from the
+ * passed {@link ClassElement} interface hierarchy, and the associated {@link ExecutableElement}.
+ * @param classElt the class element to query
+ * @return a mapping between the set of all string names of the members inherited from the passed{@link ClassElement} interface hierarchy, and the associated {@link ExecutableElement}.
+ */
+ Map<String, ExecutableElement> getMapOfMembersInheritedFromInterfaces(ClassElement classElt) => computeInterfaceLookupMap(classElt, new Set<ClassElement>());
+
+ /**
+ * Given some {@link ClassElement class element} and some member name, this returns the{@link ExecutableElement executable element} that the class inherits from the mixins,
+ * superclasses or interfaces, that has the member name, if no member is inherited {@code null} is
+ * returned.
+ * @param classElt the class element to query
+ * @param memberName the name of the executable element to find and return
+ * @return the inherited executable element with the member name, or {@code null} if no such
+ * member exists
+ */
+ ExecutableElement lookupInheritance(ClassElement classElt, String memberName) {
+ if (memberName == null || memberName.isEmpty) {
+ return null;
+ }
+ ExecutableElement executable = computeClassChainLookupMap(classElt, new Set<ClassElement>())[memberName];
+ if (executable == null) {
+ return computeInterfaceLookupMap(classElt, new Set<ClassElement>())[memberName];
+ }
+ return executable;
+ }
+
+ /**
+ * Given some {@link ClassElement class element} and some member name, this returns the{@link ExecutableElement executable element} that the class either declares itself, or
+ * inherits, that has the member name, if no member is inherited {@code null} is returned.
+ * @param classElt the class element to query
+ * @param memberName the name of the executable element to find and return
+ * @return the inherited executable element with the member name, or {@code null} if no such
+ * member exists
+ */
+ ExecutableElement lookupMember(ClassElement classElt, String memberName) {
+ ExecutableElement element = lookupMemberInClass(classElt, memberName);
+ if (element != null) {
+ return element;
+ }
+ return lookupInheritance(classElt, memberName);
+ }
+
+ /**
+ * Set the new library element context.
+ * @param library the new library element
+ */
+ void set libraryElement(LibraryElement library2) {
+ this._library = library2;
+ }
+
+ /**
+ * This method takes some inherited {@link FunctionType}, and resolves all the parameterized types
+ * in the function type, dependent on the class in which it is being overridden.
+ * @param baseFunctionType the function type that is being overridden
+ * @param memberName the name of the member, this is used to lookup the inheritance path of the
+ * override
+ * @param definingType the type that is overriding the member
+ * @return the passed function type with any parameterized types substituted
+ */
+ FunctionType substituteTypeArgumentsInMemberFromInheritance(FunctionType baseFunctionType, String memberName, InterfaceType definingType) {
+ if (baseFunctionType == null) {
+ return baseFunctionType;
+ }
+ Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
+ computeInheritancePath(inheritancePath, definingType, memberName);
+ if (inheritancePath == null || inheritancePath.length < 2) {
+ return baseFunctionType;
+ }
+ FunctionType functionTypeToReturn = baseFunctionType;
+ InterfaceType lastType = inheritancePath.removeLast();
+ while (inheritancePath.length > 0) {
+ List<Type2> paramTypes = TypeVariableTypeImpl.getTypes(lastType.element.typeVariables);
+ List<Type2> argTypes = lastType.typeArguments;
+ functionTypeToReturn = functionTypeToReturn.substitute2(argTypes, paramTypes);
+ lastType = inheritancePath.removeLast();
+ }
+ return functionTypeToReturn;
+ }
+
+ /**
+ * Compute and return a mapping between the set of all string names of the members inherited from
+ * the passed {@link ClassElement} superclass hierarchy, and the associated{@link ExecutableElement}.
+ * @param classElt the class element to query
+ * @param visitedClasses a set of visited classes passed back into this method when it calls
+ * itself recursively
+ * @return a mapping between the set of all string names of the members inherited from the passed{@link ClassElement} superclass hierarchy, and the associated {@link ExecutableElement}
+ */
+ Map<String, ExecutableElement> computeClassChainLookupMap(ClassElement classElt, Set<ClassElement> visitedClasses) {
+ Map<String, ExecutableElement> resultMap = _classLookup[classElt];
+ if (resultMap != null) {
+ return resultMap;
+ } else {
+ resultMap = new Map<String, ExecutableElement>();
+ }
+ ClassElement superclassElt = null;
+ InterfaceType supertype2 = classElt.supertype;
+ if (supertype2 != null) {
+ superclassElt = supertype2.element;
+ } else {
+ _classLookup[classElt] = resultMap;
+ return resultMap;
+ }
+ if (superclassElt != null) {
+ if (!visitedClasses.contains(superclassElt)) {
+ javaSetAdd(visitedClasses, classElt);
+ resultMap = new Map<String, ExecutableElement>.from(computeClassChainLookupMap(superclassElt, visitedClasses));
+ } else {
+ _classLookup[superclassElt] = resultMap;
+ return resultMap;
+ }
+ recordMapWithClassMembers(resultMap, superclassElt);
+ }
+ List<InterfaceType> mixins2 = classElt.mixins;
+ for (int i = mixins2.length - 1; i >= 0; i--) {
+ ClassElement mixinElement = mixins2[i].element;
+ if (mixinElement != null) {
+ recordMapWithClassMembers(resultMap, mixinElement);
+ }
+ }
+ _classLookup[classElt] = resultMap;
+ return resultMap;
+ }
+
+ /**
+ * Compute and return the inheritance path given the context of a type and a member that is
+ * overridden in the inheritance path (for which the type is in the path).
+ * @param chain the inheritance path that is built up as this method calls itself recursively,
+ * when this method is called an empty {@link LinkedList} should be provided
+ * @param currentType the current type in the inheritance path
+ * @param memberName the name of the member that is being looked up the inheritance path
+ */
+ void computeInheritancePath(Queue<InterfaceType> chain, InterfaceType currentType, String memberName) {
+ chain.add(currentType);
+ ClassElement classElt = currentType.element;
+ InterfaceType supertype2 = classElt.supertype;
+ if (supertype2 == null) {
+ return;
+ }
+ if (chain.length != 1) {
+ if (lookupMemberInClass(classElt, memberName) != null) {
+ return;
+ }
+ }
+ List<InterfaceType> mixins2 = classElt.mixins;
+ for (int i = mixins2.length - 1; i >= 0; i--) {
+ ClassElement mixinElement = mixins2[i].element;
+ if (mixinElement != null) {
+ ExecutableElement elt = lookupMemberInClass(mixinElement, memberName);
+ if (elt != null) {
+ chain.add(mixins2[i]);
+ return;
+ }
+ }
+ }
+ ClassElement superclassElt = supertype2.element;
+ if (lookupMember(superclassElt, memberName) != null) {
+ computeInheritancePath(chain, supertype2, memberName);
+ return;
+ }
+ List<InterfaceType> interfaces2 = classElt.interfaces;
+ for (InterfaceType interfaceType in interfaces2) {
+ ClassElement interfaceElement = interfaceType.element;
+ if (interfaceElement != null && lookupMember(interfaceElement, memberName) != null) {
+ computeInheritancePath(chain, interfaceType, memberName);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Compute and return a mapping between the set of all string names of the members inherited from
+ * the passed {@link ClassElement} interface hierarchy, and the associated{@link ExecutableElement}.
+ * @param classElt the class element to query
+ * @param visitedInterfaces a set of visited classes passed back into this method when it calls
+ * itself recursively
+ * @return a mapping between the set of all string names of the members inherited from the passed{@link ClassElement} interface hierarchy, and the associated {@link ExecutableElement}
+ */
+ Map<String, ExecutableElement> computeInterfaceLookupMap(ClassElement classElt, Set<ClassElement> visitedInterfaces) {
+ Map<String, ExecutableElement> resultMap = _interfaceLookup[classElt];
+ if (resultMap != null) {
+ return resultMap;
+ } else {
+ resultMap = new Map<String, ExecutableElement>();
+ }
+ List<InterfaceType> interfaces2 = classElt.interfaces;
+ if (interfaces2.length == 0) {
+ _interfaceLookup[classElt] = resultMap;
+ return resultMap;
+ }
+ List<Map<String, ExecutableElement>> lookupMaps = new List<Map<String, ExecutableElement>>();
+ for (InterfaceType interfaceType in interfaces2) {
+ ClassElement interfaceElement = interfaceType.element;
+ if (interfaceElement != null) {
+ if (!visitedInterfaces.contains(interfaceElement)) {
+ javaSetAdd(visitedInterfaces, interfaceElement);
+ lookupMaps.add(computeInterfaceLookupMap(interfaceElement, visitedInterfaces));
+ } else {
+ Map<String, ExecutableElement> map = _interfaceLookup[classElt];
+ if (map != null) {
+ lookupMaps.add(map);
+ } else {
+ _interfaceLookup[interfaceElement] = resultMap;
+ return resultMap;
+ }
+ }
+ }
+ }
+ if (lookupMaps.length == 0) {
+ _interfaceLookup[classElt] = resultMap;
+ return resultMap;
+ }
+ Map<String, Set<ExecutableElement>> unionMap = new Map<String, Set<ExecutableElement>>();
+ for (Map<String, ExecutableElement> lookupMap in lookupMaps) {
+ for (MapEntry<String, ExecutableElement> entry in getMapEntrySet(lookupMap)) {
+ String key = entry.getKey();
+ if (!unionMap.containsKey(key)) {
+ Set<ExecutableElement> set = new Set<ExecutableElement>();
+ javaSetAdd(set, entry.getValue());
+ unionMap[key] = set;
+ } else {
+ javaSetAdd(unionMap[key], entry.getValue());
+ }
+ }
+ }
+ for (InterfaceType interfaceType in interfaces2) {
+ ClassElement interfaceElement = interfaceType.element;
+ if (interfaceElement != null) {
+ List<MethodElement> methods2 = interfaceElement.methods;
+ for (MethodElement method in methods2) {
+ if (method.isAccessibleIn(_library) && !method.isStatic()) {
+ String key = method.name;
+ if (!unionMap.containsKey(key)) {
+ Set<ExecutableElement> set = new Set<ExecutableElement>();
+ javaSetAdd(set, method);
+ unionMap[key] = set;
+ } else {
+ javaSetAdd(unionMap[key], method);
+ }
+ }
+ }
+ List<PropertyAccessorElement> accessors2 = interfaceElement.accessors;
+ for (PropertyAccessorElement accessor in accessors2) {
+ if (accessor.isAccessibleIn(_library) && !accessor.isStatic()) {
+ String key = accessor.name;
+ if (!unionMap.containsKey(key)) {
+ Set<ExecutableElement> set = new Set<ExecutableElement>();
+ javaSetAdd(set, accessor);
+ unionMap[key] = set;
+ } else {
+ javaSetAdd(unionMap[key], accessor);
+ }
+ }
+ }
+ }
+ }
+ for (MapEntry<String, Set<ExecutableElement>> entry in getMapEntrySet(unionMap)) {
+ String key = entry.getKey();
+ Set<ExecutableElement> set = entry.getValue();
+ int numOfEltsWithMatchingNames = set.length;
+ if (numOfEltsWithMatchingNames == 1) {
+ resultMap[key] = new JavaIterator(set).next();
+ } else {
+ bool allMethods = true;
+ bool allSetters = true;
+ bool allGetters = true;
+ for (ExecutableElement executableElement in set) {
+ if (executableElement is PropertyAccessorElement) {
+ allMethods = false;
+ if (((executableElement as PropertyAccessorElement)).isSetter()) {
+ allGetters = false;
+ } else {
+ allSetters = false;
+ }
+ } else {
+ allGetters = false;
+ allSetters = false;
+ }
+ }
+ if (allMethods || allGetters || allSetters) {
+ List<ExecutableElement> elements = new List.from(set);
+ List<FunctionType> executableElementTypes = new List<FunctionType>(numOfEltsWithMatchingNames);
+ for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
+ executableElementTypes[i] = elements[i].type;
+ }
+ bool foundSubtypeOfAllTypes = true;
+ for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
+ FunctionType subtype = executableElementTypes[i];
+ if (subtype == null) {
+ continue;
+ }
+ bool subtypeOfAllTypes = true;
+ for (int j = 0; j < numOfEltsWithMatchingNames && subtypeOfAllTypes; j++) {
+ if (i != j) {
+ if (!subtype.isSubtypeOf(executableElementTypes[j])) {
+ subtypeOfAllTypes = false;
+ foundSubtypeOfAllTypes = false;
+ break;
+ }
+ }
+ }
+ if (subtypeOfAllTypes) {
+ resultMap[key] = elements[i];
+ break;
+ }
+ }
+ if (!foundSubtypeOfAllTypes) {
+ reportError(classElt, classElt.nameOffset, classElt.displayName.length, StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [key]);
+ }
+ } else {
+ if (!allMethods && !allGetters) {
+ reportError(classElt, classElt.nameOffset, classElt.displayName.length, StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD, [key]);
+ }
+ resultMap.remove(entry.getKey());
+ }
+ }
+ }
+ _interfaceLookup[classElt] = resultMap;
+ return resultMap;
+ }
+
+ /**
+ * Given some {@link ClassElement}, this method finds and returns the {@link ExecutableElement} of
+ * the passed name in the class element. Static members, members in super types and members not
+ * accessible from the current library are not considered.
+ * @param classElt the class element to query
+ * @param memberName the name of the member to lookup in the class
+ * @return the found {@link ExecutableElement}, or {@code null} if no such member was found
+ */
+ ExecutableElement lookupMemberInClass(ClassElement classElt, String memberName) {
+ List<MethodElement> methods2 = classElt.methods;
+ for (MethodElement method in methods2) {
+ if (memberName == method.name && method.isAccessibleIn(_library) && !method.isStatic()) {
+ return method;
+ }
+ }
+ List<PropertyAccessorElement> accessors2 = classElt.accessors;
+ for (PropertyAccessorElement accessor in accessors2) {
+ if (memberName == accessor.name && accessor.isAccessibleIn(_library) && !accessor.isStatic()) {
+ return accessor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Record the passed map with the set of all members (methods, getters and setters) in the class
+ * into the passed map.
+ * @param map some non-{@code null}
+ * @param classElt the class element that will be recorded into the passed map
+ */
+ void recordMapWithClassMembers(Map<String, ExecutableElement> map, ClassElement classElt) {
+ List<MethodElement> methods2 = classElt.methods;
+ for (MethodElement method in methods2) {
+ if (method.isAccessibleIn(_library) && !method.isStatic()) {
+ map[method.name] = method;
+ }
+ }
+ List<PropertyAccessorElement> accessors2 = classElt.accessors;
+ for (PropertyAccessorElement accessor in accessors2) {
+ if (accessor.isAccessibleIn(_library) && !accessor.isStatic()) {
+ map[accessor.name] = accessor;
+ }
+ }
+ }
+
+ /**
+ * This method is used to report errors on when they are found computing inheritance information.
+ * See {@link ErrorVerifier#checkForInconsistentMethodInheritance()} to see where these generated
+ * error codes are reported back into the analysis engine.
+ * @param classElt the location of the source for which the exception occurred
+ * @param offset the offset of the location of the error
+ * @param length the length of the location of the error
+ * @param errorCode the error code to be associated with this error
+ * @param arguments the arguments used to build the error message
+ */
+ void reportError(ClassElement classElt, int offset, int length, ErrorCode errorCode, List<Object> arguments) {
+ Set<AnalysisError> errorSet = _errorsInClassElement[classElt];
+ if (errorSet == null) {
+ errorSet = new Set<AnalysisError>();
+ _errorsInClassElement[classElt] = errorSet;
+ }
+ javaSetAdd(errorSet, new AnalysisError.con2(classElt.source, offset, length, errorCode, arguments));
+ }
+}
+
+/**
* Instances of the class {@code Library} represent the data about a single library during the
* resolution of some (possibly different) library. They are not intended to be used except during
* the resolution process.
* @coverage dart.engine.resolver
*/
class Library {
+
/**
* The analysis context in which this library is being analyzed.
*/
InternalAnalysisContext _analysisContext;
+
/**
+ * The inheritance manager which is used for this member lookups in this library.
+ */
+ InheritanceManager _inheritanceManager;
+
+ /**
* The listener to which analysis errors will be reported.
*/
AnalysisErrorListener _errorListener;
+
/**
* The source specifying the defining compilation unit of this library.
*/
Source _librarySource;
+
/**
* The library element representing this library.
*/
LibraryElementImpl _libraryElement;
+
/**
* A list containing all of the libraries that are imported into this library.
*/
Map<ImportDirective, Library> _importedLibraries = new Map<ImportDirective, Library>();
+
/**
+ * A table mapping URI-based directive to the actual URI value.
+ */
+ Map<UriBasedDirective, String> _directiveUris = new Map<UriBasedDirective, String>();
+
+ /**
* A flag indicating whether this library explicitly imports core.
*/
bool _explicitlyImportsCore = false;
+
/**
* A list containing all of the libraries that are exported from this library.
*/
Map<ExportDirective, Library> _exportedLibraries = new Map<ExportDirective, Library>();
+
/**
* A table mapping the sources for the compilation units in this library to their corresponding
* AST structures.
*/
Map<Source, CompilationUnit> _astMap = new Map<Source, CompilationUnit>();
+
/**
* The library scope used when resolving elements within this library's compilation units.
*/
LibraryScope _libraryScope;
+
/**
* Initialize a newly created data holder that can maintain the data associated with a library.
* @param analysisContext the analysis context in which this library is being analyzed
@@ -2614,6 +3741,7 @@
this._librarySource = librarySource;
this._libraryElement = analysisContext.getLibraryElement(librarySource) as LibraryElementImpl;
}
+
/**
* Record that the given library is exported from this library.
* @param importLibrary the library that is exported from this library
@@ -2621,6 +3749,7 @@
void addExport(ExportDirective directive, Library exportLibrary) {
_exportedLibraries[directive] = exportLibrary;
}
+
/**
* Record that the given library is imported into this library.
* @param importLibrary the library that is imported into this library
@@ -2628,6 +3757,7 @@
void addImport(ImportDirective directive, Library importLibrary) {
_importedLibraries[directive] = importLibrary;
}
+
/**
* Return the AST structure associated with the given source.
* @param source the source representing the compilation unit whose AST is to be returned
@@ -2642,12 +3772,14 @@
}
return unit;
}
+
/**
* Return a collection containing the sources for the compilation units in this library, including
* the defining compilation unit.
* @return the sources for the compilation units in this library
*/
Set<Source> get compilationUnitSources => _astMap.keys.toSet();
+
/**
* Return the AST structure associated with the defining compilation unit for this library.
* @return the AST structure associated with the defining compilation unit for this library
@@ -2655,17 +3787,20 @@
* unit
*/
CompilationUnit get definingCompilationUnit => getAST(librarySource);
+
/**
* Return {@code true} if this library explicitly imports core.
* @return {@code true} if this library explicitly imports core
*/
bool get explicitlyImportsCore => _explicitlyImportsCore;
+
/**
* Return the library exported by the given directive.
* @param directive the directive that exports the library to be returned
* @return the library exported by the given directive
*/
Library getExport(ExportDirective directive) => _exportedLibraries[directive];
+
/**
* Return an array containing the libraries that are exported from this library.
* @return an array containing the libraries that are exported from this library
@@ -2675,12 +3810,14 @@
libraries.addAll(_exportedLibraries.values);
return new List.from(libraries);
}
+
/**
* Return the library imported by the given directive.
* @param directive the directive that imports the library to be returned
* @return the library imported by the given directive
*/
Library getImport(ImportDirective directive) => _importedLibraries[directive];
+
/**
* Return an array containing the libraries that are imported into this library.
* @return an array containing the libraries that are imported into this library
@@ -2690,6 +3827,7 @@
libraries.addAll(_importedLibraries.values);
return new List.from(libraries);
}
+
/**
* Return an array containing the libraries that are either imported or exported from this
* library.
@@ -2701,7 +3839,19 @@
libraries.addAll(_exportedLibraries.values);
return new List.from(libraries);
}
+
/**
+ * Return the inheritance manager for this library.
+ * @return the inheritance manager for this library
+ */
+ InheritanceManager get inheritanceManager {
+ if (_inheritanceManager == null) {
+ return _inheritanceManager = new InheritanceManager(_libraryElement);
+ }
+ return _inheritanceManager;
+ }
+
+ /**
* Return the library element representing this library, creating it if necessary.
* @return the library element representing this library
*/
@@ -2715,6 +3865,7 @@
}
return _libraryElement;
}
+
/**
* Return the library scope used when resolving elements within this library's compilation units.
* @return the library scope used when resolving elements within this library's compilation units
@@ -2725,62 +3876,75 @@
}
return _libraryScope;
}
+
/**
* Return the source specifying the defining compilation unit of this library.
* @return the source specifying the defining compilation unit of this library
*/
Source get librarySource => _librarySource;
+
/**
- * Return the result of resolving the given URI against the URI of the library, or {@code null} if
- * the URI is not valid. If the URI is not valid, report the error.
- * @param uriLiteral the string literal specifying the URI to be resolved
- * @return the result of resolving the given URI against the URI of the library
+ * Return the result of resolving the URI of the given URI-based directive against the URI of the
+ * library, or {@code null} if the URI is not valid. If the URI is not valid, report the error.
+ * @param directive the directive which URI should be resolved
+ * @return the result of resolving the URI against the URI of the library
*/
- Source getSource(StringLiteral uriLiteral) {
+ Source getSource(UriBasedDirective directive) {
+ StringLiteral uriLiteral = directive.uri;
if (uriLiteral is StringInterpolation) {
_errorListener.onError(new AnalysisError.con2(_librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION, []));
return null;
}
- Source source = getSource2(getStringValue(uriLiteral));
- if (source == null || !source.exists()) {
- _errorListener.onError(new AnalysisError.con2(_librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriLiteral.toSource()]));
+ String uriContent = uriLiteral.stringValue.trim();
+ _directiveUris[directive] = uriContent;
+ try {
+ parseUriWithException(uriContent);
+ Source source = getSource2(uriContent);
+ if (source == null || !source.exists()) {
+ _errorListener.onError(new AnalysisError.con2(_librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent]));
+ }
+ return source;
+ } on URISyntaxException catch (exception) {
+ _errorListener.onError(new AnalysisError.con2(_librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent]));
}
- return source;
+ return null;
}
+
/**
+ * Returns the URI value of the given directive.
+ */
+ String getUri(UriBasedDirective directive) => _directiveUris[directive];
+
+ /**
+ * Set the AST structure associated with the defining compilation unit for this library to the
+ * given AST structure.
+ * @param unit the AST structure associated with the defining compilation unit for this library
+ */
+ void set definingCompilationUnit(CompilationUnit unit) {
+ _astMap[librarySource] = unit;
+ }
+
+ /**
* Set whether this library explicitly imports core to match the given value.
* @param explicitlyImportsCore {@code true} if this library explicitly imports core
*/
void set explicitlyImportsCore(bool explicitlyImportsCore2) {
this._explicitlyImportsCore = explicitlyImportsCore2;
}
+
/**
* Set the library element representing this library to the given library element.
* @param libraryElement the library element representing this library
*/
void set libraryElement(LibraryElementImpl libraryElement2) {
this._libraryElement = libraryElement2;
+ if (_inheritanceManager != null) {
+ _inheritanceManager.libraryElement = libraryElement2;
+ }
}
String toString() => _librarySource.shortName;
+
/**
- * Append the value of the given string literal to the given string builder.
- * @param builder the builder to which the string's value is to be appended
- * @param literal the string literal whose value is to be appended to the builder
- * @throws IllegalArgumentException if the string is not a constant string without any string
- * interpolation
- */
- void appendStringValue(JavaStringBuilder builder, StringLiteral literal) {
- if (literal is SimpleStringLiteral) {
- builder.append(((literal as SimpleStringLiteral)).value);
- } else if (literal is AdjacentStrings) {
- for (StringLiteral stringLiteral in ((literal as AdjacentStrings)).strings) {
- appendStringValue(builder, stringLiteral);
- }
- } else {
- throw new IllegalArgumentException();
- }
- }
- /**
* Return the result of resolving the given URI against the URI of the library, or {@code null} if
* the URI is not valid.
* @param uri the URI to be resolved
@@ -2792,39 +3956,29 @@
}
return _analysisContext.sourceFactory.resolveUri(_librarySource, uri);
}
- /**
- * Return the value of the given string literal, or {@code null} if the string is not a constant
- * string without any string interpolation.
- * @param literal the string literal whose value is to be returned
- * @return the value of the given string literal
- */
- String getStringValue(StringLiteral literal) {
- JavaStringBuilder builder = new JavaStringBuilder();
- try {
- appendStringValue(builder, literal);
- } on IllegalArgumentException catch (exception) {
- return null;
- }
- return builder.toString().trim();
- }
}
+
/**
* Instances of the class {@code LibraryElementBuilder} build an element model for a single library.
* @coverage dart.engine.resolver
*/
class LibraryElementBuilder {
+
/**
* The analysis context in which the element model will be built.
*/
InternalAnalysisContext _analysisContext;
+
/**
* The listener to which errors will be reported.
*/
AnalysisErrorListener _errorListener;
+
/**
* The name of the function used as an entry point.
*/
static String _ENTRY_POINT_NAME = "main";
+
/**
* Initialize a newly created library element builder.
* @param resolver the resolver for which the element model is being built
@@ -2833,6 +3987,7 @@
this._analysisContext = resolver.analysisContext;
this._errorListener = resolver.errorListener;
}
+
/**
* Build the library element for the given library.
* @param library the library for which an element model is to be built
@@ -2857,11 +4012,13 @@
directivesToResolve.add(directive);
}
} else if (directive is PartDirective) {
- hasPartDirective = true;
- StringLiteral partUri = ((directive as PartDirective)).uri;
- Source partSource = library.getSource(partUri);
+ PartDirective partDirective = directive as PartDirective;
+ StringLiteral partUri = partDirective.uri;
+ Source partSource = library.getSource(partDirective);
if (partSource != null && partSource.exists()) {
+ hasPartDirective = true;
CompilationUnitElementImpl part = builder.buildCompilationUnit(partSource, library.getAST(partSource));
+ part.uri = library.getUri(partDirective);
String partLibraryName = getPartLibraryName(library, partSource, directivesToResolve);
if (partLibraryName == null) {
_errorListener.onError(new AnalysisError.con2(librarySource2, partUri.offset, partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()]));
@@ -2885,14 +4042,40 @@
if (entryPoint != null) {
libraryElement.entryPoint = entryPoint;
}
+ int sourcedUnitCount = sourcedCompilationUnits.length;
libraryElement.parts = new List.from(sourcedCompilationUnits);
for (Directive directive in directivesToResolve) {
directive.element = libraryElement;
}
library.libraryElement = libraryElement;
+ if (sourcedUnitCount > 0) {
+ patchTopLevelAccessors(libraryElement);
+ }
return libraryElement;
}
+
/**
+ * Add all of the non-synthetic getters and setters defined in the given compilation unit that
+ * have no corresponding accessor to one of the given collections.
+ * @param getters the map to which getters are to be added
+ * @param setters the list to which setters are to be added
+ * @param unit the compilation unit defining the accessors that are potentially being added
+ */
+ void collectAccessors(Map<String, PropertyAccessorElement> getters, List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
+ for (PropertyAccessorElement accessor in unit.accessors) {
+ if (accessor.isGetter()) {
+ if (!accessor.isSynthetic() && accessor.correspondingSetter == null) {
+ getters[accessor.displayName] = accessor;
+ }
+ } else {
+ if (!accessor.isSynthetic() && accessor.correspondingGetter == null) {
+ setters.add(accessor);
+ }
+ }
+ }
+ }
+
+ /**
* Search the top-level functions defined in the given compilation unit for the entry point.
* @param element the compilation unit to be searched
* @return the entry point that was found, or {@code null} if the compilation unit does not define
@@ -2906,6 +4089,7 @@
}
return null;
}
+
/**
* Return the name of the library that the given part is declared to be a part of, or {@code null}if the part does not contain a part-of directive.
* @param library the library containing the part
@@ -2930,87 +4114,151 @@
}
return null;
}
+
+ /**
+ * Look through all of the compilation units defined for the given library, looking for getters
+ * and setters that are defined in different compilation units but that have the same names. If
+ * any are found, make sure that they have the same variable element.
+ * @param libraryElement the library defining the compilation units to be processed
+ */
+ void patchTopLevelAccessors(LibraryElementImpl libraryElement) {
+ Map<String, PropertyAccessorElement> getters = new Map<String, PropertyAccessorElement>();
+ List<PropertyAccessorElement> setters = new List<PropertyAccessorElement>();
+ collectAccessors(getters, setters, libraryElement.definingCompilationUnit);
+ for (CompilationUnitElement unit in libraryElement.parts) {
+ collectAccessors(getters, setters, unit);
+ }
+ for (PropertyAccessorElement setter in setters) {
+ PropertyAccessorElement getter = getters[setter.displayName];
+ if (getter != null) {
+ PropertyInducingElementImpl variable2 = getter.variable as PropertyInducingElementImpl;
+ variable2.setter = setter;
+ ((setter as PropertyAccessorElementImpl)).variable = variable2;
+ }
+ }
+ }
}
+
/**
* Instances of the class {@code LibraryResolver} are used to resolve one or more mutually dependent
* libraries within a single context.
* @coverage dart.engine.resolver
*/
class LibraryResolver {
+
/**
* The analysis context in which the libraries are being analyzed.
*/
InternalAnalysisContext _analysisContext;
+
/**
* The listener to which analysis errors will be reported, this error listener is either
* references {@link #recordingErrorListener}, or it unions the passed{@link AnalysisErrorListener} with the {@link #recordingErrorListener}.
*/
- AnalysisErrorListener _errorListener;
+ RecordingErrorListener _errorListener;
+
/**
- * This error listener is used by the resolver to be able to call the listener and get back the
- * set of errors for each {@link Source}.
- * @see #recordResults()
- */
- RecordingErrorListener _recordingErrorListener;
- /**
* A source object representing the core library (dart:core).
*/
Source _coreLibrarySource;
+
/**
* The object representing the core library.
*/
Library _coreLibrary;
+
/**
* The object used to access the types from the core library.
*/
TypeProvider _typeProvider;
+
/**
* A table mapping library sources to the information being maintained for those libraries.
*/
Map<Source, Library> _libraryMap = new Map<Source, Library>();
+
/**
* A collection containing the libraries that are being resolved together.
*/
Set<Library> _librariesInCycles;
+
/**
* Initialize a newly created library resolver to resolve libraries within the given context.
* @param analysisContext the analysis context in which the library is being analyzed
*/
- LibraryResolver.con1(InternalAnalysisContext analysisContext) {
- _jtd_constructor_264_impl(analysisContext);
+ LibraryResolver(InternalAnalysisContext analysisContext) {
+ this._analysisContext = analysisContext;
+ this._errorListener = new RecordingErrorListener();
+ _coreLibrarySource = analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
}
- _jtd_constructor_264_impl(InternalAnalysisContext analysisContext) {
- _jtd_constructor_265_impl(analysisContext, null);
- }
+
/**
- * Initialize a newly created library resolver to resolve libraries within the given context.
- * @param analysisContext the analysis context in which the library is being analyzed
- * @param errorListener the listener to which analysis errors will be reported
- */
- LibraryResolver.con2(InternalAnalysisContext analysisContext2, AnalysisErrorListener additionalAnalysisErrorListener) {
- _jtd_constructor_265_impl(analysisContext2, additionalAnalysisErrorListener);
- }
- _jtd_constructor_265_impl(InternalAnalysisContext analysisContext2, AnalysisErrorListener additionalAnalysisErrorListener) {
- this._analysisContext = analysisContext2;
- this._recordingErrorListener = new RecordingErrorListener();
- if (additionalAnalysisErrorListener == null) {
- this._errorListener = _recordingErrorListener;
- } else {
- this._errorListener = new AnalysisErrorListener_9(this, additionalAnalysisErrorListener);
- }
- _coreLibrarySource = analysisContext2.sourceFactory.forUri(DartSdk.DART_CORE);
- }
- /**
* Return the analysis context in which the libraries are being analyzed.
* @return the analysis context in which the libraries are being analyzed
*/
InternalAnalysisContext get analysisContext => _analysisContext;
+
/**
* Return the listener to which analysis errors will be reported.
* @return the listener to which analysis errors will be reported
*/
- AnalysisErrorListener get errorListener => _errorListener;
+ RecordingErrorListener get errorListener => _errorListener;
+
/**
+ * Return an array containing information about all of the libraries that were resolved.
+ * @return an array containing the libraries that were resolved
+ */
+ Set<Library> get resolvedLibraries => _librariesInCycles;
+
+ /**
+ * Resolve the library specified by the given source in the given context. The library is assumed
+ * to be embedded in the given source.
+ * @param librarySource the source specifying the defining compilation unit of the library to be
+ * resolved
+ * @param unit the compilation unit representing the embedded library
+ * @param fullAnalysis {@code true} if a full analysis should be performed
+ * @return the element representing the resolved library
+ * @throws AnalysisException if the library could not be resolved for some reason
+ */
+ LibraryElement resolveEmbeddedLibrary(Source librarySource, CompilationUnit unit, bool fullAnalysis) {
+ InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.LibraryResolver.resolveEmbeddedLibrary");
+ try {
+ instrumentation.metric("fullAnalysis", fullAnalysis);
+ instrumentation.data3("fullName", librarySource.fullName);
+ Library targetLibrary = createLibrary2(librarySource, unit);
+ _coreLibrary = _libraryMap[_coreLibrarySource];
+ if (_coreLibrary == null) {
+ _coreLibrary = createLibrary(_coreLibrarySource);
+ }
+ instrumentation.metric3("createLibrary", "complete");
+ computeLibraryDependencies(targetLibrary);
+ _librariesInCycles = computeLibrariesInCycles(targetLibrary);
+ buildElementModels();
+ instrumentation.metric3("buildElementModels", "complete");
+ LibraryElement coreElement = _coreLibrary.libraryElement;
+ if (coreElement == null) {
+ throw new AnalysisException.con1("Could not resolve dart:core");
+ }
+ buildDirectiveModels();
+ instrumentation.metric3("buildDirectiveModels", "complete");
+ _typeProvider = new TypeProviderImpl(coreElement);
+ buildTypeHierarchies();
+ instrumentation.metric3("buildTypeHierarchies", "complete");
+ resolveReferencesAndTypes();
+ instrumentation.metric3("resolveReferencesAndTypes", "complete");
+ performConstantEvaluation();
+ instrumentation.metric3("performConstantEvaluation", "complete");
+ if (fullAnalysis) {
+ runAdditionalAnalyses();
+ instrumentation.metric3("runAdditionalAnalyses", "complete");
+ }
+ return targetLibrary.libraryElement;
+ } finally {
+ instrumentation.log();
+ }
+ }
+
+ /**
* Resolve the library specified by the given source in the given context.
* <p>
* Note that because Dart allows circular imports between libraries, it is possible that more than
@@ -3054,8 +4302,6 @@
runAdditionalAnalyses();
instrumentation.metric3("runAdditionalAnalyses", "complete");
}
- recordResults();
- instrumentation.metric3("recordResults", "complete");
instrumentation.metric2("librariesInCycles", _librariesInCycles.length);
for (Library lib in _librariesInCycles) {
instrumentation.metric2("librariesInCycles-CompilationUnitSources-Size", lib.compilationUnitSources.length);
@@ -3065,6 +4311,7 @@
instrumentation.log();
}
}
+
/**
* Add a dependency to the given map from the referencing library to the referenced library.
* @param dependencyMap the map to which the dependency is to be added
@@ -3079,6 +4326,7 @@
}
dependentLibraries.add(referencingLibrary);
}
+
/**
* Given a library that is part of a cycle that includes the root library, add to the given set of
* libraries all of the libraries reachable from the root library that are also included in the
@@ -3098,6 +4346,7 @@
}
}
}
+
/**
* Add the given library, and all libraries reachable from it that have not already been visited,
* to the given dependency map.
@@ -3117,6 +4366,7 @@
}
}
}
+
/**
* Build the element model representing the combinators declared by the given directive.
* @param directive the directive that declares the combinators
@@ -3137,6 +4387,7 @@
}
return new List.from(combinators);
}
+
/**
* Every library now has a corresponding {@link LibraryElement}, so it is now possible to resolve
* the import and export directives.
@@ -3154,6 +4405,7 @@
Library importedLibrary = library.getImport(importDirective);
if (importedLibrary != null) {
ImportElementImpl importElement = new ImportElementImpl();
+ importElement.uri = library.getUri(importDirective);
importElement.combinators = buildCombinators(importDirective);
LibraryElement importedLibraryElement = importedLibrary.libraryElement;
if (importedLibraryElement != null) {
@@ -3175,6 +4427,7 @@
} else if (directive is ExportDirective) {
ExportDirective exportDirective = directive as ExportDirective;
ExportElementImpl exportElement = new ExportElementImpl();
+ exportElement.uri = library.getUri(exportDirective);
exportElement.combinators = buildCombinators(exportDirective);
Library exportedLibrary = library.getExport(exportDirective);
if (exportedLibrary != null) {
@@ -3199,6 +4452,7 @@
libraryElement2.exports = new List.from(exports);
}
}
+
/**
* Build element models for all of the libraries in the current cycle.
* @throws AnalysisException if any of the element models cannot be built
@@ -3210,6 +4464,7 @@
library.libraryElement = libraryElement;
}
}
+
/**
* Resolve the type hierarchy across all of the types declared in the libraries in the current
* cycle.
@@ -3223,6 +4478,7 @@
}
}
}
+
/**
* Compute a dependency map of libraries reachable from the given library. A dependency map is a
* table that maps individual libraries to a list of the libraries that either import or export
@@ -3238,6 +4494,7 @@
addToDependencyMap(library, dependencyMap, new Set<Library>());
return dependencyMap;
}
+
/**
* Return a collection containing all of the libraries reachable from the given library that are
* contained in a cycle that includes the given library.
@@ -3251,6 +4508,7 @@
addLibrariesInCycle(library, librariesInCycle, dependencyMap);
return librariesInCycle;
}
+
/**
* Recursively traverse the libraries reachable from the given library, creating instances of the
* class {@link Library} to represent them, and record the references in the library objects.
@@ -3263,7 +4521,7 @@
for (Directive directive in unit.directives) {
if (directive is ImportDirective) {
ImportDirective importDirective = directive as ImportDirective;
- Source importedSource = library.getSource(importDirective.uri);
+ Source importedSource = library.getSource(importDirective);
if (importedSource != null) {
if (importedSource == _coreLibrarySource) {
explicitlyImportsCore = true;
@@ -3285,7 +4543,7 @@
}
} else if (directive is ExportDirective) {
ExportDirective exportDirective = directive as ExportDirective;
- Source exportedSource = library.getSource(exportDirective.uri);
+ Source exportedSource = library.getSource(exportDirective);
if (exportedSource != null) {
Library exportedLibrary = _libraryMap[exportedSource];
if (exportedLibrary == null) {
@@ -3315,6 +4573,7 @@
}
}
}
+
/**
* Create an object to represent the information about the library defined by the compilation unit
* with the given source.
@@ -3328,8 +4587,23 @@
_libraryMap[librarySource] = library;
return library;
}
+
/**
* Create an object to represent the information about the library defined by the compilation unit
+ * with the given source.
+ * @param librarySource the source of the library's defining compilation unit
+ * @return the library object that was created
+ * @throws AnalysisException if the library source is not valid
+ */
+ Library createLibrary2(Source librarySource, CompilationUnit unit) {
+ Library library = new Library(_analysisContext, _errorListener, librarySource);
+ library.definingCompilationUnit = unit;
+ _libraryMap[librarySource] = library;
+ return library;
+ }
+
+ /**
+ * Create an object to represent the information about the library defined by the compilation unit
* with the given source. Return the library object that was created, or {@code null} if the
* source is not valid.
* @param librarySource the source of the library's defining compilation unit
@@ -3348,6 +4622,7 @@
_libraryMap[librarySource] = library;
return library;
}
+
/**
* Return {@code true} if and only if the passed {@link CompilationUnit} has a part-of directive.
* @param node the {@link CompilationUnit} to test
@@ -3362,6 +4637,7 @@
}
return false;
}
+
/**
* Return an array containing the lexical identifiers associated with the nodes in the given list.
* @param names the AST nodes representing the identifiers
@@ -3375,6 +4651,7 @@
}
return identifiers;
}
+
/**
* Compute a value for all of the constants in the libraries being analyzed.
*/
@@ -3394,33 +4671,8 @@
}
computer.computeValues();
}
+
/**
- * Record the results of resolution with the analysis context. This includes recording
- * <ul>
- * <li>the resolved AST associated with each compilation unit,</li>
- * <li>the set of resolution errors produced for each compilation unit, and</li>
- * <li>the element models produced for each library.</li>
- * </ul>
- */
- void recordResults() {
- Map<Source, LibraryElement> elementMap = new Map<Source, LibraryElement>();
- for (Library library in _librariesInCycles) {
- Source librarySource2 = library.librarySource;
- recordResults2(librarySource2, librarySource2, library.definingCompilationUnit);
- for (Source source in library.compilationUnitSources) {
- recordResults2(source, librarySource2, library.getAST(source));
- }
- elementMap[library.librarySource] = library.libraryElement;
- }
- _analysisContext.recordLibraryElements(elementMap);
- }
- void recordResults2(Source source, Source librarySource, CompilationUnit unit) {
- List<AnalysisError> errors = _recordingErrorListener.getErrors2(source);
- unit.resolutionErrors = errors;
- _analysisContext.recordResolvedCompilationUnit(source, librarySource, unit);
- _analysisContext.recordResolutionErrors(source, librarySource, errors, unit.lineInfo);
- }
- /**
* Resolve the identifiers and perform type analysis in the libraries in the current cycle.
* @throws AnalysisException if any of the identifiers could not be resolved or if any of the
* libraries could not have their types analyzed
@@ -3430,6 +4682,7 @@
resolveReferencesAndTypes2(library);
}
}
+
/**
* Resolve the identifiers and perform type analysis in the given library.
* @param library the library to be resolved
@@ -3442,6 +4695,7 @@
library.getAST(source).accept(visitor);
}
}
+
/**
* Run additional analyses, such as the {@link ConstantVerifier} and {@link ErrorVerifier}analysis in the current cycle.
* @throws AnalysisException if any of the identifiers could not be resolved or if the types in
@@ -3452,6 +4706,7 @@
runAdditionalAnalyses2(library);
}
}
+
/**
* Run additional analyses, such as the {@link ConstantVerifier} and {@link ErrorVerifier}analysis in the given library.
* @param library the library to have the extra analyses processes run
@@ -3462,50 +4717,48 @@
for (Source source in library.compilationUnitSources) {
ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
CompilationUnit unit = library.getAST(source);
- ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter, library.libraryElement, _typeProvider);
+ ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter, library.libraryElement, _typeProvider, library.inheritanceManager);
unit.accept(errorVerifier);
- ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter);
+ ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter, _typeProvider);
unit.accept(constantVerifier);
}
}
}
-class AnalysisErrorListener_9 implements AnalysisErrorListener {
- final LibraryResolver LibraryResolver_this;
- AnalysisErrorListener additionalAnalysisErrorListener;
- AnalysisErrorListener_9(this.LibraryResolver_this, this.additionalAnalysisErrorListener);
- void onError(AnalysisError error) {
- additionalAnalysisErrorListener.onError(error);
- LibraryResolver_this._recordingErrorListener.onError(error);
- }
-}
+
/**
* Instances of the class {@code ResolverVisitor} are used to resolve the nodes within a single
* compilation unit.
* @coverage dart.engine.resolver
*/
class ResolverVisitor extends ScopedVisitor {
+
/**
* The object used to resolve the element associated with the current node.
*/
ElementResolver _elementResolver;
+
/**
* The object used to compute the type associated with the current node.
*/
StaticTypeAnalyzer _typeAnalyzer;
+
/**
* The class element representing the class containing the current node, or {@code null} if the
* current node is not contained in a class.
*/
ClassElement _enclosingClass = null;
+
/**
* The element representing the function containing the current node, or {@code null} if the
* current node is not contained in a function.
*/
ExecutableElement _enclosingFunction = null;
+
/**
* The object keeping track of which elements have had their types overridden.
*/
TypeOverrideManager _overrideManager = new TypeOverrideManager();
+
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param library the library containing the compilation unit being resolved
@@ -3513,12 +4766,13 @@
* @param typeProvider the object used to access the types from the core library
*/
ResolverVisitor.con1(Library library, Source source, TypeProvider typeProvider) : super.con1(library, source, typeProvider) {
- _jtd_constructor_266_impl(library, source, typeProvider);
+ _jtd_constructor_272_impl(library, source, typeProvider);
}
- _jtd_constructor_266_impl(Library library, Source source, TypeProvider typeProvider) {
+ _jtd_constructor_272_impl(Library library, Source source, TypeProvider typeProvider) {
this._elementResolver = new ElementResolver(this);
this._typeAnalyzer = new StaticTypeAnalyzer(this);
}
+
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param definingLibrary the element for the library containing the compilation unit being
@@ -3529,12 +4783,13 @@
* during resolution
*/
ResolverVisitor.con2(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, AnalysisErrorListener errorListener) : super.con2(definingLibrary, source, typeProvider, errorListener) {
- _jtd_constructor_267_impl(definingLibrary, source, typeProvider, errorListener);
+ _jtd_constructor_273_impl(definingLibrary, source, typeProvider, errorListener);
}
- _jtd_constructor_267_impl(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, AnalysisErrorListener errorListener) {
+ _jtd_constructor_273_impl(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, AnalysisErrorListener errorListener) {
this._elementResolver = new ElementResolver(this);
this._typeAnalyzer = new StaticTypeAnalyzer(this);
}
+
/**
* Return the object keeping track of which elements have had their types overridden.
* @return the object keeping track of which elements have had their types overridden
@@ -3542,62 +4797,49 @@
TypeOverrideManager get overrideManager => _overrideManager;
Object visitAsExpression(AsExpression node) {
super.visitAsExpression(node);
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- VariableElement element = getOverridableElement(node.expression);
- if (element != null) {
- Type2 type2 = node.type.type;
- if (type2 != null) {
- override(element, getType(element), type2);
- }
- }
+ VariableElement element = getOverridableElement(node.expression);
+ if (element != null) {
+ override(element, node.type.type);
}
return null;
}
Object visitAssertStatement(AssertStatement node) {
super.visitAssertStatement(node);
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- propagateTrueState(node.condition);
- }
+ propagateTrueState(node.condition);
return null;
}
Object visitBinaryExpression(BinaryExpression node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- sc.TokenType operatorType = node.operator.type;
- if (identical(operatorType, sc.TokenType.AMPERSAND_AMPERSAND)) {
- Expression leftOperand2 = node.leftOperand;
- leftOperand2.accept(this);
- Expression rightOperand2 = node.rightOperand;
- if (rightOperand2 != null) {
- try {
- _overrideManager.enterScope();
- propagateTrueState(leftOperand2);
- rightOperand2.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
+ sc.TokenType operatorType = node.operator.type;
+ Expression leftOperand2 = node.leftOperand;
+ Expression rightOperand2 = node.rightOperand;
+ if (identical(operatorType, sc.TokenType.AMPERSAND_AMPERSAND)) {
+ safelyVisit(leftOperand2);
+ if (rightOperand2 != null) {
+ try {
+ _overrideManager.enterScope();
+ propagateTrueState(leftOperand2);
+ rightOperand2.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
- } else if (identical(operatorType, sc.TokenType.BAR_BAR)) {
- Expression leftOperand3 = node.leftOperand;
- leftOperand3.accept(this);
- Expression rightOperand3 = node.rightOperand;
- if (rightOperand3 != null) {
- try {
- _overrideManager.enterScope();
- propagateFalseState(leftOperand3);
- rightOperand3.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
+ }
+ } else if (identical(operatorType, sc.TokenType.BAR_BAR)) {
+ safelyVisit(leftOperand2);
+ if (rightOperand2 != null) {
+ try {
+ _overrideManager.enterScope();
+ propagateFalseState(leftOperand2);
+ rightOperand2.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
- } else {
- node.leftOperand.accept(this);
- node.rightOperand.accept(this);
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
} else {
- super.visitBinaryExpression(node);
+ safelyVisit(leftOperand2);
+ safelyVisit(rightOperand2);
}
+ node.accept(_elementResolver);
+ node.accept(_typeAnalyzer);
return null;
}
Object visitBreakStatement(BreakStatement node) {
@@ -3623,69 +4865,63 @@
return null;
}
Object visitCompilationUnit(CompilationUnit node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- for (Directive directive in node.directives) {
- directive.accept(this);
- }
- List<CompilationUnitMember> classes = new List<CompilationUnitMember>();
- for (CompilationUnitMember declaration in node.declarations) {
- if (declaration is ClassDeclaration) {
- classes.add(declaration);
- } else {
- declaration.accept(this);
- }
- }
- for (CompilationUnitMember declaration in classes) {
+ try {
+ _overrideManager.enterScope();
+ for (Directive directive in node.directives) {
+ directive.accept(this);
+ }
+ List<CompilationUnitMember> classes = new List<CompilationUnitMember>();
+ for (CompilationUnitMember declaration in node.declarations) {
+ if (declaration is ClassDeclaration) {
+ classes.add(declaration);
+ } else {
declaration.accept(this);
}
- } finally {
- _overrideManager.exitScope();
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
- } else {
- super.visitCompilationUnit(node);
+ for (CompilationUnitMember declaration in classes) {
+ declaration.accept(this);
+ }
+ } finally {
+ _overrideManager.exitScope();
}
+ node.accept(_elementResolver);
+ node.accept(_typeAnalyzer);
return null;
}
Object visitConditionalExpression(ConditionalExpression node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- Expression condition2 = node.condition;
- condition2.accept(this);
- Expression thenExpression2 = node.thenExpression;
- if (thenExpression2 != null) {
- try {
- _overrideManager.enterScope();
- propagateTrueState(condition2);
- thenExpression2.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
+ Expression condition2 = node.condition;
+ safelyVisit(condition2);
+ Expression thenExpression2 = node.thenExpression;
+ if (thenExpression2 != null) {
+ try {
+ _overrideManager.enterScope();
+ propagateTrueState(condition2);
+ thenExpression2.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
- Expression elseExpression2 = node.elseExpression;
- if (elseExpression2 != null) {
- try {
- _overrideManager.enterScope();
- propagateFalseState(condition2);
- elseExpression2.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
- }
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
- bool thenIsAbrupt = thenExpression2 != null && isAbruptTermination(thenExpression2);
- bool elseIsAbrupt = elseExpression2 != null && isAbruptTermination(elseExpression2);
- if (elseIsAbrupt && !thenIsAbrupt) {
- propagateTrueState(condition2);
- } else if (thenIsAbrupt && !elseIsAbrupt) {
+ }
+ Expression elseExpression2 = node.elseExpression;
+ if (elseExpression2 != null) {
+ try {
+ _overrideManager.enterScope();
propagateFalseState(condition2);
+ elseExpression2.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
- } else {
- super.visitConditionalExpression(node);
}
+ node.accept(_elementResolver);
+ node.accept(_typeAnalyzer);
+ bool thenIsAbrupt = isAbruptTermination(thenExpression2);
+ bool elseIsAbrupt = isAbruptTermination(elseExpression2);
+ if (elseIsAbrupt && !thenIsAbrupt) {
+ propagateTrueState(condition2);
+ propagateState(thenExpression2);
+ } else if (thenIsAbrupt && !elseIsAbrupt) {
+ propagateFalseState(condition2);
+ propagateState(elseExpression2);
+ }
return null;
}
Object visitConstructorDeclaration(ConstructorDeclaration node) {
@@ -3714,57 +4950,50 @@
node.accept(_typeAnalyzer);
return null;
}
+ Object visitDoStatement(DoStatement node) {
+ try {
+ _overrideManager.enterScope();
+ super.visitDoStatement(node);
+ } finally {
+ _overrideManager.exitScope();
+ }
+ return null;
+ }
Object visitFieldDeclaration(FieldDeclaration node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitFieldDeclaration(node);
- } finally {
- Map<Element, Type2> overrides = captureOverrides(node.fields);
- _overrideManager.exitScope();
- applyOverrides(overrides);
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitFieldDeclaration(node);
+ } finally {
+ Map<Element, Type2> overrides = _overrideManager.captureOverrides(node.fields);
+ _overrideManager.exitScope();
+ _overrideManager.applyOverrides(overrides);
}
return null;
}
Object visitForEachStatement(ForEachStatement node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitForEachStatement(node);
- } finally {
- _overrideManager.exitScope();
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitForEachStatement(node);
+ } finally {
+ _overrideManager.exitScope();
}
return null;
}
Object visitForStatement(ForStatement node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitForStatement(node);
- } finally {
- _overrideManager.exitScope();
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitForStatement(node);
+ } finally {
+ _overrideManager.exitScope();
}
return null;
}
Object visitFunctionBody(FunctionBody node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitFunctionBody(node);
- } finally {
- _overrideManager.exitScope();
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitFunctionBody(node);
+ } finally {
+ _overrideManager.exitScope();
}
return null;
}
@@ -3783,55 +5012,57 @@
ExecutableElement outerFunction = _enclosingFunction;
try {
_enclosingFunction = node.element;
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- _overrideManager.enterScope();
- }
+ _overrideManager.enterScope();
super.visitFunctionExpression(node);
} finally {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- _overrideManager.exitScope();
- }
+ _overrideManager.exitScope();
_enclosingFunction = outerFunction;
}
return null;
}
Object visitHideCombinator(HideCombinator node) => null;
Object visitIfStatement(IfStatement node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- Expression condition2 = node.condition;
- condition2.accept(this);
- Statement thenStatement2 = node.thenStatement;
- if (thenStatement2 != null) {
- try {
- _overrideManager.enterScope();
- propagateTrueState(condition2);
- thenStatement2.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
+ Expression condition2 = node.condition;
+ safelyVisit(condition2);
+ Map<Element, Type2> thenOverrides = null;
+ Statement thenStatement2 = node.thenStatement;
+ if (thenStatement2 != null) {
+ try {
+ _overrideManager.enterScope();
+ propagateTrueState(condition2);
+ thenStatement2.accept(this);
+ } finally {
+ thenOverrides = _overrideManager.captureLocalOverrides();
+ _overrideManager.exitScope();
}
- Statement elseStatement2 = node.elseStatement;
- if (elseStatement2 != null) {
- try {
- _overrideManager.enterScope();
- propagateFalseState(condition2);
- elseStatement2.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
- }
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
- bool thenIsAbrupt = thenStatement2 != null && isAbruptTermination2(thenStatement2);
- bool elseIsAbrupt = elseStatement2 != null && isAbruptTermination2(elseStatement2);
- if (elseIsAbrupt && !thenIsAbrupt) {
- propagateTrueState(condition2);
- } else if (thenIsAbrupt && !elseIsAbrupt) {
+ }
+ Map<Element, Type2> elseOverrides = null;
+ Statement elseStatement2 = node.elseStatement;
+ if (elseStatement2 != null) {
+ try {
+ _overrideManager.enterScope();
propagateFalseState(condition2);
+ elseStatement2.accept(this);
+ } finally {
+ elseOverrides = _overrideManager.captureLocalOverrides();
+ _overrideManager.exitScope();
}
- } else {
- super.visitIfStatement(node);
}
+ node.accept(_elementResolver);
+ node.accept(_typeAnalyzer);
+ bool thenIsAbrupt = isAbruptTermination2(thenStatement2);
+ bool elseIsAbrupt = isAbruptTermination2(elseStatement2);
+ if (elseIsAbrupt && !thenIsAbrupt) {
+ propagateTrueState(condition2);
+ if (thenOverrides != null) {
+ _overrideManager.applyOverrides(thenOverrides);
+ }
+ } else if (thenIsAbrupt && !elseIsAbrupt) {
+ propagateFalseState(condition2);
+ if (elseOverrides != null) {
+ _overrideManager.applyOverrides(elseOverrides);
+ }
+ }
return null;
}
Object visitLabel(Label node) => null;
@@ -3885,145 +5116,164 @@
return null;
}
Object visitSwitchCase(SwitchCase node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitSwitchCase(node);
- } finally {
- _overrideManager.exitScope();
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitSwitchCase(node);
+ } finally {
+ _overrideManager.exitScope();
}
return null;
}
Object visitSwitchDefault(SwitchDefault node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitSwitchDefault(node);
- } finally {
- _overrideManager.exitScope();
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitSwitchDefault(node);
+ } finally {
+ _overrideManager.exitScope();
}
return null;
}
Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- try {
- _overrideManager.enterScope();
- super.visitTopLevelVariableDeclaration(node);
- } finally {
- Map<Element, Type2> overrides = captureOverrides(node.variables);
- _overrideManager.exitScope();
- applyOverrides(overrides);
- }
- } else {
+ try {
+ _overrideManager.enterScope();
super.visitTopLevelVariableDeclaration(node);
+ } finally {
+ Map<Element, Type2> overrides = _overrideManager.captureOverrides(node.variables);
+ _overrideManager.exitScope();
+ _overrideManager.applyOverrides(overrides);
}
return null;
}
Object visitTypeName(TypeName node) => null;
Object visitWhileStatement(WhileStatement node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- Expression condition2 = node.condition;
- condition2.accept(this);
- Statement body2 = node.body;
- if (body2 != null) {
- try {
- _overrideManager.enterScope();
- propagateTrueState(condition2);
- body2.accept(this);
- } finally {
- _overrideManager.exitScope();
- }
+ Expression condition2 = node.condition;
+ safelyVisit(condition2);
+ Statement body2 = node.body;
+ if (body2 != null) {
+ try {
+ _overrideManager.enterScope();
+ propagateTrueState(condition2);
+ body2.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
- } else {
- super.visitWhileStatement(node);
}
+ node.accept(_elementResolver);
+ node.accept(_typeAnalyzer);
return null;
}
+
/**
* Return the class element representing the class containing the current node, or {@code null} if
* the current node is not contained in a class.
* @return the class element representing the class containing the current node
*/
ClassElement get enclosingClass => _enclosingClass;
+
/**
* Return the element representing the function containing the current node, or {@code null} if
* the current node is not contained in a function.
* @return the element representing the function containing the current node
*/
ExecutableElement get enclosingFunction => _enclosingFunction;
+
/**
* Return the element associated with the given expression whose type can be overridden, or{@code null} if there is no element whose type can be overridden.
* @param expression the expression with which the element is associated
* @return the element associated with the given expression
*/
VariableElement getOverridableElement(Expression expression) {
+ Element element = null;
if (expression is SimpleIdentifier) {
- Element element2 = ((expression as SimpleIdentifier)).element;
- if (element2 is VariableElement) {
- return element2 as VariableElement;
- }
+ element = ((expression as SimpleIdentifier)).element;
+ } else if (expression is PrefixedIdentifier) {
+ element = ((expression as PrefixedIdentifier)).element;
+ } else if (expression is PropertyAccess) {
+ element = ((expression as PropertyAccess)).propertyName.element;
}
+ if (element is VariableElement) {
+ return element as VariableElement;
+ }
return null;
}
+
+ /**
+ * If it is appropriate to do so, override the current type of the given element with the given
+ * type. Generally speaking, it is appropriate if the given type is more specific than the current
+ * type.
+ * @param element the element whose type might be overridden
+ * @param potentialType the potential type of the element
+ */
+ void override(VariableElement element, Type2 potentialType) {
+ if (potentialType == null || identical(potentialType, BottomTypeImpl.instance)) {
+ return;
+ }
+ if (element is PropertyInducingElement) {
+ PropertyInducingElement variable = element as PropertyInducingElement;
+ if (!variable.isConst() && !variable.isFinal()) {
+ return;
+ }
+ }
+ Type2 currentType = getBestType(element);
+ if (currentType == null || !currentType.isMoreSpecificThan(potentialType)) {
+ _overrideManager.setType(element, potentialType);
+ }
+ }
void visitForEachStatementInScope(ForEachStatement node) {
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- DeclaredIdentifier loopVariable2 = node.loopVariable;
- safelyVisit(loopVariable2);
- Expression iterator2 = node.iterator;
- if (iterator2 != null) {
- iterator2.accept(this);
- if (loopVariable2 != null) {
+ Expression iterator2 = node.iterator;
+ safelyVisit(iterator2);
+ DeclaredIdentifier loopVariable2 = node.loopVariable;
+ safelyVisit(loopVariable2);
+ Statement body2 = node.body;
+ if (body2 != null) {
+ try {
+ _overrideManager.enterScope();
+ if (loopVariable2 != null && iterator2 != null) {
LocalVariableElement loopElement = loopVariable2.element;
- override(loopElement, loopElement.type, getIteratorElementType(iterator2));
+ if (loopElement != null) {
+ override(loopElement, getIteratorElementType(iterator2));
+ }
}
+ body2.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
- safelyVisit(node.body);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
- } else {
- super.visitForEachStatementInScope(node);
}
+ node.accept(_elementResolver);
+ node.accept(_typeAnalyzer);
}
- /**
- * Apply a set of overrides that were previously captured.
- * @param overrides the overrides to be applied
- */
- void applyOverrides(Map<Element, Type2> overrides) {
- for (MapEntry<Element, Type2> entry in getMapEntrySet(overrides)) {
- _overrideManager.setType(entry.getKey(), entry.getValue());
+ void visitForStatementInScope(ForStatement node) {
+ safelyVisit(node.variables);
+ safelyVisit(node.initialization);
+ safelyVisit(node.condition);
+ _overrideManager.enterScope();
+ try {
+ propagateTrueState(node.condition);
+ safelyVisit(node.body);
+ node.updaters.accept(this);
+ } finally {
+ _overrideManager.exitScope();
}
}
+
/**
- * Return a map from the elements for the variables in the given list that have their types
- * overridden to the overriding type.
- * @param variableList the list of variables whose overriding types are to be captured
- * @return a table mapping elements to their overriding types
+ * Return the best type information available for the given element. If the type of the element
+ * has been overridden, then return the overriding type. Otherwise, return the static type.
+ * @param element the element for which type information is to be returned
+ * @return the best type information available for the given element
*/
- Map<Element, Type2> captureOverrides(VariableDeclarationList variableList) {
- Map<Element, Type2> overrides = new Map<Element, Type2>();
- if (StaticTypeAnalyzer.USE_TYPE_PROPAGATION) {
- if (variableList.isConst() || variableList.isFinal()) {
- for (VariableDeclaration variable in variableList.variables) {
- Element element2 = variable.element;
- if (element2 != null) {
- Type2 type = _overrideManager.getType(element2);
- if (type != null) {
- overrides[element2] = type;
- }
- }
- }
+ Type2 getBestType(Element element) {
+ Type2 bestType = _overrideManager.getType(element);
+ if (bestType == null) {
+ if (element is LocalVariableElement) {
+ bestType = ((element as LocalVariableElement)).type;
+ } else if (element is ParameterElement) {
+ bestType = ((element as ParameterElement)).type;
}
}
- return overrides;
+ return bestType;
}
+
/**
* The given expression is the expression used to compute the iterator for a for-each statement.
* Attempt to compute the type of objects that will be assigned to the loop variable and return
@@ -4049,20 +5299,8 @@
}
return null;
}
+
/**
- * Return the type of the given (overridable) element.
- * @param element the element whose type is to be returned
- * @return the type of the given element
- */
- Type2 getType(Element element) {
- if (element is LocalVariableElement) {
- return ((element as LocalVariableElement)).type;
- } else if (element is ParameterElement) {
- return ((element as ParameterElement)).type;
- }
- return null;
- }
- /**
* Return {@code true} if the given expression terminates abruptly (that is, if any expression
* following the given expression will not be reached).
* @param expression the expression being tested
@@ -4074,6 +5312,7 @@
}
return expression2 is ThrowExpression || expression2 is RethrowExpression;
}
+
/**
* Return {@code true} if the given statement terminates abruptly (that is, if any statement
* following the given statement will not be reached).
@@ -4081,7 +5320,7 @@
* @return {@code true} if the given statement terminates abruptly
*/
bool isAbruptTermination2(Statement statement) {
- if (statement is ReturnStatement) {
+ if (statement is ReturnStatement || statement is BreakStatement || statement is ContinueStatement) {
return true;
} else if (statement is ExpressionStatement) {
return isAbruptTermination(((statement as ExpressionStatement)).expression);
@@ -4095,92 +5334,74 @@
}
return false;
}
+
/**
- * If it is appropriate to do so, override the type of the given element. Use the static type and
- * inferred type of the element to determine whether or not it is appropriate.
- * @param element the element whose type might be overridden
- * @param staticType the static type of the element
- * @param inferredType the inferred type of the element
- */
- void override(VariableElement element, Type2 staticType, Type2 inferredType) {
- if (identical(inferredType, BottomTypeImpl.instance)) {
- return;
- }
- if (element is PropertyInducingElement) {
- PropertyInducingElement variable = element as PropertyInducingElement;
- if (!variable.isConst() && !variable.isFinal()) {
- return;
- }
- }
- if (staticType == null || (inferredType != null && inferredType.isMoreSpecificThan(staticType))) {
- _overrideManager.setType(element, inferredType);
- }
- }
- /**
* Propagate any type information that results from knowing that the given condition will have
- * evaluated to 'false'.
+ * been evaluated to 'false'.
* @param condition the condition that will have evaluated to 'false'
*/
void propagateFalseState(Expression condition) {
- while (condition is ParenthesizedExpression) {
- condition = ((condition as ParenthesizedExpression)).expression;
- }
- if (condition is IsExpression) {
+ if (condition is BinaryExpression) {
+ BinaryExpression binary = condition as BinaryExpression;
+ if (identical(binary.operator.type, sc.TokenType.BAR_BAR)) {
+ propagateFalseState(binary.leftOperand);
+ propagateFalseState(binary.rightOperand);
+ }
+ } else if (condition is IsExpression) {
IsExpression is2 = condition as IsExpression;
if (is2.notOperator != null) {
VariableElement element = getOverridableElement(is2.expression);
if (element != null) {
- Type2 type2 = is2.type.type;
- if (type2 != null) {
- override(element, getType(element), type2);
- }
+ override(element, is2.type.type);
}
}
- } else if (condition is BinaryExpression) {
- BinaryExpression binary = condition as BinaryExpression;
- if (identical(binary.operator.type, sc.TokenType.BAR_BAR)) {
- propagateFalseState(binary.leftOperand);
- propagateFalseState(binary.rightOperand);
+ } else if (condition is PrefixExpression) {
+ PrefixExpression prefix = condition as PrefixExpression;
+ if (identical(prefix.operator.type, sc.TokenType.BANG)) {
+ propagateTrueState(prefix.operand);
}
+ } else if (condition is ParenthesizedExpression) {
+ propagateFalseState(((condition as ParenthesizedExpression)).expression);
}
}
+
/**
+ * Propagate any type information that results from knowing that the given expression will have
+ * been evaluated without altering the flow of execution.
+ * @param expression the expression that will have been evaluated
+ */
+ void propagateState(Expression expression) {
+ }
+
+ /**
* Propagate any type information that results from knowing that the given condition will have
- * evaluated to 'true'.
+ * been evaluated to 'true'.
* @param condition the condition that will have evaluated to 'true'
*/
void propagateTrueState(Expression condition) {
- while (condition is ParenthesizedExpression) {
- condition = ((condition as ParenthesizedExpression)).expression;
- }
- if (condition is IsExpression) {
+ if (condition is BinaryExpression) {
+ BinaryExpression binary = condition as BinaryExpression;
+ if (identical(binary.operator.type, sc.TokenType.AMPERSAND_AMPERSAND)) {
+ propagateTrueState(binary.leftOperand);
+ propagateTrueState(binary.rightOperand);
+ }
+ } else if (condition is IsExpression) {
IsExpression is2 = condition as IsExpression;
if (is2.notOperator == null) {
VariableElement element = getOverridableElement(is2.expression);
if (element != null) {
- Type2 type2 = is2.type.type;
- if (type2 != null) {
- override(element, getType(element), type2);
- }
+ override(element, is2.type.type);
}
}
- } else if (condition is BinaryExpression) {
- BinaryExpression binary = condition as BinaryExpression;
- if (identical(binary.operator.type, sc.TokenType.AMPERSAND_AMPERSAND)) {
- propagateTrueState(binary.leftOperand);
- propagateTrueState(binary.rightOperand);
+ } else if (condition is PrefixExpression) {
+ PrefixExpression prefix = condition as PrefixExpression;
+ if (identical(prefix.operator.type, sc.TokenType.BANG)) {
+ propagateFalseState(prefix.operand);
}
+ } else if (condition is ParenthesizedExpression) {
+ propagateTrueState(((condition as ParenthesizedExpression)).expression);
}
}
- /**
- * Visit the given AST node if it is not null.
- * @param node the node to be visited
- */
- void safelyVisit(ASTNode node) {
- if (node != null) {
- node.accept(this);
- }
- }
get elementResolver_J2DAccessor => _elementResolver;
set elementResolver_J2DAccessor(__v) => _elementResolver = __v;
get labelScope_J2DAccessor => _labelScope;
@@ -4192,36 +5413,44 @@
get enclosingClass_J2DAccessor => _enclosingClass;
set enclosingClass_J2DAccessor(__v) => _enclosingClass = __v;
}
+
/**
* The abstract class {@code ScopedVisitor} maintains name and label scopes as an AST structure is
* being visited.
* @coverage dart.engine.resolver
*/
abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
+
/**
* The element for the library containing the compilation unit being visited.
*/
LibraryElement _definingLibrary;
+
/**
* The source representing the compilation unit being visited.
*/
Source _source;
+
/**
* The error listener that will be informed of any errors that are found during resolution.
*/
AnalysisErrorListener _errorListener;
+
/**
* The scope used to resolve identifiers.
*/
Scope _nameScope;
+
/**
* The object used to access the types from the core library.
*/
TypeProvider _typeProvider;
+
/**
* The scope used to resolve labels for {@code break} and {@code continue} statements, or{@code null} if no labels have been defined in the current context.
*/
LabelScope _labelScope;
+
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param library the library containing the compilation unit being resolved
@@ -4229,9 +5458,9 @@
* @param typeProvider the object used to access the types from the core library
*/
ScopedVisitor.con1(Library library, Source source2, TypeProvider typeProvider2) {
- _jtd_constructor_268_impl(library, source2, typeProvider2);
+ _jtd_constructor_274_impl(library, source2, typeProvider2);
}
- _jtd_constructor_268_impl(Library library, Source source2, TypeProvider typeProvider2) {
+ _jtd_constructor_274_impl(Library library, Source source2, TypeProvider typeProvider2) {
this._definingLibrary = library.libraryElement;
this._source = source2;
LibraryScope libraryScope2 = library.libraryScope;
@@ -4239,6 +5468,7 @@
this._nameScope = libraryScope2;
this._typeProvider = typeProvider2;
}
+
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param definingLibrary the element for the library containing the compilation unit being
@@ -4249,20 +5479,22 @@
* during resolution
*/
ScopedVisitor.con2(LibraryElement definingLibrary2, Source source2, TypeProvider typeProvider2, AnalysisErrorListener errorListener2) {
- _jtd_constructor_269_impl(definingLibrary2, source2, typeProvider2, errorListener2);
+ _jtd_constructor_275_impl(definingLibrary2, source2, typeProvider2, errorListener2);
}
- _jtd_constructor_269_impl(LibraryElement definingLibrary2, Source source2, TypeProvider typeProvider2, AnalysisErrorListener errorListener2) {
+ _jtd_constructor_275_impl(LibraryElement definingLibrary2, Source source2, TypeProvider typeProvider2, AnalysisErrorListener errorListener2) {
this._definingLibrary = definingLibrary2;
this._source = source2;
this._errorListener = errorListener2;
this._nameScope = new LibraryScope(definingLibrary2, errorListener2);
this._typeProvider = typeProvider2;
}
+
/**
* Return the library element for the library containing the compilation unit being resolved.
* @return the library element for the library containing the compilation unit being resolved
*/
LibraryElement get definingLibrary => _definingLibrary;
+
/**
* Return the object used to access the types from the core library.
* @return the object used to access the types from the core library
@@ -4363,7 +5595,7 @@
Scope outerNameScope = _nameScope;
_nameScope = new EnclosedScope(_nameScope);
try {
- super.visitForStatement(node);
+ visitForStatementInScope(node);
} finally {
_nameScope = outerNameScope;
_labelScope = outerLabelScope;
@@ -4385,16 +5617,20 @@
return null;
}
Object visitFunctionExpression(FunctionExpression node) {
- Scope outerScope = _nameScope;
- try {
- ExecutableElement functionElement = node.element;
- if (functionElement == null) {
- } else {
- _nameScope = new FunctionScope(_nameScope, functionElement);
+ if (node.parent is FunctionDeclaration) {
+ super.visitFunctionExpression(node);
+ } else {
+ Scope outerScope = _nameScope;
+ try {
+ ExecutableElement functionElement = node.element;
+ if (functionElement == null) {
+ } else {
+ _nameScope = new FunctionScope(_nameScope, functionElement);
+ }
+ super.visitFunctionExpression(node);
+ } finally {
+ _nameScope = outerScope;
}
- super.visitFunctionExpression(node);
- } finally {
- _nameScope = outerScope;
}
return null;
}
@@ -4429,26 +5665,22 @@
}
Object visitSwitchCase(SwitchCase node) {
node.expression.accept(this);
- LabelScope outerLabelScope = addScopesFor(node.labels);
Scope outerNameScope = _nameScope;
_nameScope = new EnclosedScope(_nameScope);
try {
node.statements.accept(this);
} finally {
_nameScope = outerNameScope;
- _labelScope = outerLabelScope;
}
return null;
}
Object visitSwitchDefault(SwitchDefault node) {
- LabelScope outerLabelScope = addScopesFor(node.labels);
Scope outerNameScope = _nameScope;
_nameScope = new EnclosedScope(_nameScope);
try {
node.statements.accept(this);
} finally {
_nameScope = outerNameScope;
- _labelScope = outerLabelScope;
}
return null;
}
@@ -4459,7 +5691,7 @@
for (Label label in member.labels) {
SimpleIdentifier labelName = label.label;
LabelElement labelElement = labelName.element as LabelElement;
- _labelScope = new LabelScope.con2(outerScope, labelName.name, labelElement);
+ _labelScope = new LabelScope.con2(_labelScope, labelName.name, labelElement);
}
}
try {
@@ -4489,16 +5721,19 @@
}
return null;
}
+
/**
* Return the label scope in which the current node is being resolved.
* @return the label scope in which the current node is being resolved
*/
LabelScope get labelScope => _labelScope;
+
/**
* Return the name scope in which the current node is being resolved.
* @return the name scope in which the current node is being resolved
*/
Scope get nameScope => _nameScope;
+
/**
* Report an error with the given error code and arguments.
* @param errorCode the error code of the error to be reported
@@ -4508,25 +5743,61 @@
void reportError(ErrorCode errorCode, ASTNode node, List<Object> arguments) {
_errorListener.onError(new AnalysisError.con2(_source, node.offset, node.length, errorCode, arguments));
}
+
/**
* Report an error with the given error code and arguments.
* @param errorCode the error code of the error to be reported
+ * @param offset the offset of the location of the error
+ * @param length the length of the location of the error
+ * @param arguments the arguments to the error, used to compose the error message
+ */
+ void reportError5(ErrorCode errorCode, int offset, int length, List<Object> arguments) {
+ _errorListener.onError(new AnalysisError.con2(_source, offset, length, errorCode, arguments));
+ }
+
+ /**
+ * Report an error with the given error code and arguments.
+ * @param errorCode the error code of the error to be reported
* @param token the token specifying the location of the error
* @param arguments the arguments to the error, used to compose the error message
*/
- void reportError3(ErrorCode errorCode, sc.Token token, List<Object> arguments) {
+ void reportError6(ErrorCode errorCode, sc.Token token, List<Object> arguments) {
_errorListener.onError(new AnalysisError.con2(_source, token.offset, token.length, errorCode, arguments));
}
+
/**
+ * Visit the given AST node if it is not null.
+ * @param node the node to be visited
+ */
+ void safelyVisit(ASTNode node) {
+ if (node != null) {
+ node.accept(this);
+ }
+ }
+
+ /**
* Visit the given statement after it's scope has been created. This replaces the normal call to
* the inherited visit method so that ResolverVisitor can intervene when type propagation is
* enabled.
* @param node the statement to be visited
*/
void visitForEachStatementInScope(ForEachStatement node) {
- super.visitForEachStatement(node);
+ safelyVisit(node.iterator);
+ safelyVisit(node.loopVariable);
+ safelyVisit(node.body);
}
+
/**
+ * Visit the given statement after it's scope has been created. This replaces the normal call to
+ * the inherited visit method so that ResolverVisitor can intervene when type propagation is
+ * enabled.
+ * @param node the statement to be visited
+ */
+ void visitForStatementInScope(ForStatement node) {
+ super.visitForStatement(node);
+ }
+
+ /**
* Add scopes for each of the given labels.
* @param labels the labels for which new scopes are to be added
* @return the scope that was in effect before the new scopes were added
@@ -4542,6 +5813,7 @@
return outerScope;
}
}
+
/**
* Instances of the class {@code StaticTypeAnalyzer} perform two type-related tasks. First, they
* compute the static type of every expression. Second, they look for any static type errors or
@@ -4553,6 +5825,7 @@
* @coverage dart.engine.resolver
*/
class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
+
/**
* Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
* implement those tags.
@@ -4620,36 +5893,39 @@
map["video"] = "VideoElement";
return map;
}
+
/**
* The resolver driving the resolution and type analysis.
*/
ResolverVisitor _resolver;
+
/**
* The object providing access to the types defined by the language.
*/
TypeProvider _typeProvider;
+
/**
* The type representing the type 'dynamic'.
*/
Type2 _dynamicType;
+
/**
* The type representing the class containing the nodes being analyzed, or {@code null} if the
* nodes are not within a class.
*/
InterfaceType _thisType;
+
/**
* The object keeping track of which elements have had their types overridden.
*/
TypeOverrideManager _overrideManager;
+
/**
- * A flag indicating whether type propagation should be enabled.
- */
- static bool USE_TYPE_PROPAGATION = true;
- /**
* A table mapping HTML tag names to the names of the classes (in 'dart:html') that implement
* those tags.
*/
static Map<String, String> _HTML_ELEMENT_TO_CLASS_MAP = createHtmlTagToClassMap();
+
/**
* Initialize a newly created type analyzer.
* @param resolver the resolver driving this participant
@@ -4660,6 +5936,7 @@
_dynamicType = _typeProvider.dynamicType;
_overrideManager = resolver.overrideManager;
}
+
/**
* Set the type of the class being analyzed to the given type.
* @param thisType the type representing the class containing the nodes being analyzed
@@ -4667,15 +5944,24 @@
void set thisType(InterfaceType thisType2) {
this._thisType = thisType2;
}
+
/**
* The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is{@code String}.</blockquote>
*/
- Object visitAdjacentStrings(AdjacentStrings node) => recordType(node, _typeProvider.stringType);
+ Object visitAdjacentStrings(AdjacentStrings node) {
+ recordStaticType(node, _typeProvider.stringType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.33: <blockquote>The static type of an argument definition
* test is {@code bool}.</blockquote>
*/
- Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) => recordType(node, _typeProvider.boolType);
+ Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) {
+ recordStaticType(node, _typeProvider.boolType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.32: <blockquote>... the cast expression <i>e as T</i> ...
* <p>
@@ -4684,10 +5970,14 @@
* <p>
* The static type of a cast expression <i>e as T</i> is <i>T</i>.</blockquote>
*/
- Object visitAsExpression(AsExpression node) => recordType(node, getType4(node.type));
+ Object visitAsExpression(AsExpression node) {
+ recordStaticType(node, getType2(node.type));
+ return null;
+ }
+
/**
- * The Dart Language Specification, 12.18: <blockquote> ... an assignment <i>a</i> of the form
- * <i>v = e</i> ...
+ * The Dart Language Specification, 12.18: <blockquote>... an assignment <i>a</i> of the form <i>v
+ * = e</i> ...
* <p>
* It is a static type warning if the static type of <i>e</i> may not be assigned to the static
* type of <i>v</i>.
@@ -4722,22 +6012,41 @@
* <i>e<sub>2</sub></i>. A compound assignment of the form <i>e<sub>1</sub>\[e<sub>2</sub>\] op=
* e<sub>3</sub></i> is equivalent to <i>((a, i) => a\[i\] = a\[i\] op e<sub>3</sub>)(e<sub>1</sub>,
* e<sub>2</sub>)</i> where <i>a</i> and <i>i</i> are a variables that are not used in
- * <i>e<sub>3</sub></i>. </blockquote>
+ * <i>e<sub>3</sub></i>.</blockquote>
*/
Object visitAssignmentExpression(AssignmentExpression node) {
sc.TokenType operator2 = node.operator.type;
- if (operator2 != sc.TokenType.EQ) {
- return recordReturnType(node, node.element);
- }
- Type2 rightType = getType2(node.rightHandSide);
- if (USE_TYPE_PROPAGATION) {
+ if (identical(operator2, sc.TokenType.EQ)) {
+ Expression rightHandSide2 = node.rightHandSide;
+ Type2 staticType = getStaticType(rightHandSide2);
+ recordStaticType(node, staticType);
+ Type2 overrideType = staticType;
+ Type2 propagatedType = getPropagatedType(rightHandSide2);
+ if (propagatedType != null) {
+ if (propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ overrideType = propagatedType;
+ }
VariableElement element = _resolver.getOverridableElement(node.leftHandSide);
if (element != null) {
- override(element, getType(element), rightType);
+ _resolver.override(element, overrideType);
}
+ } else {
+ ExecutableElement staticMethodElement = node.staticElement;
+ Type2 staticType = computeReturnType(staticMethodElement);
+ recordStaticType(node, staticType);
+ MethodElement propagatedMethodElement = node.element;
+ if (propagatedMethodElement != staticMethodElement) {
+ Type2 propagatedType = computeReturnType(propagatedMethodElement);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ }
}
- return recordType(node, rightType);
+ return null;
}
+
/**
* The Dart Language Specification, 12.20: <blockquote>The static type of a logical boolean
* expression is {@code bool}.</blockquote>
@@ -4776,35 +6085,40 @@
* <i>super.op(e<sub>2</sub>)</i>.</blockquote>
*/
Object visitBinaryExpression(BinaryExpression node) {
- sc.TokenType operator2 = node.operator.type;
- while (true) {
- if (operator2 == sc.TokenType.AMPERSAND_AMPERSAND || operator2 == sc.TokenType.BAR_BAR || operator2 == sc.TokenType.EQ_EQ || operator2 == sc.TokenType.BANG_EQ) {
- return recordType(node, _typeProvider.boolType);
- } else if (operator2 == sc.TokenType.MINUS || operator2 == sc.TokenType.PERCENT || operator2 == sc.TokenType.PLUS || operator2 == sc.TokenType.STAR || operator2 == sc.TokenType.TILDE_SLASH) {
- Type2 intType2 = _typeProvider.intType;
- if (identical(getType2(node.leftOperand), intType2) && identical(getType2(node.rightOperand), intType2)) {
- return recordType(node, intType2);
- }
- } else if (operator2 == sc.TokenType.SLASH) {
- Type2 doubleType2 = _typeProvider.doubleType;
- if (identical(getType2(node.leftOperand), doubleType2) || identical(getType2(node.rightOperand), doubleType2)) {
- return recordType(node, doubleType2);
- }
+ ExecutableElement staticMethodElement = node.staticElement;
+ Type2 staticType = computeReturnType(staticMethodElement);
+ staticType = refineBinaryExpressionType(node, staticType);
+ recordStaticType(node, staticType);
+ MethodElement propagatedMethodElement = node.element;
+ if (propagatedMethodElement != staticMethodElement) {
+ Type2 propagatedType = computeReturnType(propagatedMethodElement);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
}
- break;
}
- return recordReturnType(node, node.element);
+ return null;
}
+
/**
- * The Dart Language Specification, 12.4: <blockquote>The static type of a boolean literal is{@code bool}.</blockquote>
+ * The Dart Language Specification, 12.4: <blockquote>The static type of a boolean literal is
+ * bool.</blockquote>
*/
- Object visitBooleanLiteral(BooleanLiteral node) => recordType(node, _typeProvider.boolType);
+ Object visitBooleanLiteral(BooleanLiteral node) {
+ recordStaticType(node, _typeProvider.boolType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.15.2: <blockquote>A cascaded method invocation expression
* of the form <i>e..suffix</i> is equivalent to the expression <i>(t) {t.suffix; return
* t;}(e)</i>.</blockquote>
*/
- Object visitCascadeExpression(CascadeExpression node) => recordType(node, getType2(node.target));
+ Object visitCascadeExpression(CascadeExpression node) {
+ recordStaticType(node, getStaticType(node.target));
+ recordPropagatedType(node, getPropagatedType(node.target));
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.19: <blockquote> ... a conditional expression <i>c</i> of
* the form <i>e<sub>1</sub> ? e<sub>2</sub> : e<sub>3</sub></i> ...
@@ -4815,24 +6129,52 @@
* and the static type of <i>e<sub>3</sub></i>.</blockquote>
*/
Object visitConditionalExpression(ConditionalExpression node) {
- Type2 thenType = getType2(node.thenExpression);
- Type2 elseType = getType2(node.elseExpression);
- if (thenType == null) {
- return recordType(node, _dynamicType);
+ Type2 staticThenType = getStaticType(node.thenExpression);
+ Type2 staticElseType = getStaticType(node.elseExpression);
+ if (staticThenType == null) {
+ staticThenType = _dynamicType;
}
- Type2 resultType = thenType.getLeastUpperBound(elseType);
- return recordType(node, resultType);
+ if (staticElseType == null) {
+ staticElseType = _dynamicType;
+ }
+ Type2 staticType = staticThenType.getLeastUpperBound(staticElseType);
+ if (staticType == null) {
+ staticType = _dynamicType;
+ }
+ recordStaticType(node, staticType);
+ Type2 propagatedThenType = getPropagatedType(node.thenExpression);
+ Type2 propagatedElseType = getPropagatedType(node.elseExpression);
+ if (propagatedThenType != null || propagatedElseType != null) {
+ if (propagatedThenType == null) {
+ propagatedThenType = staticThenType;
+ }
+ if (propagatedElseType == null) {
+ propagatedElseType = staticElseType;
+ }
+ Type2 propagatedType = propagatedThenType.getLeastUpperBound(propagatedElseType);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ }
+ return null;
}
+
/**
- * The Dart Language Specification, 12.3: <blockquote>The static type of a literal double is{@code double}.</blockquote>
+ * The Dart Language Specification, 12.3: <blockquote>The static type of a literal double is
+ * double.</blockquote>
*/
- Object visitDoubleLiteral(DoubleLiteral node) => recordType(node, _typeProvider.doubleType);
+ Object visitDoubleLiteral(DoubleLiteral node) {
+ recordStaticType(node, _typeProvider.doubleType);
+ return null;
+ }
Object visitFunctionDeclaration(FunctionDeclaration node) {
FunctionExpression function = node.functionExpression;
FunctionTypeImpl functionType = node.element.type as FunctionTypeImpl;
- setTypeInformation(functionType, computeReturnType(node), function.parameters);
- return recordType(function, functionType);
+ setTypeInformation(functionType, computeReturnType2(node), function.parameters);
+ recordStaticType(function, functionType);
+ return null;
}
+
/**
* The Dart Language Specification, 12.9: <blockquote>The static type of a function literal of the
* form <i>(T<sub>1</sub> a<sub>1</sub>, &hellip;, T<sub>n</sub> a<sub>n</sub>, \[T<sub>n+1</sub>
@@ -4868,9 +6210,11 @@
return null;
}
FunctionTypeImpl functionType = node.element.type as FunctionTypeImpl;
- setTypeInformation(functionType, computeReturnType2(node), node.parameters);
- return recordType(node, functionType);
+ setTypeInformation(functionType, computeReturnType3(node), node.parameters);
+ recordStaticType(node, functionType);
+ return null;
}
+
/**
* The Dart Language Specification, 12.14.4: <blockquote>A function expression invocation <i>i</i>
* has the form <i>e<sub>f</sub>(a<sub>1</sub>, &hellip;, a<sub>n</sub>, x<sub>n+1</sub>:
@@ -4883,7 +6227,20 @@
* If <i>F</i> is not a function type, the static type of <i>i</i> is dynamic. Otherwise the
* static type of <i>i</i> is the declared return type of <i>F</i>.</blockquote>
*/
- Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) => recordReturnType(node, node.element);
+ Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+ ExecutableElement staticMethodElement = node.staticElement;
+ Type2 staticType = computeReturnType(staticMethodElement);
+ recordStaticType(node, staticType);
+ ExecutableElement propagatedMethodElement = node.element;
+ Type2 propagatedType = computeReturnType(propagatedMethodElement);
+ if (staticType == null) {
+ recordStaticType(node, propagatedType);
+ } else if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.29: <blockquote>An assignable expression of the form
* <i>e<sub>1</sub>\[e<sub>2</sub>\]</i> is evaluated as a method invocation of the operator method
@@ -4891,10 +6248,31 @@
*/
Object visitIndexExpression(IndexExpression node) {
if (node.inSetterContext()) {
- return recordArgumentType(node, node.element);
+ ExecutableElement staticMethodElement = node.staticElement;
+ Type2 staticType = computeArgumentType(staticMethodElement);
+ recordStaticType(node, staticType);
+ MethodElement propagatedMethodElement = node.element;
+ if (propagatedMethodElement != staticMethodElement) {
+ Type2 propagatedType = computeArgumentType(propagatedMethodElement);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ }
+ } else {
+ ExecutableElement staticMethodElement = node.staticElement;
+ Type2 staticType = computeReturnType(staticMethodElement);
+ recordStaticType(node, staticType);
+ MethodElement propagatedMethodElement = node.element;
+ if (propagatedMethodElement != staticMethodElement) {
+ Type2 propagatedType = computeReturnType(propagatedMethodElement);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ }
}
- return recordReturnType(node, node.element);
+ return null;
}
+
/**
* The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
* either the form <i>new T.id(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> or the form <i>new
@@ -4905,31 +6283,39 @@
* form <i>const T(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> is <i>T</i>. </blockquote>
*/
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
- if (USE_TYPE_PROPAGATION) {
- ConstructorElement element2 = node.element;
- if (element2 != null && "Element" == element2.enclosingElement.name && "tag" == element2.name) {
- LibraryElement library2 = element2.library;
- if (isHtmlLibrary(library2)) {
- Type2 returnType = getFirstArgumentAsType2(library2, node.argumentList, _HTML_ELEMENT_TO_CLASS_MAP);
- if (returnType != null) {
- return recordType(node, returnType);
- }
+ recordStaticType(node, node.constructorName.type.type);
+ ConstructorElement element2 = node.element;
+ if (element2 != null && "Element" == element2.enclosingElement.name && "tag" == element2.name) {
+ LibraryElement library2 = element2.library;
+ if (isHtmlLibrary(library2)) {
+ Type2 returnType = getFirstArgumentAsType2(library2, node.argumentList, _HTML_ELEMENT_TO_CLASS_MAP);
+ if (returnType != null) {
+ recordPropagatedType(node, returnType);
}
}
}
- return recordType(node, node.constructorName.type.type);
+ return null;
}
+
/**
* The Dart Language Specification, 12.3: <blockquote>The static type of an integer literal is{@code int}.</blockquote>
*/
- Object visitIntegerLiteral(IntegerLiteral node) => recordType(node, _typeProvider.intType);
+ Object visitIntegerLiteral(IntegerLiteral node) {
+ recordStaticType(node, _typeProvider.intType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.31: <blockquote>It is a static warning if <i>T</i> does not
* denote a type available in the current lexical scope.
* <p>
* The static type of an is-expression is {@code bool}.</blockquote>
*/
- Object visitIsExpression(IsExpression node) => recordType(node, _typeProvider.boolType);
+ Object visitIsExpression(IsExpression node) {
+ recordStaticType(node, _typeProvider.boolType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.6: <blockquote>The static type of a list literal of the
* form <i><b>const</b> &lt;E&gt;\[e<sub>1</sub>, &hellip;, e<sub>n</sub>\]</i> or the form
@@ -4938,16 +6324,41 @@
* the form <i>\[e<sub>1</sub>, &hellip;, e<sub>n</sub>\]</i> is {@code List&lt;dynamic&gt;}.</blockquote>
*/
Object visitListLiteral(ListLiteral node) {
+ Type2 staticType = _dynamicType;
TypeArgumentList typeArguments2 = node.typeArguments;
if (typeArguments2 != null) {
NodeList<TypeName> arguments2 = typeArguments2.arguments;
if (arguments2 != null && arguments2.length == 1) {
- TypeName argumentType = arguments2[0];
- return recordType(node, _typeProvider.listType.substitute5(<Type2> [getType4(argumentType)]));
+ TypeName argumentTypeName = arguments2[0];
+ Type2 argumentType = getType2(argumentTypeName);
+ if (argumentType != null) {
+ staticType = argumentType;
+ }
}
}
- return recordType(node, _typeProvider.listType.substitute5(<Type2> [_dynamicType]));
+ recordStaticType(node, _typeProvider.listType.substitute5(<Type2> [staticType]));
+ NodeList<Expression> elements2 = node.elements;
+ int count = elements2.length;
+ if (count > 0) {
+ Type2 propagatedType = getBestType(elements2[0]);
+ for (int i = 1; i < count; i++) {
+ Type2 elementType = getBestType(elements2[i]);
+ if (propagatedType != elementType) {
+ propagatedType = _dynamicType;
+ } else {
+ propagatedType = propagatedType.getLeastUpperBound(elementType);
+ if (propagatedType == null) {
+ propagatedType = _dynamicType;
+ }
+ }
+ }
+ if (propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, _typeProvider.listType.substitute5(<Type2> [propagatedType]));
+ }
+ }
+ return null;
}
+
/**
* The Dart Language Specification, 12.7: <blockquote>The static type of a map literal of the form
* <i><b>const</b> &lt;String, V&gt; {k<sub>1</sub>:e<sub>1</sub>, &hellip;,
@@ -4961,19 +6372,67 @@
* <i>String</i>.</blockquote>
*/
Object visitMapLiteral(MapLiteral node) {
+ Type2 staticKeyType = _dynamicType;
+ Type2 staticValueType = _dynamicType;
TypeArgumentList typeArguments2 = node.typeArguments;
if (typeArguments2 != null) {
NodeList<TypeName> arguments2 = typeArguments2.arguments;
if (arguments2 != null && arguments2.length == 2) {
- TypeName keyType = arguments2[0];
- if (keyType != _typeProvider.stringType) {
+ TypeName entryKeyTypeName = arguments2[0];
+ Type2 entryKeyType = getType2(entryKeyTypeName);
+ if (entryKeyType != null) {
+ staticKeyType = entryKeyType;
}
- TypeName valueType = arguments2[1];
- return recordType(node, _typeProvider.mapType.substitute5(<Type2> [_typeProvider.stringType, getType4(valueType)]));
+ TypeName entryValueTypeName = arguments2[1];
+ Type2 entryValueType = getType2(entryValueTypeName);
+ if (entryValueType != null) {
+ staticValueType = entryValueType;
+ }
}
}
- return recordType(node, _typeProvider.mapType.substitute5(<Type2> [_typeProvider.stringType, _dynamicType]));
+ recordStaticType(node, _typeProvider.mapType.substitute5(<Type2> [staticKeyType, staticValueType]));
+ NodeList<MapLiteralEntry> entries2 = node.entries;
+ int count = entries2.length;
+ if (count > 0) {
+ MapLiteralEntry entry = entries2[0];
+ Type2 propagatedKeyType = getBestType(entry.key);
+ Type2 propagatedValueType = getBestType(entry.value);
+ for (int i = 1; i < count; i++) {
+ entry = entries2[i];
+ Type2 elementKeyType = getBestType(entry.key);
+ if (propagatedKeyType != elementKeyType) {
+ propagatedKeyType = _dynamicType;
+ } else {
+ propagatedKeyType = propagatedKeyType.getLeastUpperBound(elementKeyType);
+ if (propagatedKeyType == null) {
+ propagatedKeyType = _dynamicType;
+ }
+ }
+ Type2 elementValueType = getBestType(entry.value);
+ if (propagatedValueType != elementValueType) {
+ propagatedValueType = _dynamicType;
+ } else {
+ propagatedValueType = propagatedValueType.getLeastUpperBound(elementValueType);
+ if (propagatedValueType == null) {
+ propagatedValueType = _dynamicType;
+ }
+ }
+ }
+ bool betterKey = propagatedKeyType != null && propagatedKeyType.isMoreSpecificThan(staticKeyType);
+ bool betterValue = propagatedValueType != null && propagatedValueType.isMoreSpecificThan(staticValueType);
+ if (betterKey || betterValue) {
+ if (!betterKey) {
+ propagatedKeyType = staticKeyType;
+ }
+ if (!betterValue) {
+ propagatedValueType = staticValueType;
+ }
+ recordPropagatedType(node, _typeProvider.mapType.substitute5(<Type2> [propagatedKeyType, propagatedValueType]));
+ }
+ }
+ return null;
}
+
/**
* The Dart Language Specification, 12.15.1: <blockquote>An ordinary method invocation <i>i</i>
* has the form <i>o.m(a<sub>1</sub>, &hellip;, a<sub>n</sub>, x<sub>n+1</sub>: a<sub>n+1</sub>,
@@ -5011,63 +6470,103 @@
* <i>F</i>.</blockquote>
*/
Object visitMethodInvocation(MethodInvocation node) {
- if (USE_TYPE_PROPAGATION) {
- String methodName2 = node.methodName.name;
- if (methodName2 == "\$dom_createEvent") {
- Expression target = node.realTarget;
- if (target != null) {
- Type2 targetType = getType2(target);
- if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
- LibraryElement library2 = targetType.element.library;
- if (isHtmlLibrary(library2)) {
- Type2 returnType = getFirstArgumentAsType(library2, node.argumentList);
- if (returnType != null) {
- return recordType(node, returnType);
- }
+ SimpleIdentifier methodNameNode = node.methodName;
+ Element staticMethodElement = methodNameNode.staticElement;
+ if (staticMethodElement == null) {
+ staticMethodElement = methodNameNode.element;
+ }
+ Type2 staticType = computeReturnType(staticMethodElement);
+ recordStaticType(node, staticType);
+ String methodName = methodNameNode.name;
+ if (methodName == "\$dom_createEvent") {
+ Expression target = node.realTarget;
+ if (target != null) {
+ Type2 targetType = getBestType(target);
+ if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
+ LibraryElement library2 = targetType.element.library;
+ if (isHtmlLibrary(library2)) {
+ Type2 returnType = getFirstArgumentAsType(library2, node.argumentList);
+ if (returnType != null) {
+ recordPropagatedType(node, returnType);
}
}
}
- } else if (methodName2 == "query") {
- Expression target = node.realTarget;
- if (target == null) {
- Element methodElement = node.methodName.element;
- if (methodElement != null) {
- LibraryElement library3 = methodElement.library;
- if (isHtmlLibrary(library3)) {
- Type2 returnType = getFirstArgumentAsQuery(library3, node.argumentList);
- if (returnType != null) {
- return recordType(node, returnType);
- }
+ }
+ } else if (methodName == "query") {
+ Expression target = node.realTarget;
+ if (target == null) {
+ Element methodElement = methodNameNode.element;
+ if (methodElement != null) {
+ LibraryElement library3 = methodElement.library;
+ if (isHtmlLibrary(library3)) {
+ Type2 returnType = getFirstArgumentAsQuery(library3, node.argumentList);
+ if (returnType != null) {
+ recordPropagatedType(node, returnType);
}
}
- } else {
- Type2 targetType = getType2(target);
- if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
- LibraryElement library4 = targetType.element.library;
- if (isHtmlLibrary(library4)) {
- Type2 returnType = getFirstArgumentAsQuery(library4, node.argumentList);
- if (returnType != null) {
- return recordType(node, returnType);
- }
+ }
+ } else {
+ Type2 targetType = getBestType(target);
+ if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
+ LibraryElement library4 = targetType.element.library;
+ if (isHtmlLibrary(library4)) {
+ Type2 returnType = getFirstArgumentAsQuery(library4, node.argumentList);
+ if (returnType != null) {
+ recordPropagatedType(node, returnType);
}
}
}
- } else if (methodName2 == "JS") {
- Type2 returnType = getFirstArgumentAsType(_typeProvider.objectType.element.library, node.argumentList);
- if (returnType != null) {
- return recordType(node, returnType);
+ }
+ } else if (methodName == "\$dom_createElement") {
+ Expression target = node.realTarget;
+ Type2 targetType = getBestType(target);
+ if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
+ LibraryElement library5 = targetType.element.library;
+ if (isHtmlLibrary(library5)) {
+ Type2 returnType = getFirstArgumentAsQuery(library5, node.argumentList);
+ if (returnType != null) {
+ recordPropagatedType(node, returnType);
+ }
}
}
+ } else if (methodName == "JS") {
+ Type2 returnType = getFirstArgumentAsType(_typeProvider.objectType.element.library, node.argumentList);
+ if (returnType != null) {
+ recordPropagatedType(node, returnType);
+ }
+ } else {
+ Element propagatedElement = methodNameNode.element;
+ if (propagatedElement != staticMethodElement) {
+ Type2 propagatedType = computeReturnType(propagatedElement);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ }
}
- return recordReturnType(node, node.methodName.element);
+ return null;
}
- Object visitNamedExpression(NamedExpression node) => recordType(node, getType2(node.expression));
+ Object visitNamedExpression(NamedExpression node) {
+ Expression expression2 = node.expression;
+ recordStaticType(node, getStaticType(expression2));
+ recordPropagatedType(node, getPropagatedType(expression2));
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.2: <blockquote>The static type of {@code null} is bottom.
* </blockquote>
*/
- Object visitNullLiteral(NullLiteral node) => recordType(node, _typeProvider.bottomType);
- Object visitParenthesizedExpression(ParenthesizedExpression node) => recordType(node, getType2(node.expression));
+ Object visitNullLiteral(NullLiteral node) {
+ recordStaticType(node, _typeProvider.bottomType);
+ return null;
+ }
+ Object visitParenthesizedExpression(ParenthesizedExpression node) {
+ Expression expression2 = node.expression;
+ recordStaticType(node, getStaticType(expression2));
+ recordPropagatedType(node, getPropagatedType(expression2));
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.28: <blockquote>A postfix expression of the form
* <i>v++</i>, where <i>v</i> is an identifier, is equivalent to <i>(){var r = v; v = r + 1;
@@ -5094,47 +6593,57 @@
* A postfix expression of the form <i>e1\[e2\]--</i> is equivalent to <i>(a, i){var r = a\[i\]; a\[i\]
* = r - 1; return r}(e1, e2)</i></blockquote>
*/
- Object visitPostfixExpression(PostfixExpression node) => recordType(node, getType2(node.operand));
+ Object visitPostfixExpression(PostfixExpression node) {
+ Expression operand2 = node.operand;
+ Type2 staticType = getStaticType(operand2);
+ sc.TokenType operator2 = node.operator.type;
+ if (identical(operator2, sc.TokenType.MINUS_MINUS) || identical(operator2, sc.TokenType.PLUS_PLUS)) {
+ Type2 intType2 = _typeProvider.intType;
+ if (identical(getStaticType(node.operand), intType2)) {
+ staticType = intType2;
+ }
+ }
+ recordStaticType(node, staticType);
+ recordPropagatedType(node, getPropagatedType(operand2));
+ return null;
+ }
+
/**
* See {@link #visitSimpleIdentifier(SimpleIdentifier)}.
*/
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
SimpleIdentifier prefixedIdentifier = node.identifier;
Element element2 = prefixedIdentifier.element;
- if (element2 == null) {
- return recordType(node, _dynamicType);
- }
- if (USE_TYPE_PROPAGATION) {
- Type2 type = _overrideManager.getType(element2);
- if (type != null) {
- return recordType(node, type);
- }
- }
- Type2 type;
+ Type2 staticType = _dynamicType;
if (element2 is ClassElement) {
if (isNotTypeLiteral(node)) {
- type = ((element2 as ClassElement)).type;
+ staticType = ((element2 as ClassElement)).type;
} else {
- type = _typeProvider.typeType;
+ staticType = _typeProvider.typeType;
}
} else if (element2 is FunctionTypeAliasElement) {
- type = ((element2 as FunctionTypeAliasElement)).type;
+ staticType = ((element2 as FunctionTypeAliasElement)).type;
} else if (element2 is MethodElement) {
- type = ((element2 as MethodElement)).type;
+ staticType = ((element2 as MethodElement)).type;
} else if (element2 is PropertyAccessorElement) {
- type = getType3((element2 as PropertyAccessorElement), node.prefix.staticType);
+ staticType = getType((element2 as PropertyAccessorElement), node.prefix.staticType);
} else if (element2 is ExecutableElement) {
- type = ((element2 as ExecutableElement)).type;
+ staticType = ((element2 as ExecutableElement)).type;
} else if (element2 is TypeVariableElement) {
- type = ((element2 as TypeVariableElement)).type;
+ staticType = ((element2 as TypeVariableElement)).type;
} else if (element2 is VariableElement) {
- type = ((element2 as VariableElement)).type;
- } else {
- type = _dynamicType;
+ staticType = ((element2 as VariableElement)).type;
}
- recordType(prefixedIdentifier, type);
- return recordType(node, type);
+ recordStaticType(prefixedIdentifier, staticType);
+ recordStaticType(node, staticType);
+ Type2 propagatedType = _overrideManager.getType(element2);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(prefixedIdentifier, propagatedType);
+ recordPropagatedType(node, propagatedType);
+ }
+ return null;
}
+
/**
* The Dart Language Specification, 12.27: <blockquote>A unary expression <i>u</i> of the form
* <i>op e</i> is equivalent to a method invocation <i>expression e.op()</i>. An expression of the
@@ -5143,10 +6652,28 @@
Object visitPrefixExpression(PrefixExpression node) {
sc.TokenType operator2 = node.operator.type;
if (identical(operator2, sc.TokenType.BANG)) {
- return recordType(node, _typeProvider.boolType);
+ recordStaticType(node, _typeProvider.boolType);
+ } else {
+ ExecutableElement staticMethodElement = node.staticElement;
+ Type2 staticType = computeReturnType(staticMethodElement);
+ if (identical(operator2, sc.TokenType.MINUS_MINUS) || identical(operator2, sc.TokenType.PLUS_PLUS)) {
+ Type2 intType2 = _typeProvider.intType;
+ if (identical(getStaticType(node.operand), intType2)) {
+ staticType = intType2;
+ }
+ }
+ recordStaticType(node, staticType);
+ MethodElement propagatedMethodElement = node.element;
+ if (propagatedMethodElement != staticMethodElement) {
+ Type2 propagatedType = computeReturnType(propagatedMethodElement);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ }
}
- return recordReturnType(node, node.element);
+ return null;
}
+
/**
* The Dart Language Specification, 12.13: <blockquote> Property extraction allows for a member of
* an object to be concisely extracted from the object. If <i>o</i> is an object, and if <i>m</i>
@@ -5193,30 +6720,31 @@
Object visitPropertyAccess(PropertyAccess node) {
SimpleIdentifier propertyName2 = node.propertyName;
Element element2 = propertyName2.element;
- if (USE_TYPE_PROPAGATION) {
- Type2 type = _overrideManager.getType(element2);
- if (type != null) {
- return recordType(node, type);
- }
- }
+ Type2 staticType = _dynamicType;
if (element2 is MethodElement) {
- FunctionType type2 = ((element2 as MethodElement)).type;
- recordType(propertyName2, type2);
- return recordType(node, type2);
+ staticType = ((element2 as MethodElement)).type;
} else if (element2 is PropertyAccessorElement) {
- Type2 propertyType = getType3((element2 as PropertyAccessorElement), node.target != null ? node.target.staticType : null);
- recordType(propertyName2, propertyType);
- return recordType(node, propertyType);
+ staticType = getType((element2 as PropertyAccessorElement), node.target != null ? getStaticType(node.target) : null);
} else {
}
- recordType(propertyName2, _dynamicType);
- return recordType(node, _dynamicType);
+ recordStaticType(propertyName2, staticType);
+ recordStaticType(node, staticType);
+ Type2 propagatedType = _overrideManager.getType(element2);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ return null;
}
+
/**
* The Dart Language Specification, 12.9: <blockquote>The static type of a rethrow expression is
* bottom.</blockquote>
*/
- Object visitRethrowExpression(RethrowExpression node) => recordType(node, _typeProvider.bottomType);
+ Object visitRethrowExpression(RethrowExpression node) {
+ recordStaticType(node, _typeProvider.bottomType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.30: <blockquote>Evaluation of an identifier expression
* <i>e</i> of the form <i>id</i> proceeds as follows:
@@ -5261,99 +6789,169 @@
*/
Object visitSimpleIdentifier(SimpleIdentifier node) {
Element element2 = node.element;
- if (element2 == null) {
- return recordType(node, _dynamicType);
- }
- if (USE_TYPE_PROPAGATION) {
- Type2 type = _overrideManager.getType(element2);
- if (type != null) {
- return recordType(node, type);
- }
- }
- Type2 type;
+ Type2 staticType = _dynamicType;
if (element2 is ClassElement) {
if (isNotTypeLiteral(node)) {
- type = ((element2 as ClassElement)).type;
+ staticType = ((element2 as ClassElement)).type;
} else {
- type = _typeProvider.typeType;
+ staticType = _typeProvider.typeType;
}
} else if (element2 is FunctionTypeAliasElement) {
- type = ((element2 as FunctionTypeAliasElement)).type;
+ staticType = ((element2 as FunctionTypeAliasElement)).type;
} else if (element2 is MethodElement) {
- type = ((element2 as MethodElement)).type;
+ staticType = ((element2 as MethodElement)).type;
} else if (element2 is PropertyAccessorElement) {
- type = getType3((element2 as PropertyAccessorElement), null);
+ staticType = getType((element2 as PropertyAccessorElement), null);
} else if (element2 is ExecutableElement) {
- type = ((element2 as ExecutableElement)).type;
+ staticType = ((element2 as ExecutableElement)).type;
} else if (element2 is TypeVariableElement) {
- type = ((element2 as TypeVariableElement)).type;
+ staticType = ((element2 as TypeVariableElement)).type;
} else if (element2 is VariableElement) {
- type = ((element2 as VariableElement)).type;
+ staticType = ((element2 as VariableElement)).type;
} else if (element2 is PrefixElement) {
return null;
} else {
- type = _dynamicType;
+ staticType = _dynamicType;
}
- return recordType(node, type);
+ recordStaticType(node, staticType);
+ Type2 propagatedType = _overrideManager.getType(element2);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType(node, propagatedType);
+ }
+ return null;
}
+
/**
* The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is{@code String}.</blockquote>
*/
- Object visitSimpleStringLiteral(SimpleStringLiteral node) => recordType(node, _typeProvider.stringType);
+ Object visitSimpleStringLiteral(SimpleStringLiteral node) {
+ recordStaticType(node, _typeProvider.stringType);
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is{@code String}.</blockquote>
*/
- Object visitStringInterpolation(StringInterpolation node) => recordType(node, _typeProvider.stringType);
+ Object visitStringInterpolation(StringInterpolation node) {
+ recordStaticType(node, _typeProvider.stringType);
+ return null;
+ }
Object visitSuperExpression(SuperExpression node) {
if (_thisType == null) {
- return recordType(node, _dynamicType);
+ recordStaticType(node, _dynamicType);
} else {
- return recordType(node, _thisType.superclass);
+ recordStaticType(node, _thisType);
}
+ return null;
}
+
/**
* The Dart Language Specification, 12.10: <blockquote>The static type of {@code this} is the
* interface of the immediately enclosing class.</blockquote>
*/
Object visitThisExpression(ThisExpression node) {
if (_thisType == null) {
- return recordType(node, _dynamicType);
+ recordStaticType(node, _dynamicType);
} else {
- return recordType(node, _thisType);
+ recordStaticType(node, _thisType);
}
+ return null;
}
+
/**
* The Dart Language Specification, 12.8: <blockquote>The static type of a throw expression is
* bottom.</blockquote>
*/
- Object visitThrowExpression(ThrowExpression node) => recordType(node, _typeProvider.bottomType);
+ Object visitThrowExpression(ThrowExpression node) {
+ recordStaticType(node, _typeProvider.bottomType);
+ return null;
+ }
Object visitVariableDeclaration(VariableDeclaration node) {
- if (USE_TYPE_PROPAGATION) {
- Expression initializer2 = node.initializer;
- if (initializer2 != null) {
- Type2 rightType = getType2(initializer2);
- VariableElement element2 = node.name.element as VariableElement;
- if (element2 != null) {
- override(element2, getType(element2), rightType);
- }
+ Expression initializer2 = node.initializer;
+ if (initializer2 != null) {
+ Type2 rightType = getBestType(initializer2);
+ VariableElement element2 = node.name.element as VariableElement;
+ if (element2 != null) {
+ _resolver.override(element2, rightType);
}
}
return null;
}
+
/**
+ * Record that the static type of the given node is the type of the second argument to the method
+ * represented by the given element.
+ * @param element the element representing the method invoked by the given node
+ */
+ Type2 computeArgumentType(ExecutableElement element) {
+ if (element != null) {
+ List<ParameterElement> parameters2 = element.parameters;
+ if (parameters2 != null && parameters2.length == 2) {
+ return parameters2[1].type;
+ }
+ }
+ return _dynamicType;
+ }
+
+ /**
+ * Compute the return type of the method or function represented by the given element.
+ * @param element the element representing the method or function invoked by the given node
+ * @return the return type that was computed
+ */
+ Type2 computeReturnType(Element element) {
+ if (element is PropertyAccessorElement) {
+ FunctionType propertyType = ((element as PropertyAccessorElement)).type;
+ if (propertyType != null) {
+ Type2 returnType2 = propertyType.returnType;
+ if (returnType2 is InterfaceType) {
+ if (identical(returnType2, _typeProvider.functionType)) {
+ return _dynamicType;
+ }
+ MethodElement callMethod = ((returnType2 as InterfaceType)).lookUpMethod(ElementResolver.CALL_METHOD_NAME, _resolver.definingLibrary);
+ if (callMethod != null) {
+ return callMethod.type.returnType;
+ }
+ } else if (returnType2 is FunctionType) {
+ Type2 innerReturnType = ((returnType2 as FunctionType)).returnType;
+ if (innerReturnType != null) {
+ return innerReturnType;
+ }
+ } else if (returnType2.isDartCoreFunction()) {
+ return _dynamicType;
+ }
+ if (returnType2 != null) {
+ return returnType2;
+ }
+ }
+ } else if (element is ExecutableElement) {
+ FunctionType type2 = ((element as ExecutableElement)).type;
+ if (type2 != null) {
+ return type2.returnType;
+ }
+ } else if (element is VariableElement) {
+ Type2 variableType = ((element as VariableElement)).type;
+ if (variableType is FunctionType) {
+ return ((variableType as FunctionType)).returnType;
+ }
+ }
+ return _dynamicType;
+ }
+
+ /**
* Given a function declaration, compute the return type of the function. The return type of
* functions with a block body is {@code dynamicType}, with an expression body it is the type of
* the expression.
* @param node the function expression whose return type is to be computed
* @return the return type that was computed
*/
- Type2 computeReturnType(FunctionDeclaration node) {
+ Type2 computeReturnType2(FunctionDeclaration node) {
TypeName returnType2 = node.returnType;
if (returnType2 == null) {
- return computeReturnType2(node.functionExpression);
+ return _dynamicType;
}
return returnType2.type;
}
+
/**
* Given a function expression, compute the return type of the function. The return type of
* functions with a block body is {@code dynamicType}, with an expression body it is the type of
@@ -5361,14 +6959,32 @@
* @param node the function expression whose return type is to be computed
* @return the return type that was computed
*/
- Type2 computeReturnType2(FunctionExpression node) {
+ Type2 computeReturnType3(FunctionExpression node) {
FunctionBody body2 = node.body;
if (body2 is ExpressionFunctionBody) {
- return getType2(((body2 as ExpressionFunctionBody)).expression);
+ return getStaticType(((body2 as ExpressionFunctionBody)).expression);
}
return _dynamicType;
}
+
/**
+ * Return the propagated type of the given expression if it is available, or the static type if
+ * there is no propagated type.
+ * @param expression the expression whose type is to be returned
+ * @return the propagated or static type of the given expression
+ */
+ Type2 getBestType(Expression expression) {
+ Type2 type = expression.propagatedType;
+ if (type == null) {
+ type = expression.staticType;
+ if (type == null) {
+ return _dynamicType;
+ }
+ }
+ return type;
+ }
+
+ /**
* If the given argument list contains at least one argument, and if the argument is a simple
* string literal, then parse that argument as a query string and return the type specified by the
* argument.
@@ -5395,6 +7011,7 @@
}
return null;
}
+
/**
* If the given argument list contains at least one argument, and if the argument is a simple
* string literal, return the String value of the argument.
@@ -5411,6 +7028,7 @@
}
return null;
}
+
/**
* If the given argument list contains at least one argument, and if the argument is a simple
* string literal, and if the value of the argument is the name of a class defined within the
@@ -5420,6 +7038,7 @@
* @return the type specified by the first argument in the argument list
*/
Type2 getFirstArgumentAsType(LibraryElement library, ArgumentList argumentList) => getFirstArgumentAsType2(library, argumentList, null);
+
/**
* If the given argument list contains at least one argument, and if the argument is a simple
* string literal, and if the value of the argument is the name of a class defined within the
@@ -5441,31 +7060,30 @@
}
return null;
}
+
/**
- * Return the type of the given (overridable) element.
- * @param element the element whose type is to be returned
- * @return the type of the given element
+ * Return the propagated type of the given expression.
+ * @param expression the expression whose type is to be returned
+ * @return the propagated type of the given expression
*/
- Type2 getType(Element element) {
- if (element is LocalVariableElement) {
- return ((element as LocalVariableElement)).type;
- } else if (element is ParameterElement) {
- return ((element as ParameterElement)).type;
- }
- return null;
+ Type2 getPropagatedType(Expression expression) {
+ Type2 type = expression.propagatedType;
+ return type;
}
+
/**
- * Return the type of the given expression that is to be used for type analysis.
+ * Return the static type of the given expression.
* @param expression the expression whose type is to be returned
- * @return the type of the given expression
+ * @return the static type of the given expression
*/
- Type2 getType2(Expression expression) {
+ Type2 getStaticType(Expression expression) {
Type2 type = expression.staticType;
if (type == null) {
return _dynamicType;
}
return type;
}
+
/**
* Return the type that should be recorded for a node that resolved to the given accessor.
* @param accessor the accessor that the node resolved to
@@ -5474,7 +7092,7 @@
* specific type information
* @return the type that should be recorded for a node that resolved to the given accessor
*/
- Type2 getType3(PropertyAccessorElement accessor, Type2 context) {
+ Type2 getType(PropertyAccessorElement accessor, Type2 context) {
FunctionType functionType = accessor.type;
if (functionType == null) {
return _dynamicType;
@@ -5508,24 +7126,27 @@
}
return returnType2;
}
+
/**
* Return the type represented by the given type name.
* @param typeName the type name representing the type to be returned
* @return the type represented by the type name
*/
- Type2 getType4(TypeName typeName) {
+ Type2 getType2(TypeName typeName) {
Type2 type2 = typeName.type;
if (type2 == null) {
return _dynamicType;
}
return type2;
}
+
/**
* Return {@code true} if the given library is the 'dart:html' library.
* @param library the library being tested
* @return {@code true} if the library is 'dart:html'
*/
bool isHtmlLibrary(LibraryElement library) => library.name == "dart.dom.html";
+
/**
* Return {@code true} if the given node is not a type literal.
* @param node the node being tested
@@ -5535,92 +7156,58 @@
ASTNode parent2 = node.parent;
return parent2 is TypeName || (parent2 is PrefixedIdentifier && (parent2.parent is TypeName || identical(((parent2 as PrefixedIdentifier)).prefix, node))) || (parent2 is PropertyAccess && identical(((parent2 as PropertyAccess)).target, node)) || (parent2 is MethodInvocation && identical(node, ((parent2 as MethodInvocation)).target));
}
+
/**
- * If it is appropriate to do so, override the type of the given element. Use the static type and
- * inferred type of the element to determine whether or not it is appropriate.
- * @param element the element whose type might be overridden
- * @param staticType the static type of the element
- * @param inferredType the inferred type of the element
- */
- void override(VariableElement element, Type2 staticType, Type2 inferredType) {
- if (identical(inferredType, BottomTypeImpl.instance)) {
- return;
- }
- if (element is PropertyInducingElement) {
- PropertyInducingElement variable = element as PropertyInducingElement;
- if (!variable.isConst() && !variable.isFinal()) {
- return;
- }
- }
- if (staticType == null || (inferredType != null && inferredType.isMoreSpecificThan(staticType))) {
- _overrideManager.setType(element, inferredType);
- }
- }
- /**
- * Record that the static type of the given node is the type of the second argument to the method
- * represented by the given element.
+ * Record that the propagated type of the given node is the given type.
* @param expression the node whose type is to be recorded
- * @param element the element representing the method invoked by the given node
+ * @param type the propagated type of the node
*/
- Object recordArgumentType(IndexExpression expression, MethodElement element) {
- if (element != null) {
- List<ParameterElement> parameters2 = element.parameters;
- if (parameters2 != null && parameters2.length == 2) {
- return recordType(expression, parameters2[1].type);
- }
+ void recordPropagatedType(Expression expression, Type2 type) {
+ if (type != null && !type.isDynamic()) {
+ expression.propagatedType = type;
}
- return recordType(expression, _dynamicType);
}
+
/**
- * Record that the static type of the given node is the return type of the method or function
- * represented by the given element.
- * @param expression the node whose type is to be recorded
- * @param element the element representing the method or function invoked by the given node
- */
- Object recordReturnType(Expression expression, Element element) {
- if (element is PropertyAccessorElement) {
- FunctionType propertyType = ((element as PropertyAccessorElement)).type;
- if (propertyType != null) {
- Type2 returnType2 = propertyType.returnType;
- if (returnType2 is FunctionType) {
- Type2 innerReturnType = ((returnType2 as FunctionType)).returnType;
- if (innerReturnType != null) {
- return recordType(expression, innerReturnType);
- }
- } else if (returnType2.isDartCoreFunction()) {
- return recordType(expression, _dynamicType);
- }
- if (returnType2 != null) {
- return recordType(expression, returnType2);
- }
- }
- } else if (element is ExecutableElement) {
- FunctionType type2 = ((element as ExecutableElement)).type;
- if (type2 != null) {
- return recordType(expression, type2.returnType);
- }
- } else if (element is VariableElement) {
- Type2 variableType = ((element as VariableElement)).type;
- if (variableType is FunctionType) {
- return recordType(expression, ((variableType as FunctionType)).returnType);
- }
- }
- return recordType(expression, _dynamicType);
- }
- /**
* Record that the static type of the given node is the given type.
* @param expression the node whose type is to be recorded
* @param type the static type of the node
*/
- Object recordType(Expression expression, Type2 type) {
+ void recordStaticType(Expression expression, Type2 type) {
if (type == null) {
expression.staticType = _dynamicType;
} else {
expression.staticType = type;
}
- return null;
}
+
/**
+ * Attempts to make a better guess for the static type of the given binary expression.
+ * @param node the binary expression to analyze
+ * @param staticType the static type of the expression as resolved
+ * @return the better type guess, or the same static type as given
+ */
+ Type2 refineBinaryExpressionType(BinaryExpression node, Type2 staticType) {
+ sc.TokenType operator2 = node.operator.type;
+ if (identical(operator2, sc.TokenType.AMPERSAND_AMPERSAND) || identical(operator2, sc.TokenType.BAR_BAR) || identical(operator2, sc.TokenType.EQ_EQ) || identical(operator2, sc.TokenType.BANG_EQ)) {
+ return _typeProvider.boolType;
+ }
+ if (identical(operator2, sc.TokenType.MINUS) || identical(operator2, sc.TokenType.PERCENT) || identical(operator2, sc.TokenType.PLUS) || identical(operator2, sc.TokenType.STAR)) {
+ Type2 doubleType2 = _typeProvider.doubleType;
+ if (identical(getStaticType(node.leftOperand), doubleType2) || identical(getStaticType(node.rightOperand), doubleType2)) {
+ return doubleType2;
+ }
+ }
+ if (identical(operator2, sc.TokenType.MINUS) || identical(operator2, sc.TokenType.PERCENT) || identical(operator2, sc.TokenType.PLUS) || identical(operator2, sc.TokenType.STAR) || identical(operator2, sc.TokenType.TILDE_SLASH)) {
+ Type2 intType2 = _typeProvider.intType;
+ if (identical(getStaticType(node.leftOperand), intType2) && identical(getStaticType(node.rightOperand), intType2)) {
+ staticType = intType2;
+ }
+ }
+ return staticType;
+ }
+
+ /**
* Set the return type and parameter type information for the given function type based on the
* given return type and parameter elements.
* @param functionType the function type to be filled in
@@ -5653,26 +7240,61 @@
get thisType_J2DAccessor => _thisType;
set thisType_J2DAccessor(__v) => _thisType = __v;
}
+
/**
* Instances of the class {@code TypeOverrideManager} manage the ability to override the type of an
* element within a given context.
*/
class TypeOverrideManager {
+
/**
* The current override scope, or {@code null} if no scope has been entered.
*/
TypeOverrideManager_TypeOverrideScope _currentScope;
+
/**
- * Initialize a newly created override manager to not be in any scope.
+ * Apply a set of overrides that were previously captured.
+ * @param overrides the overrides to be applied
*/
- TypeOverrideManager() : super() {
+ void applyOverrides(Map<Element, Type2> overrides) {
+ if (_currentScope == null) {
+ throw new IllegalStateException("Cannot apply overrides without a scope");
+ }
+ _currentScope.applyOverrides(overrides);
}
+
/**
+ * Return a table mapping the elements whose type is overridden in the current scope to the
+ * overriding type.
+ * @return the overrides in the current scope
+ */
+ Map<Element, Type2> captureLocalOverrides() {
+ if (_currentScope == null) {
+ throw new IllegalStateException("Cannot capture local overrides without a scope");
+ }
+ return _currentScope.captureLocalOverrides();
+ }
+
+ /**
+ * Return a map from the elements for the variables in the given list that have their types
+ * overridden to the overriding type.
+ * @param variableList the list of variables whose overriding types are to be captured
+ * @return a table mapping elements to their overriding types
+ */
+ Map<Element, Type2> captureOverrides(VariableDeclarationList variableList) {
+ if (_currentScope == null) {
+ throw new IllegalStateException("Cannot capture overrides without a scope");
+ }
+ return _currentScope.captureOverrides(variableList);
+ }
+
+ /**
* Enter a new override scope.
*/
void enterScope() {
_currentScope = new TypeOverrideManager_TypeOverrideScope(_currentScope);
}
+
/**
* Exit the current override scope.
*/
@@ -5682,6 +7304,7 @@
}
_currentScope = _currentScope._outerScope;
}
+
/**
* Return the overridden type of the given element, or {@code null} if the type of the element has
* not been overridden.
@@ -5694,6 +7317,7 @@
}
return _currentScope.getType(element);
}
+
/**
* Set the overridden type of the given element to the given type
* @param element the element whose type might have been overridden
@@ -5706,19 +7330,23 @@
_currentScope.setType(element, type);
}
}
+
/**
* Instances of the class {@code TypeOverrideScope} represent a scope in which the types of
* elements can be overridden.
*/
class TypeOverrideManager_TypeOverrideScope {
+
/**
* The outer scope in which types might be overridden.
*/
TypeOverrideManager_TypeOverrideScope _outerScope;
+
/**
* A table mapping elements to the overridden type of that element.
*/
Map<Element, Type2> _overridenTypes = new Map<Element, Type2>();
+
/**
* Initialize a newly created scope to be an empty child of the given scope.
* @param outerScope the outer scope in which types might be overridden
@@ -5726,7 +7354,47 @@
TypeOverrideManager_TypeOverrideScope(TypeOverrideManager_TypeOverrideScope outerScope) {
this._outerScope = outerScope;
}
+
/**
+ * Apply a set of overrides that were previously captured.
+ * @param overrides the overrides to be applied
+ */
+ void applyOverrides(Map<Element, Type2> overrides) {
+ for (MapEntry<Element, Type2> entry in getMapEntrySet(overrides)) {
+ _overridenTypes[entry.getKey()] = entry.getValue();
+ }
+ }
+
+ /**
+ * Return a table mapping the elements whose type is overridden in the current scope to the
+ * overriding type.
+ * @return the overrides in the current scope
+ */
+ Map<Element, Type2> captureLocalOverrides() => _overridenTypes;
+
+ /**
+ * Return a map from the elements for the variables in the given list that have their types
+ * overridden to the overriding type.
+ * @param variableList the list of variables whose overriding types are to be captured
+ * @return a table mapping elements to their overriding types
+ */
+ Map<Element, Type2> captureOverrides(VariableDeclarationList variableList) {
+ Map<Element, Type2> overrides = new Map<Element, Type2>();
+ if (variableList.isConst() || variableList.isFinal()) {
+ for (VariableDeclaration variable in variableList.variables) {
+ Element element2 = variable.element;
+ if (element2 != null) {
+ Type2 type = _overridenTypes[element2];
+ if (type != null) {
+ overrides[element2] = type;
+ }
+ }
+ }
+ }
+ return overrides;
+ }
+
+ /**
* Return the overridden type of the given element, or {@code null} if the type of the element
* has not been overridden.
* @param element the element whose type might have been overridden
@@ -5744,6 +7412,7 @@
}
return null;
}
+
/**
* Set the overridden type of the given element to the given type
* @param element the element whose type might have been overridden
@@ -5753,136 +7422,165 @@
_overridenTypes[element] = type;
}
}
+
/**
* The interface {@code TypeProvider} defines the behavior of objects that provide access to types
* defined by the language.
* @coverage dart.engine.resolver
*/
abstract class TypeProvider {
+
/**
* Return the type representing the built-in type 'bool'.
* @return the type representing the built-in type 'bool'
*/
InterfaceType get boolType;
+
/**
* Return the type representing the type 'bottom'.
* @return the type representing the type 'bottom'
*/
Type2 get bottomType;
+
/**
* Return the type representing the built-in type 'double'.
* @return the type representing the built-in type 'double'
*/
InterfaceType get doubleType;
+
/**
* Return the type representing the built-in type 'dynamic'.
* @return the type representing the built-in type 'dynamic'
*/
Type2 get dynamicType;
+
/**
* Return the type representing the built-in type 'Function'.
* @return the type representing the built-in type 'Function'
*/
InterfaceType get functionType;
+
/**
* Return the type representing the built-in type 'int'.
* @return the type representing the built-in type 'int'
*/
InterfaceType get intType;
+
/**
* Return the type representing the built-in type 'List'.
* @return the type representing the built-in type 'List'
*/
InterfaceType get listType;
+
/**
* Return the type representing the built-in type 'Map'.
* @return the type representing the built-in type 'Map'
*/
InterfaceType get mapType;
+
/**
* Return the type representing the built-in type 'num'.
* @return the type representing the built-in type 'num'
*/
InterfaceType get numType;
+
/**
* Return the type representing the built-in type 'Object'.
* @return the type representing the built-in type 'Object'
*/
InterfaceType get objectType;
+
/**
* Return the type representing the built-in type 'StackTrace'.
* @return the type representing the built-in type 'StackTrace'
*/
InterfaceType get stackTraceType;
+
/**
* Return the type representing the built-in type 'String'.
* @return the type representing the built-in type 'String'
*/
InterfaceType get stringType;
+
/**
* Return the type representing the built-in type 'Type'.
* @return the type representing the built-in type 'Type'
*/
InterfaceType get typeType;
}
+
/**
* Instances of the class {@code TypeProviderImpl} provide access to types defined by the language
* by looking for those types in the element model for the core library.
* @coverage dart.engine.resolver
*/
class TypeProviderImpl implements TypeProvider {
+
/**
* The type representing the built-in type 'bool'.
*/
InterfaceType _boolType;
+
/**
* The type representing the type 'bottom'.
*/
Type2 _bottomType;
+
/**
* The type representing the built-in type 'double'.
*/
InterfaceType _doubleType;
+
/**
* The type representing the built-in type 'dynamic'.
*/
Type2 _dynamicType;
+
/**
* The type representing the built-in type 'Function'.
*/
InterfaceType _functionType;
+
/**
* The type representing the built-in type 'int'.
*/
InterfaceType _intType;
+
/**
* The type representing the built-in type 'List'.
*/
InterfaceType _listType;
+
/**
* The type representing the built-in type 'Map'.
*/
InterfaceType _mapType;
+
/**
* The type representing the built-in type 'num'.
*/
InterfaceType _numType;
+
/**
* The type representing the built-in type 'Object'.
*/
InterfaceType _objectType;
+
/**
* The type representing the built-in type 'StackTrace'.
*/
InterfaceType _stackTraceType;
+
/**
* The type representing the built-in type 'String'.
*/
InterfaceType _stringType;
+
/**
* The type representing the built-in type 'Type'.
*/
InterfaceType _typeType;
+
/**
* Initialize a newly created type provider to provide the types defined in the given library.
* @param coreLibrary the element representing the core library (dart:core).
@@ -5903,6 +7601,7 @@
InterfaceType get stackTraceType => _stackTraceType;
InterfaceType get stringType => _stringType;
InterfaceType get typeType => _typeType;
+
/**
* Return the type with the given name from the given namespace, or {@code null} if there is no
* class with the given name.
@@ -5918,6 +7617,7 @@
}
return ((element as ClassElement)).type;
}
+
/**
* Initialize the types provided by this type provider from the given library.
* @param library the library containing the definitions of the core types
@@ -5939,6 +7639,7 @@
_typeType = getType(namespace, "Type");
}
}
+
/**
* Instances of the class {@code TypeResolverVisitor} are used to resolve the types associated with
* the elements in the element model. This includes the types of superclasses, mixins, interfaces,
@@ -5947,22 +7648,30 @@
* @coverage dart.engine.resolver
*/
class TypeResolverVisitor extends ScopedVisitor {
+
/**
* The type representing the type 'dynamic'.
*/
Type2 _dynamicType;
+
/**
+ * The flag specifying if currently visited class references 'super' expression.
+ */
+ bool _hasReferenceToSuper = false;
+
+ /**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param library the library containing the compilation unit being resolved
* @param source the source representing the compilation unit being visited
* @param typeProvider the object used to access the types from the core library
*/
TypeResolverVisitor.con1(Library library, Source source, TypeProvider typeProvider) : super.con1(library, source, typeProvider) {
- _jtd_constructor_274_impl(library, source, typeProvider);
+ _jtd_constructor_280_impl(library, source, typeProvider);
}
- _jtd_constructor_274_impl(Library library, Source source, TypeProvider typeProvider) {
+ _jtd_constructor_280_impl(Library library, Source source, TypeProvider typeProvider) {
_dynamicType = typeProvider.dynamicType;
}
+
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
* @param definingLibrary the element for the library containing the compilation unit being
@@ -5973,9 +7682,9 @@
* during resolution
*/
TypeResolverVisitor.con2(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, AnalysisErrorListener errorListener) : super.con2(definingLibrary, source, typeProvider, errorListener) {
- _jtd_constructor_275_impl(definingLibrary, source, typeProvider, errorListener);
+ _jtd_constructor_281_impl(definingLibrary, source, typeProvider, errorListener);
}
- _jtd_constructor_275_impl(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, AnalysisErrorListener errorListener) {
+ _jtd_constructor_281_impl(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, AnalysisErrorListener errorListener) {
_dynamicType = typeProvider.dynamicType;
}
Object visitCatchClause(CatchClause node) {
@@ -5987,7 +7696,7 @@
if (exceptionTypeName == null) {
exceptionType = typeProvider.objectType;
} else {
- exceptionType = getType5(exceptionTypeName);
+ exceptionType = getType3(exceptionTypeName);
}
recordType(exception, exceptionType);
Element element2 = exception.element;
@@ -6003,12 +7712,14 @@
return null;
}
Object visitClassDeclaration(ClassDeclaration node) {
+ _hasReferenceToSuper = false;
super.visitClassDeclaration(node);
ClassElementImpl classElement = getClassElement(node.name);
InterfaceType superclassType = null;
ExtendsClause extendsClause2 = node.extendsClause;
if (extendsClause2 != null) {
- superclassType = resolveType(extendsClause2.superclass, CompileTimeErrorCode.EXTENDS_NON_CLASS);
+ ErrorCode errorCode = node.withClause == null ? CompileTimeErrorCode.EXTENDS_NON_CLASS : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
+ superclassType = resolveType(extendsClause2.superclass, errorCode);
if (superclassType != typeProvider.objectType) {
classElement.validMixin = false;
}
@@ -6021,6 +7732,7 @@
}
}
classElement.supertype = superclassType;
+ classElement.hasReferenceToSuper2 = _hasReferenceToSuper;
}
resolve(classElement, node.withClause, node.implementsClause);
return null;
@@ -6028,7 +7740,7 @@
Object visitClassTypeAlias(ClassTypeAlias node) {
super.visitClassTypeAlias(node);
ClassElementImpl classElement = getClassElement(node.name);
- InterfaceType superclassType = resolveType(node.superclass, CompileTimeErrorCode.EXTENDS_NON_CLASS);
+ InterfaceType superclassType = resolveType(node.superclass, CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
if (superclassType == null) {
superclassType = typeProvider.objectType;
}
@@ -6054,7 +7766,7 @@
if (typeName == null) {
declaredType = _dynamicType;
} else {
- declaredType = getType5(typeName);
+ declaredType = getType3(typeName);
}
LocalVariableElementImpl element2 = node.element as LocalVariableElementImpl;
element2.type = declaredType;
@@ -6074,7 +7786,7 @@
if (typeName == null) {
type = _dynamicType;
} else {
- type = getType5(typeName);
+ type = getType3(typeName);
}
parameter.type = type;
} else {
@@ -6099,8 +7811,10 @@
Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
super.visitFunctionTypedFormalParameter(node);
ParameterElementImpl element2 = node.identifier.element as ParameterElementImpl;
- FunctionTypeImpl type = new FunctionTypeImpl.con1((null as ExecutableElement));
- setTypeInformation(type, node.returnType, getElements(node.parameters));
+ AnonymousFunctionTypeImpl type = new AnonymousFunctionTypeImpl();
+ List<ParameterElement> parameters2 = getElements(node.parameters);
+ setTypeInformation(type, node.returnType, parameters2);
+ type.baseParameters = parameters2;
element2.type = type;
return null;
}
@@ -6131,7 +7845,7 @@
if (typeName == null) {
declaredType = _dynamicType;
} else {
- declaredType = getType5(typeName);
+ declaredType = getType3(typeName);
}
Element element2 = node.identifier.element;
if (element2 is ParameterElement) {
@@ -6140,6 +7854,10 @@
}
return null;
}
+ Object visitSuperExpression(SuperExpression node) {
+ _hasReferenceToSuper = true;
+ return super.visitSuperExpression(node);
+ }
Object visitTypeName(TypeName node) {
super.visitTypeName(node);
Identifier typeName = node.name;
@@ -6179,18 +7897,36 @@
}
}
}
- if (element == null) {
- Identifier simpleIdentifier;
- if (typeName is SimpleIdentifier) {
- simpleIdentifier = typeName;
+ bool elementValid = element is! MultiplyDefinedElement;
+ if (elementValid && element is! ClassElement && isTypeNameInInstanceCreationExpression(node)) {
+ SimpleIdentifier typeNameSimple = getTypeSimpleIdentifier(typeName);
+ InstanceCreationExpression creation = node.parent.parent as InstanceCreationExpression;
+ if (creation.isConst()) {
+ if (element == null) {
+ reportError(CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
+ } else {
+ reportError(CompileTimeErrorCode.CONST_WITH_NON_TYPE, typeNameSimple, [typeName]);
+ }
+ elementValid = false;
} else {
- simpleIdentifier = ((typeName as PrefixedIdentifier)).prefix;
+ if (element != null) {
+ reportError(StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
+ elementValid = false;
+ }
}
- if (simpleIdentifier.name == "boolean") {
- reportError(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, simpleIdentifier, []);
+ }
+ if (elementValid && element == null) {
+ SimpleIdentifier typeNameSimple = getTypeSimpleIdentifier(typeName);
+ if (typeNameSimple.name == "boolean") {
+ reportError(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
+ } else if (isTypeNameInCatchClause(node)) {
+ reportError(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, node, [node]);
} else {
- reportError(StaticWarningCode.UNDEFINED_CLASS, simpleIdentifier, [simpleIdentifier.name]);
+ reportError(StaticWarningCode.UNDEFINED_CLASS, typeNameSimple, [typeNameSimple.name]);
}
+ elementValid = false;
+ }
+ if (!elementValid) {
setElement(typeName, _dynamicType.element);
typeName.staticType = _dynamicType;
node.type = _dynamicType;
@@ -6215,6 +7951,9 @@
node.type = type;
}
} else {
+ if (isTypeNameInCatchClause(node)) {
+ reportError(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, node, [node]);
+ }
setElement(typeName, _dynamicType.element);
typeName.staticType = _dynamicType;
node.type = _dynamicType;
@@ -6228,7 +7967,7 @@
int count = Math.min(argumentCount, parameterCount);
List<Type2> typeArguments = new List<Type2>();
for (int i = 0; i < count; i++) {
- Type2 argumentType = getType5(arguments2[i]);
+ Type2 argumentType = getType3(arguments2[i]);
if (argumentType != null) {
typeArguments.add(argumentType);
}
@@ -6273,7 +8012,7 @@
if (typeName == null) {
declaredType = _dynamicType;
} else {
- declaredType = getType5(typeName);
+ declaredType = getType3(typeName);
}
Element element2 = node.name.element;
if (element2 is VariableElement) {
@@ -6296,6 +8035,7 @@
}
return null;
}
+
/**
* Return the class element that represents the class whose name was provided.
* @param identifier the name from the declaration of a class
@@ -6311,6 +8051,7 @@
}
return element2 as ClassElementImpl;
}
+
/**
* Return an array containing all of the elements associated with the parameters in the given
* list.
@@ -6327,6 +8068,7 @@
}
return new List.from(elements);
}
+
/**
* The number of type arguments in the given type name does not match the number of parameters in
* the corresponding class element. Return the error code that should be used to report this
@@ -6349,6 +8091,7 @@
}
return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
}
+
/**
* Given the multiple elements to which a single name could potentially be resolved, return the
* single interface type that should be used, or {@code null} if there is no clear choice.
@@ -6367,18 +8110,20 @@
}
return type;
}
+
/**
* Return the type represented by the given type name.
* @param typeName the type name representing the type to be returned
* @return the type represented by the type name
*/
- Type2 getType5(TypeName typeName) {
+ Type2 getType3(TypeName typeName) {
Type2 type2 = typeName.type;
if (type2 == null) {
return _dynamicType;
}
return type2;
}
+
/**
* Return the type arguments associated with the given type.
* @param type the type whole type arguments are to be returned
@@ -6392,7 +8137,50 @@
}
return TypeImpl.EMPTY_ARRAY;
}
+
/**
+ * Returns the simple identifier of the given (may be qualified) type name.
+ * @param typeName the (may be qualified) qualified type name
+ * @return the simple identifier of the given (may be qualified) type name.
+ */
+ SimpleIdentifier getTypeSimpleIdentifier(Identifier typeName) {
+ if (typeName is SimpleIdentifier) {
+ return typeName as SimpleIdentifier;
+ } else {
+ return ((typeName as PrefixedIdentifier)).identifier;
+ }
+ }
+
+ /**
+ * Checks if the given type name is used as the exception type in the catch clause.
+ * @param typeName the type name to analyzer
+ * @return {@code true} if the given type name is used as the exception type in the catch clause.
+ */
+ bool isTypeNameInCatchClause(TypeName typeName) {
+ ASTNode parent2 = typeName.parent;
+ if (parent2 is CatchClause) {
+ CatchClause catchClause = parent2 as CatchClause;
+ return identical(catchClause.exceptionType, typeName);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the given type name is used as the type in the instance creation expression.
+ * @param typeName the type name to analyzer
+ * @return {@code true} if the given type name is used as the type in the instance creation
+ * expression
+ */
+ bool isTypeNameInInstanceCreationExpression(TypeName typeName) {
+ ASTNode parent2 = typeName.parent;
+ if (parent2 is ConstructorName && parent2.parent is InstanceCreationExpression) {
+ ConstructorName constructorName = parent2 as ConstructorName;
+ return constructorName != null && identical(constructorName.type, typeName);
+ }
+ return false;
+ }
+
+ /**
* Record that the static type of the given node is the given type.
* @param expression the node whose type is to be recorded
* @param type the static type of the node
@@ -6405,6 +8193,7 @@
}
return null;
}
+
/**
* Resolve the types in the given with and implements clauses and associate those types with the
* given class element.
@@ -6434,20 +8223,15 @@
String name3 = typeName.name.name;
if (name3 == dynamicKeyword) {
reportError(CompileTimeErrorCode.IMPLEMENTS_DYNAMIC, typeName, []);
- } else {
- Element element3 = typeName.name.element;
- if (element3 != null && element3 == classElement) {
- reportError(CompileTimeErrorCode.IMPLEMENTS_SELF, typeName, [name3]);
- }
}
if (!detectedRepeatOnIndex[i]) {
for (int j = i + 1; j < typeNames.length; j++) {
- Element element4 = typeName.name.element;
+ Element element3 = typeName.name.element;
TypeName typeName2 = typeNames[j];
Identifier identifier2 = typeName2.name;
String name2 = identifier2.name;
Element element2 = identifier2.element;
- if (element4 != null && element4 == element2) {
+ if (element3 != null && element3 == element2) {
detectedRepeatOnIndex[j] = true;
reportError(CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
}
@@ -6459,6 +8243,7 @@
}
}
}
+
/**
* Return the type specified by the given name.
* @param typeName the type name specifying the type to be returned
@@ -6477,6 +8262,7 @@
}
return null;
}
+
/**
* Resolve the types in the given list of type names.
* @param typeNames the type names to be resolved
@@ -6509,6 +8295,7 @@
}
}
}
+
/**
* Set the return type and parameter type information for the given function type based on the
* given return type and parameter elements.
@@ -6548,11 +8335,13 @@
}
}
}
+
/**
* Instances of the class {@code ClassScope} implement the scope defined by a class.
* @coverage dart.engine.resolver
*/
class ClassScope extends EnclosedScope {
+
/**
* Initialize a newly created scope enclosed within another scope.
* @param enclosingScope the scope in which this scope is lexically enclosed
@@ -6562,6 +8351,17 @@
defineTypeParameters(typeElement);
defineMembers(typeElement);
}
+ AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
+ if (existing is PropertyAccessorElement && duplicate is MethodElement) {
+ if (existing.nameOffset < duplicate.nameOffset) {
+ return new AnalysisError.con2(duplicate.source, duplicate.nameOffset, duplicate.displayName.length, CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME, [existing.displayName]);
+ } else {
+ return new AnalysisError.con2(existing.source, existing.nameOffset, existing.displayName.length, CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME, [existing.displayName]);
+ }
+ }
+ return super.getErrorForDuplicate(existing, duplicate);
+ }
+
/**
* Define the instance members defined by the class.
* @param typeElement the element representing the type represented by this scope
@@ -6574,6 +8374,7 @@
define(method);
}
}
+
/**
* Define the type parameters for the class.
* @param typeElement the element representing the type represented by this scope
@@ -6585,16 +8386,19 @@
}
}
}
+
/**
* Instances of the class {@code EnclosedScope} implement a scope that is lexically enclosed in
* another scope.
* @coverage dart.engine.resolver
*/
class EnclosedScope extends Scope {
+
/**
* The scope in which this scope is lexically enclosed.
*/
Scope _enclosingScope;
+
/**
* Initialize a newly created scope enclosed within another scope.
* @param enclosingScope the scope in which this scope is lexically enclosed
@@ -6604,24 +8408,27 @@
}
LibraryElement get definingLibrary => _enclosingScope.definingLibrary;
AnalysisErrorListener get errorListener => _enclosingScope.errorListener;
+
/**
* Return the scope in which this scope is lexically enclosed.
* @return the scope in which this scope is lexically enclosed
*/
Scope get enclosingScope => _enclosingScope;
- Element lookup3(String name, LibraryElement referencingLibrary) {
+ Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary) {
Element element = localLookup(name, referencingLibrary);
if (element != null) {
return element;
}
- return _enclosingScope.lookup3(name, referencingLibrary);
+ return _enclosingScope.lookup3(identifier, name, referencingLibrary);
}
}
+
/**
* Instances of the class {@code FunctionScope} implement the scope defined by a function.
* @coverage dart.engine.resolver
*/
class FunctionScope extends EnclosedScope {
+
/**
* Initialize a newly created scope enclosed within another scope.
* @param enclosingScope the scope in which this scope is lexically enclosed
@@ -6630,6 +8437,7 @@
FunctionScope(Scope enclosingScope, ExecutableElement functionElement) : super(new EnclosedScope(enclosingScope)) {
defineParameters(functionElement);
}
+
/**
* Define the parameters for the given function in the scope that encloses this function.
* @param functionElement the element representing the function represented by this scope
@@ -6649,12 +8457,14 @@
}
}
}
+
/**
* Instances of the class {@code FunctionTypeScope} implement the scope defined by a function type
* alias.
* @coverage dart.engine.resolver
*/
class FunctionTypeScope extends EnclosedScope {
+
/**
* Initialize a newly created scope enclosed within another scope.
* @param enclosingScope the scope in which this scope is lexically enclosed
@@ -6664,6 +8474,7 @@
defineTypeVariables(typeElement);
defineParameters(typeElement);
}
+
/**
* Define the parameters for the function type alias.
* @param typeElement the element representing the type represented by this scope
@@ -6673,6 +8484,7 @@
define(parameter);
}
}
+
/**
* Define the type variables for the function type alias.
* @param typeElement the element representing the type represented by this scope
@@ -6684,31 +8496,38 @@
}
}
}
+
/**
* Instances of the class {@code LabelScope} represent a scope in which a single label is defined.
* @coverage dart.engine.resolver
*/
class LabelScope {
+
/**
* The label scope enclosing this label scope.
*/
LabelScope _outerScope;
+
/**
* The label defined in this scope.
*/
String _label;
+
/**
* The element to which the label resolves.
*/
LabelElement _element;
+
/**
* The marker used to look up a label element for an unlabeled {@code break} or {@code continue}.
*/
static String EMPTY_LABEL = "";
+
/**
* The label element returned for scopes that can be the target of an unlabeled {@code break} or{@code continue}.
*/
static SimpleIdentifier _EMPTY_LABEL_IDENTIFIER = new SimpleIdentifier.full(new sc.StringToken(sc.TokenType.IDENTIFIER, "", 0));
+
/**
* Initialize a newly created scope to represent the potential target of an unlabeled{@code break} or {@code continue}.
* @param outerScope the label scope enclosing the new label scope
@@ -6716,11 +8535,12 @@
* @param onSwitchMember {@code true} if this label is associated with a {@code switch} member
*/
LabelScope.con1(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMember) {
- _jtd_constructor_280_impl(outerScope, onSwitchStatement, onSwitchMember);
+ _jtd_constructor_286_impl(outerScope, onSwitchStatement, onSwitchMember);
}
- _jtd_constructor_280_impl(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMember) {
- _jtd_constructor_281_impl(outerScope, EMPTY_LABEL, new LabelElementImpl(_EMPTY_LABEL_IDENTIFIER, onSwitchStatement, onSwitchMember));
+ _jtd_constructor_286_impl(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMember) {
+ _jtd_constructor_287_impl(outerScope, EMPTY_LABEL, new LabelElementImpl(_EMPTY_LABEL_IDENTIFIER, onSwitchStatement, onSwitchMember));
}
+
/**
* Initialize a newly created scope to represent the given label.
* @param outerScope the label scope enclosing the new label scope
@@ -6728,13 +8548,14 @@
* @param element the element to which the label resolves
*/
LabelScope.con2(LabelScope outerScope2, String label2, LabelElement element2) {
- _jtd_constructor_281_impl(outerScope2, label2, element2);
+ _jtd_constructor_287_impl(outerScope2, label2, element2);
}
- _jtd_constructor_281_impl(LabelScope outerScope2, String label2, LabelElement element2) {
+ _jtd_constructor_287_impl(LabelScope outerScope2, String label2, LabelElement element2) {
this._outerScope = outerScope2;
this._label = label2;
this._element = element2;
}
+
/**
* Return the label element corresponding to the given label, or {@code null} if the given label
* is not defined in this scope.
@@ -6742,6 +8563,7 @@
* @return the label element corresponding to the given label
*/
LabelElement lookup(SimpleIdentifier targetLabel) => lookup2(targetLabel.name);
+
/**
* Return the label element corresponding to the given label, or {@code null} if the given label
* is not defined in this scope.
@@ -6758,25 +8580,75 @@
}
}
}
+
/**
* Instances of the class {@code LibraryImportScope} represent the scope containing all of the names
* available from imported libraries.
* @coverage dart.engine.resolver
*/
class LibraryImportScope extends Scope {
+
/**
+ * @return {@code true} if the given {@link Identifier} is the part of type annotation.
+ */
+ static bool isTypeAnnotation(Identifier identifier) {
+ ASTNode parent4 = identifier.parent;
+ if (parent4 is TypeName) {
+ ASTNode parent2 = parent4.parent;
+ if (parent2 is FunctionDeclaration) {
+ FunctionDeclaration decl = parent2 as FunctionDeclaration;
+ return identical(decl.returnType, parent4);
+ }
+ if (parent2 is FunctionTypeAlias) {
+ FunctionTypeAlias decl = parent2 as FunctionTypeAlias;
+ return identical(decl.returnType, parent4);
+ }
+ if (parent2 is MethodDeclaration) {
+ MethodDeclaration decl = parent2 as MethodDeclaration;
+ return identical(decl.returnType, parent4);
+ }
+ if (parent2 is VariableDeclarationList) {
+ VariableDeclarationList decl = parent2 as VariableDeclarationList;
+ return identical(decl.type, parent4);
+ }
+ if (parent2 is SimpleFormalParameter) {
+ SimpleFormalParameter decl = parent2 as SimpleFormalParameter;
+ return identical(decl.type, parent4);
+ }
+ if (parent2 is TypeParameter) {
+ TypeParameter decl = parent2 as TypeParameter;
+ return identical(decl.bound, parent4);
+ }
+ if (parent2 is TypeArgumentList) {
+ ASTNode parent3 = parent2.parent;
+ if (parent3 is TypeName) {
+ TypeName typeName = parent3 as TypeName;
+ if (identical((typeName).typeArguments, parent2)) {
+ return isTypeAnnotation(typeName.name);
+ }
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+
+ /**
* The element representing the library in which this scope is enclosed.
*/
LibraryElement _definingLibrary;
+
/**
* The listener that is to be informed when an error is encountered.
*/
AnalysisErrorListener _errorListener;
+
/**
* A list of the namespaces representing the names that are available in this scope from imported
* libraries.
*/
List<Namespace> _importedNamespaces = new List<Namespace>();
+
/**
* Initialize a newly created scope representing the names imported into the given library.
* @param definingLibrary the element representing the library that imports the names defined in
@@ -6789,13 +8661,13 @@
createImportedNamespaces(definingLibrary);
}
void define(Element element) {
- if (!Scope.isPrivateName(element.name)) {
+ if (!Scope.isPrivateName(element.displayName)) {
super.define(element);
}
}
LibraryElement get definingLibrary => _definingLibrary;
AnalysisErrorListener get errorListener => _errorListener;
- Element lookup3(String name, LibraryElement referencingLibrary) {
+ Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary) {
Element foundElement = localLookup(name, referencingLibrary);
if (foundElement != null) {
return foundElement;
@@ -6811,12 +8683,27 @@
}
}
if (foundElement is MultiplyDefinedElementImpl) {
+ String foundEltName = foundElement.displayName;
+ String libName1 = "", libName2 = "";
+ List<Element> conflictingMembers = ((foundElement as MultiplyDefinedElementImpl)).conflictingElements;
+ LibraryElement enclosingLibrary = conflictingMembers[0].getAncestor(LibraryElement);
+ if (enclosingLibrary != null) {
+ libName1 = enclosingLibrary.definingCompilationUnit.displayName;
+ }
+ enclosingLibrary = conflictingMembers[1].getAncestor(LibraryElement);
+ if (enclosingLibrary != null) {
+ libName2 = enclosingLibrary.definingCompilationUnit.displayName;
+ }
+ ErrorCode errorCode = isTypeAnnotation(identifier) ? StaticWarningCode.AMBIGUOUS_IMPORT : CompileTimeErrorCode.AMBIGUOUS_IMPORT;
+ _errorListener.onError(new AnalysisError.con2(source, identifier.offset, identifier.length, errorCode, [foundEltName, libName1, libName2]));
+ return foundElement;
}
if (foundElement != null) {
- defineWithoutChecking(foundElement);
+ defineWithoutChecking2(name, foundElement);
}
return foundElement;
}
+
/**
* Create all of the namespaces associated with the libraries imported into this library. The
* names are not added to this scope, but are stored for later reference.
@@ -6830,12 +8717,14 @@
}
}
}
+
/**
* Instances of the class {@code LibraryScope} implement a scope containing all of the names defined
* in a given library.
* @coverage dart.engine.resolver
*/
class LibraryScope extends EnclosedScope {
+
/**
* Initialize a newly created scope representing the names defined in the given library.
* @param definingLibrary the element representing the library represented by this scope
@@ -6844,6 +8733,20 @@
LibraryScope(LibraryElement definingLibrary, AnalysisErrorListener errorListener) : super(new LibraryImportScope(definingLibrary, errorListener)) {
defineTopLevelNames(definingLibrary);
}
+ AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
+ if (existing is PrefixElement) {
+ int offset = duplicate.nameOffset;
+ if (duplicate is PropertyAccessorElement) {
+ PropertyAccessorElement accessor = duplicate as PropertyAccessorElement;
+ if (accessor.isSynthetic()) {
+ offset = accessor.variable.nameOffset;
+ }
+ }
+ return new AnalysisError.con2(source, offset, duplicate.displayName.length, CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, [existing.displayName]);
+ }
+ return super.getErrorForDuplicate(existing, duplicate);
+ }
+
/**
* Add to this scope all of the public top-level names that are defined in the given compilation
* unit.
@@ -6864,6 +8767,7 @@
define(element);
}
}
+
/**
* Add to this scope all of the names that are explicitly defined in the given library.
* @param definingLibrary the element representing the library that defines the names in this
@@ -6879,21 +8783,25 @@
}
}
}
+
/**
* Instances of the class {@code Namespace} implement a mapping of identifiers to the elements
* represented by those identifiers. Namespaces are the building blocks for scopes.
* @coverage dart.engine.resolver
*/
class Namespace {
+
/**
* A table mapping names that are defined in this namespace to the element representing the thing
* declared with that name.
*/
Map<String, Element> _definedNames;
+
/**
* An empty namespace.
*/
static Namespace EMPTY = new Namespace(new Map<String, Element>());
+
/**
* Initialize a newly created namespace to have the given defined names.
* @param definedNames the mapping from names that are defined in this namespace to the
@@ -6902,6 +8810,7 @@
Namespace(Map<String, Element> definedNames) {
this._definedNames = definedNames;
}
+
/**
* Return the element in this namespace that is available to the containing scope using the given
* name.
@@ -6909,29 +8818,43 @@
* @return the element represented by the given identifier
*/
Element get(String name) => _definedNames[name];
+
/**
* Return a table containing the same mappings as those defined by this namespace.
* @return a table containing the same mappings as those defined by this namespace
*/
Map<String, Element> get definedNames => new Map<String, Element>.from(_definedNames);
}
+
/**
* Instances of the class {@code NamespaceBuilder} are used to build a {@code Namespace}. Namespace
* builders are thread-safe and re-usable.
* @coverage dart.engine.resolver
*/
class NamespaceBuilder {
+
/**
- * Initialize a newly created namespace builder.
+ * Create a namespace representing the export namespace of the given {@link ExportElement}.
+ * @param element the export element whose export namespace is to be created
+ * @return the export namespace that was created
*/
- NamespaceBuilder() : super() {
+ Namespace createExportNamespace(ExportElement element) {
+ LibraryElement exportedLibrary2 = element.exportedLibrary;
+ if (exportedLibrary2 == null) {
+ return Namespace.EMPTY;
+ }
+ Map<String, Element> definedNames = createExportMapping(exportedLibrary2, new Set<LibraryElement>());
+ definedNames = apply(definedNames, element.combinators);
+ return new Namespace(definedNames);
}
+
/**
* Create a namespace representing the export namespace of the given library.
* @param library the library whose export namespace is to be created
* @return the export namespace that was created
*/
- Namespace createExportNamespace(LibraryElement library) => new Namespace(createExportMapping(library, new Set<LibraryElement>()));
+ Namespace createExportNamespace2(LibraryElement library) => new Namespace(createExportMapping(library, new Set<LibraryElement>()));
+
/**
* Create a namespace representing the import namespace of the given library.
* @param library the library whose import namespace is to be created
@@ -6947,6 +8870,7 @@
definedNames = apply2(definedNames, element.prefix);
return new Namespace(definedNames);
}
+
/**
* Create a namespace representing the public namespace of the given library.
* @param library the library whose public namespace is to be created
@@ -6960,6 +8884,7 @@
}
return new Namespace(definedNames);
}
+
/**
* Add all of the names in the given namespace to the given mapping table.
* @param definedNames the mapping table to which the names in the given namespace are to be added
@@ -6970,6 +8895,7 @@
definedNames[entry.getKey()] = entry.getValue();
}
}
+
/**
* Add all of the names in the given namespace to the given mapping table.
* @param definedNames the mapping table to which the names in the given namespace are to be added
@@ -6980,6 +8906,7 @@
addAll(definedNames2, namespace.definedNames);
}
}
+
/**
* Add the given element to the given mapping table if it has a publicly visible name.
* @param definedNames the mapping table to which the public name is to be added
@@ -6991,6 +8918,7 @@
definedNames[name2] = element;
}
}
+
/**
* Add to the given mapping table all of the public top-level names that are defined in the given
* compilation unit.
@@ -7011,10 +8939,8 @@
for (ClassElement element in compilationUnit.types) {
addIfPublic(definedNames, element);
}
- for (VariableElement element in compilationUnit.topLevelVariables) {
- addIfPublic(definedNames, element);
- }
}
+
/**
* Apply the given combinators to all of the names in the given mapping table.
* @param definedNames the mapping table to which the namespace operations are to be applied
@@ -7032,6 +8958,7 @@
}
return definedNames;
}
+
/**
* Apply the given prefix to all of the names in the table of defined names.
* @param definedNames the names that were defined before this operation
@@ -7049,6 +8976,7 @@
return definedNames;
}
}
+
/**
* Create a mapping table representing the export namespace of the given library.
* @param library the library whose public namespace is to be created
@@ -7075,6 +9003,7 @@
visitedElements.remove(library);
}
}
+
/**
* Hide all of the given names by removing them from the given collection of defined names.
* @param definedNames the names that were defined before this operation
@@ -7085,6 +9014,7 @@
definedNames.remove(name);
}
}
+
/**
* Show only the given names by removing all other names from the given collection of defined
* names.
@@ -7102,43 +9032,45 @@
return newNames;
}
}
+
/**
* The abstract class {@code Scope} defines the behavior common to name scopes used by the resolver
* to determine which names are visible at any given point in the code.
* @coverage dart.engine.resolver
*/
abstract class Scope {
+
/**
* The prefix used to mark an identifier as being private to its library.
*/
static String PRIVATE_NAME_PREFIX = "_";
+
/**
* The suffix added to the declared name of a setter when looking up the setter. Used to
* disambiguate between a getter and a setter that have the same name.
*/
static String SETTER_SUFFIX = "=";
+
/**
* The name used to look up the method used to implement the unary minus operator. Used to
* disambiguate between the unary and binary operators.
*/
static String UNARY_MINUS = "unary-";
+
/**
* Return {@code true} if the given name is a library-private name.
* @param name the name being tested
* @return {@code true} if the given name is a library-private name
*/
static bool isPrivateName(String name) => name != null && name.startsWith(PRIVATE_NAME_PREFIX);
+
/**
* A table mapping names that are defined in this scope to the element representing the thing
* declared with that name.
*/
Map<String, Element> _definedNames = new Map<String, Element>();
+
/**
- * Initialize a newly created scope to be empty.
- */
- Scope() : super() {
- }
- /**
* Add the given element to this scope. If there is already an element with the given name defined
* in this scope, then an error will be generated and the original element will continue to be
* mapped to the name. If there is an element with the given name in an enclosing scope, then a
@@ -7155,6 +9087,7 @@
}
}
}
+
/**
* Return the element with which the given identifier is associated, or {@code null} if the name
* is not defined within this scope.
@@ -7163,7 +9096,8 @@
* implement library-level privacy
* @return the element with which the given identifier is associated
*/
- Element lookup(Identifier identifier, LibraryElement referencingLibrary) => lookup3(identifier.name, referencingLibrary);
+ Element lookup(Identifier identifier, LibraryElement referencingLibrary) => lookup3(identifier, identifier.name, referencingLibrary);
+
/**
* Add the given element to this scope without checking for duplication or hiding.
* @param element the element to be added to this scope
@@ -7171,11 +9105,22 @@
void defineWithoutChecking(Element element) {
_definedNames[getName(element)] = element;
}
+
/**
+ * Add the given element to this scope without checking for duplication or hiding.
+ * @param name the name of the element to be added
+ * @param element the element to be added to this scope
+ */
+ void defineWithoutChecking2(String name, Element element) {
+ _definedNames[name] = element;
+ }
+
+ /**
* Return the element representing the library in which this scope is enclosed.
* @return the element representing the library in which this scope is enclosed
*/
LibraryElement get definingLibrary;
+
/**
* Return the error code to be used when reporting that a name being defined locally conflicts
* with another element of the same name in the local scope.
@@ -7188,19 +9133,22 @@
if (source2 == null) {
source2 = source;
}
- return new AnalysisError.con2(source2, duplicate.nameOffset, duplicate.name.length, CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.name]);
+ return new AnalysisError.con2(source2, duplicate.nameOffset, duplicate.displayName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]);
}
+
/**
* Return the listener that is to be informed when an error is encountered.
* @return the listener that is to be informed when an error is encountered
*/
AnalysisErrorListener get errorListener;
+
/**
* Return the source object representing the compilation unit with which errors related to this
* scope should be associated.
* @return the source object with which errors should be associated
*/
Source get source => definingLibrary.definingCompilationUnit.source;
+
/**
* Return the element with which the given name is associated, or {@code null} if the name is not
* defined within this scope. This method only returns elements that are directly defined within
@@ -7211,15 +9159,19 @@
* @return the element with which the given name is associated
*/
Element localLookup(String name, LibraryElement referencingLibrary) => _definedNames[name];
+
/**
* Return the element with which the given name is associated, or {@code null} if the name is not
* defined within this scope.
+ * @param identifier the identifier node to lookup element for, used to report correct kind of a
+ * problem and associate problem with
* @param name the name associated with the element to be returned
* @param referencingLibrary the library that contains the reference to the name, used to
* implement library-level privacy
* @return the element with which the given name is associated
*/
- Element lookup3(String name, LibraryElement referencingLibrary);
+ Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary);
+
/**
* Return the name that will be used to look up the given element.
* @param element the element whose look-up name is to be returned
@@ -7231,15 +9183,11 @@
if (method.name == "-" && method.parameters.length == 0) {
return UNARY_MINUS;
}
- } else if (element is PropertyAccessorElement) {
- PropertyAccessorElement accessor = element as PropertyAccessorElement;
- if (accessor.isSetter()) {
- return "${accessor.name}${SETTER_SUFFIX}";
- }
}
return element.name;
}
}
+
/**
* Instances of the class {@code ConstantVerifier} traverse an AST structure looking for additional
* errors and warnings not covered by the parser and resolver. In particular, it looks for errors
@@ -7247,22 +9195,58 @@
* @coverage dart.engine.resolver
*/
class ConstantVerifier extends RecursiveASTVisitor<Object> {
+
/**
* The error reporter by which errors will be reported.
*/
ErrorReporter _errorReporter;
+
/**
+ * The type representing the type 'bool'.
+ */
+ InterfaceType _boolType;
+
+ /**
+ * The type representing the type 'int'.
+ */
+ InterfaceType _intType;
+
+ /**
+ * The type representing the type 'num'.
+ */
+ InterfaceType _numType;
+
+ /**
+ * The type representing the type 'string'.
+ */
+ InterfaceType _stringType;
+
+ /**
* Initialize a newly created constant verifier.
* @param errorReporter the error reporter by which errors will be reported
*/
- ConstantVerifier(ErrorReporter errorReporter) {
+ ConstantVerifier(ErrorReporter errorReporter, TypeProvider typeProvider) {
this._errorReporter = errorReporter;
+ this._boolType = typeProvider.boolType;
+ this._intType = typeProvider.intType;
+ this._numType = typeProvider.numType;
+ this._stringType = typeProvider.stringType;
}
+ Object visitConstructorDeclaration(ConstructorDeclaration node) {
+ if (node.constKeyword != null) {
+ validateInitializers(node);
+ }
+ return super.visitConstructorDeclaration(node);
+ }
Object visitFunctionExpression(FunctionExpression node) {
super.visitFunctionExpression(node);
validateDefaultValues(node.parameters);
return null;
}
+ Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+ validateConstantArguments(node);
+ return super.visitInstanceCreationExpression(node);
+ }
Object visitListLiteral(ListLiteral node) {
super.visitListLiteral(node);
if (node.modifier != null) {
@@ -7275,20 +9259,39 @@
Object visitMapLiteral(MapLiteral node) {
super.visitMapLiteral(node);
bool isConst = node.modifier != null;
- Set<String> keys = new Set<String>();
+ bool reportEqualKeys = true;
+ Set<Object> keys = new Set<Object>();
+ List<Expression> invalidKeys = new List<Expression>();
for (MapLiteralEntry entry in node.entries) {
- StringLiteral key2 = entry.key;
- EvaluationResultImpl result = validate(key2, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
- if (result is ValidResult && ((result as ValidResult)).value is String) {
- String value2 = ((result as ValidResult)).value as String;
- if (keys.contains(value2)) {
- _errorReporter.reportError(StaticWarningCode.EQUAL_KEYS_IN_MAP, key2, []);
+ Expression key2 = entry.key;
+ if (isConst) {
+ EvaluationResultImpl result = validate(key2, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
+ validate(entry.value, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
+ if (result is ValidResult) {
+ Object value2 = ((result as ValidResult)).value;
+ if (keys.contains(value2)) {
+ invalidKeys.add(key2);
+ } else {
+ javaSetAdd(keys, value2);
+ }
+ }
+ } else {
+ EvaluationResultImpl result = key2.accept(new ConstantVisitor());
+ if (result is ValidResult) {
+ Object value3 = ((result as ValidResult)).value;
+ if (keys.contains(value3)) {
+ invalidKeys.add(key2);
+ } else {
+ javaSetAdd(keys, value3);
+ }
} else {
- javaSetAdd(keys, value2);
+ reportEqualKeys = false;
}
}
- if (isConst) {
- validate(entry.value, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
+ }
+ if (reportEqualKeys) {
+ for (Expression key in invalidKeys) {
+ _errorReporter.reportError2(StaticWarningCode.EQUAL_KEYS_IN_MAP, key, []);
}
}
return null;
@@ -7318,19 +9321,35 @@
}
return null;
}
+
/**
+ * Return {@code true} if the given value is the result of evaluating an expression whose value is
+ * a valid key in a const map literal. Keys in const map literals must be either a string, number,
+ * boolean, list, map, or null.
+ * @param value
+ * @return {@code true} if the given value is a valid key in a const map literal
+ */
+ bool isValidConstMapKey(Object value) => true;
+
+ /**
* If the given result represents one or more errors, report those errors. Except for special
* cases, use the given error code rather than the one reported in the error.
* @param result the result containing any errors that need to be reported
* @param errorCode the error code to be used if the result represents an error
*/
- void reportErrors(EvaluationResultImpl result, ErrorCode errorCode) {
+ void reportErrors(EvaluationResultImpl result, ErrorCode errorCode2) {
if (result is ErrorResult) {
for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) {
- _errorReporter.reportError(errorCode, data.node, []);
+ ErrorCode dataErrorCode = data.errorCode;
+ if (identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM)) {
+ _errorReporter.reportError2(dataErrorCode, data.node, []);
+ } else {
+ _errorReporter.reportError2(errorCode2, data.node, []);
+ }
}
}
}
+
/**
* Validate that the given expression is a compile time constant. Return the value of the compile
* time constant, or {@code null} if the expression is not a compile time constant.
@@ -7343,7 +9362,29 @@
reportErrors(result, errorCode);
return result;
}
+
/**
+ * Validate that if the passed instance creation is 'const' then all its arguments are constant
+ * expressions.
+ * @param node the instance creation evaluate
+ */
+ void validateConstantArguments(InstanceCreationExpression node) {
+ if (!node.isConst()) {
+ return;
+ }
+ ArgumentList argumentList2 = node.argumentList;
+ if (argumentList2 == null) {
+ return;
+ }
+ for (Expression argument in argumentList2.arguments) {
+ if (argument is NamedExpression) {
+ argument = ((argument as NamedExpression)).expression;
+ }
+ validate(argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
+ }
+ }
+
+ /**
* Validate that the default value associated with each of the parameters in the given list is a
* compile time constant.
* @param parameters the list of parameters to be validated
@@ -7366,53 +9407,169 @@
}
}
}
+
+ /**
+ * Validates that the given expression is a compile time constant.
+ * @param parameterElements the elements of parameters of constant constructor, they are
+ * considered as a valid potentially constant expressions
+ * @param expression the expression to validate
+ */
+ void validateInitializerExpression(List<ParameterElement> parameterElements, Expression expression) {
+ EvaluationResultImpl result = expression.accept(new ConstantVisitor_10(this, parameterElements));
+ reportErrors(result, CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
+ }
+
+ /**
+ * Validates that all of the arguments of a constructor initializer are compile time constants.
+ * @param parameterElements the elements of parameters of constant constructor, they are
+ * considered as a valid potentially constant expressions
+ * @param argumentList the argument list to validate
+ */
+ void validateInitializerInvocationArguments(List<ParameterElement> parameterElements, ArgumentList argumentList) {
+ if (argumentList == null) {
+ return;
+ }
+ for (Expression argument in argumentList.arguments) {
+ validateInitializerExpression(parameterElements, argument);
+ }
+ }
+
+ /**
+ * Validates that the expressions of the given initializers (of a constant constructor) are all
+ * compile time constants.
+ * @param constructor the constant constructor declaration to validate
+ */
+ void validateInitializers(ConstructorDeclaration constructor) {
+ List<ParameterElement> parameterElements = constructor.parameters.elements;
+ NodeList<ConstructorInitializer> initializers2 = constructor.initializers;
+ for (ConstructorInitializer initializer in initializers2) {
+ if (initializer is ConstructorFieldInitializer) {
+ ConstructorFieldInitializer fieldInitializer = initializer as ConstructorFieldInitializer;
+ validateInitializerExpression(parameterElements, fieldInitializer.expression);
+ }
+ if (initializer is RedirectingConstructorInvocation) {
+ RedirectingConstructorInvocation invocation = initializer as RedirectingConstructorInvocation;
+ validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
+ }
+ if (initializer is SuperConstructorInvocation) {
+ SuperConstructorInvocation invocation = initializer as SuperConstructorInvocation;
+ validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
+ }
+ }
+ }
}
+class ConstantVisitor_10 extends ConstantVisitor {
+ final ConstantVerifier ConstantVerifier_this;
+ List<ParameterElement> parameterElements;
+ ConstantVisitor_10(this.ConstantVerifier_this, this.parameterElements) : super();
+ EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) {
+ Element element2 = node.element;
+ for (ParameterElement parameterElement in parameterElements) {
+ if (identical(parameterElement, element2) && parameterElement != null) {
+ Type2 type2 = parameterElement.type;
+ if (type2 != null) {
+ if (type2.isDynamic()) {
+ return ValidResult.RESULT_DYNAMIC;
+ }
+ if (type2.isSubtypeOf(ConstantVerifier_this._boolType)) {
+ return ValidResult.RESULT_BOOL;
+ }
+ if (type2.isSubtypeOf(ConstantVerifier_this._intType)) {
+ return ValidResult.RESULT_INT;
+ }
+ if (type2.isSubtypeOf(ConstantVerifier_this._numType)) {
+ return ValidResult.RESULT_NUM;
+ }
+ if (type2.isSubtypeOf(ConstantVerifier_this._stringType)) {
+ return ValidResult.RESULT_STRING;
+ }
+ }
+ return ValidResult.RESULT_OBJECT;
+ }
+ }
+ return super.visitSimpleIdentifier(node);
+ }
+}
+
/**
* Instances of the class {@code ErrorVerifier} traverse an AST structure looking for additional
* errors and warnings not covered by the parser and resolver.
* @coverage dart.engine.resolver
*/
class ErrorVerifier extends RecursiveASTVisitor<Object> {
+
/**
+ * Checks if the given expression is the reference to the type.
+ * @param expr the expression to evaluate
+ * @return {@code true} if the given expression is the reference to the type
+ */
+ static bool isTypeReference(Expression expr) {
+ if (expr is Identifier) {
+ Identifier identifier = expr as Identifier;
+ return identifier.element is ClassElement;
+ }
+ return false;
+ }
+
+ /**
* The error reporter by which errors will be reported.
*/
ErrorReporter _errorReporter;
+
/**
* The current library that is being analyzed.
*/
LibraryElement _currentLibrary;
+
/**
* The type representing the type 'dynamic'.
*/
Type2 _dynamicType;
+
/**
* The object providing access to the types defined by the language.
*/
TypeProvider _typeProvider;
+
/**
+ * The manager for the inheritance mappings.
+ */
+ InheritanceManager _inheritanceManager;
+
+ /**
* This is set to {@code true} iff the visitor is currently visiting children nodes of a{@link ConstructorDeclaration} and the constructor is 'const'.
* @see #visitConstructorDeclaration(ConstructorDeclaration)
*/
bool _isEnclosingConstructorConst = false;
+
/**
* This is set to {@code true} iff the visitor is currently visiting children nodes of a{@link CatchClause}.
* @see #visitCatchClause(CatchClause)
*/
bool _isInCatchClause = false;
+
/**
+ * This is set to {@code true} iff the visitor is currently visiting a{@link ConstructorInitializer}.
+ */
+ bool _isInConstructorInitializer = false;
+
+ /**
* This is set to {@code true} iff the visitor is currently visiting code in the SDK.
*/
bool _isInSystemLibrary = false;
+
/**
* The class containing the AST nodes being visited, or {@code null} if we are not in the scope of
* a class.
*/
ClassElement _enclosingClass;
+
/**
* The method or function that we are currently visiting, or {@code null} if we are not inside a
* method or function.
*/
ExecutableElement _enclosingFunction;
+
/**
* This map is initialized when visiting the contents of a class declaration. If the visitor is
* not in an enclosing class declaration, then the map is set to {@code null}.
@@ -7425,15 +9582,37 @@
* @see #checkForAllFinalInitializedErrorCodes(ConstructorDeclaration)
*/
Map<FieldElement, INIT_STATE> _initialFieldElementsMap;
+
/**
+ * A table mapping name of the library to the export directive which export this library.
+ */
+ Map<String, LibraryElement> _nameToExportElement = new Map<String, LibraryElement>();
+
+ /**
+ * A table mapping name of the library to the import directive which import this library.
+ */
+ Map<String, LibraryElement> _nameToImportElement = new Map<String, LibraryElement>();
+
+ /**
+ * A table mapping names to the export elements exported them.
+ */
+ Map<String, ExportElement> _exportedNames = new Map<String, ExportElement>();
+
+ /**
+ * A set of the names of the variable initializers we are visiting now.
+ */
+ Set<String> _namesForReferenceToDeclaredVariableInInitializer = new Set<String>();
+
+ /**
* A list of types used by the {@link CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS} and{@link CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS} error codes.
*/
List<InterfaceType> _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT;
- ErrorVerifier(ErrorReporter errorReporter, LibraryElement currentLibrary, TypeProvider typeProvider) {
+ ErrorVerifier(ErrorReporter errorReporter, LibraryElement currentLibrary, TypeProvider typeProvider, InheritanceManager inheritanceManager) {
this._errorReporter = errorReporter;
this._currentLibrary = currentLibrary;
this._isInSystemLibrary = currentLibrary.source.isInSystemLibrary();
this._typeProvider = typeProvider;
+ this._inheritanceManager = inheritanceManager;
_isEnclosingConstructorConst = false;
_isInCatchClause = false;
_dynamicType = typeProvider.dynamicType;
@@ -7443,14 +9622,29 @@
checkForArgumentDefinitionTestNonParameter(node);
return super.visitArgumentDefinitionTest(node);
}
+ Object visitArgumentList(ArgumentList node) {
+ checkForArgumentTypeNotAssignable(node);
+ return super.visitArgumentList(node);
+ }
Object visitAssertStatement(AssertStatement node) {
checkForNonBoolExpression(node);
return super.visitAssertStatement(node);
}
Object visitAssignmentExpression(AssignmentExpression node) {
- checkForInvalidAssignment(node);
+ sc.Token operator2 = node.operator;
+ sc.TokenType operatorType = operator2.type;
+ if (identical(operatorType, sc.TokenType.EQ)) {
+ checkForInvalidAssignment2(node.leftHandSide, node.rightHandSide);
+ } else {
+ checkForInvalidAssignment(node);
+ }
+ checkForAssignmentToFinal(node);
return super.visitAssignmentExpression(node);
}
+ Object visitBinaryExpression(BinaryExpression node) {
+ checkForArgumentTypeNotAssignable2(node.rightOperand);
+ return super.visitBinaryExpression(node);
+ }
Object visitCatchClause(CatchClause node) {
bool previousIsInCatchClause = _isInCatchClause;
try {
@@ -7464,7 +9658,19 @@
ClassElement outerClass = _enclosingClass;
try {
_enclosingClass = node.element;
+ WithClause withClause2 = node.withClause;
+ ImplementsClause implementsClause2 = node.implementsClause;
+ ExtendsClause extendsClause2 = node.extendsClause;
checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME);
+ checkForMemberWithClassName();
+ checkForAllMixinErrorCodes(withClause2);
+ if (implementsClause2 != null || extendsClause2 != null) {
+ if (!checkForImplementsDisallowedClass(implementsClause2) && !checkForExtendsDisallowedClass(extendsClause2)) {
+ checkForNonAbstractClassInheritsAbstractMember(node);
+ checkForInconsistentMethodInheritance();
+ checkForRecursiveInterfaceInheritance(_enclosingClass, new List<ClassElement>());
+ }
+ }
ClassElement classElement = node.element;
if (classElement != null) {
List<FieldElement> fieldElements = classElement.fields;
@@ -7484,6 +9690,14 @@
}
Object visitClassTypeAlias(ClassTypeAlias node) {
checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
+ checkForAllMixinErrorCodes(node.withClause);
+ ClassElement outerClassElement = _enclosingClass;
+ try {
+ _enclosingClass = node.element;
+ checkForRecursiveInterfaceInheritance(node.element, new List<ClassElement>());
+ } finally {
+ _enclosingClass = outerClassElement;
+ }
return super.visitClassTypeAlias(node);
}
Object visitConditionalExpression(ConditionalExpression node) {
@@ -7498,12 +9712,28 @@
checkForConstConstructorWithNonFinalField(node);
checkForConflictingConstructorNameAndMember(node);
checkForAllFinalInitializedErrorCodes(node);
+ checkForRedirectingConstructorErrorCodes(node);
+ checkForMultipleSuperInitializers(node);
+ checkForRecursiveConstructorRedirect(node);
+ checkForRecursiveFactoryRedirect(node);
+ checkForRedirectToInvalidFunction(node);
+ checkForUndefinedConstructorInInitializerImplicit(node);
+ checkForRedirectToNonConstConstructor(node);
return super.visitConstructorDeclaration(node);
} finally {
_isEnclosingConstructorConst = false;
_enclosingFunction = outerFunction;
}
}
+ Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ _isInConstructorInitializer = true;
+ try {
+ checkForFieldInitializerNotAssignable(node);
+ return super.visitConstructorFieldInitializer(node);
+ } finally {
+ _isInConstructorInitializer = false;
+ }
+ }
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
checkForPrivateOptionalParameter(node);
return super.visitDefaultFormalParameter(node);
@@ -7512,19 +9742,37 @@
checkForNonBoolCondition(node.condition);
return super.visitDoStatement(node);
}
- Object visitExtendsClause(ExtendsClause node) {
- checkForExtendsDisallowedClass(node);
- return super.visitExtendsClause(node);
+ Object visitExportDirective(ExportDirective node) {
+ checkForAmbiguousExport(node);
+ checkForExportDuplicateLibraryName(node);
+ checkForExportInternalLibrary(node);
+ return super.visitExportDirective(node);
}
Object visitFieldFormalParameter(FieldFormalParameter node) {
checkForConstFormalParameter(node);
- checkForFieldInitializerOutsideConstructor(node);
+ checkForFieldInitializingFormalRedirectingConstructor(node);
return super.visitFieldFormalParameter(node);
}
Object visitFunctionDeclaration(FunctionDeclaration node) {
ExecutableElement outerFunction = _enclosingFunction;
try {
+ SimpleIdentifier identifier = node.name;
+ String methoName = "";
+ if (identifier != null) {
+ methoName = identifier.name;
+ }
_enclosingFunction = node.element;
+ if (node.isSetter() || node.isGetter()) {
+ checkForMismatchedAccessorTypes(node, methoName);
+ if (node.isSetter()) {
+ FunctionExpression functionExpression2 = node.functionExpression;
+ if (functionExpression2 != null) {
+ checkForWrongNumberOfParametersForSetter(node.name, functionExpression2.parameters);
+ }
+ TypeName returnType2 = node.returnType;
+ checkForNonVoidReturnTypeForSetter(returnType2);
+ }
+ }
return super.visitFunctionDeclaration(node);
} finally {
_enclosingFunction = outerFunction;
@@ -7548,18 +9796,29 @@
checkForNonBoolCondition(node.condition);
return super.visitIfStatement(node);
}
- Object visitImplementsClause(ImplementsClause node) {
- checkForImplementsDisallowedClass(node);
- return super.visitImplementsClause(node);
+ Object visitImportDirective(ImportDirective node) {
+ checkForImportDuplicateLibraryName(node);
+ checkForImportInternalLibrary(node);
+ return super.visitImportDirective(node);
}
+ Object visitIndexExpression(IndexExpression node) {
+ checkForArgumentTypeNotAssignable2(node.index);
+ return super.visitIndexExpression(node);
+ }
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
ConstructorName constructorName2 = node.constructorName;
TypeName typeName = constructorName2.type;
Type2 type2 = typeName.type;
if (type2 is InterfaceType) {
InterfaceType interfaceType = type2 as InterfaceType;
- checkForConstWithNonConst(node);
checkForConstOrNewWithAbstractClass(node, typeName, interfaceType);
+ if (node.isConst()) {
+ checkForConstWithNonConst(node);
+ checkForConstWithUndefinedConstructor(node);
+ checkForConstWithTypeParameters(node);
+ } else {
+ checkForNewWithUndefinedConstructor(node);
+ }
checkForTypeArgumentNotMatchingBounds(node, constructorName2.element, typeName);
}
return super.visitInstanceCreationExpression(node);
@@ -7587,27 +9846,74 @@
}
}
}
+ checkForNonConstMapAsExpressionStatement(node);
return super.visitMapLiteral(node);
}
Object visitMethodDeclaration(MethodDeclaration node) {
ExecutableElement previousFunction = _enclosingFunction;
try {
_enclosingFunction = node.element;
- if (node.isSetter()) {
- checkForWrongNumberOfParametersForSetter(node);
+ SimpleIdentifier identifier = node.name;
+ String methoName = "";
+ if (identifier != null) {
+ methoName = identifier.name;
+ }
+ if (node.isSetter() || node.isGetter()) {
+ checkForMismatchedAccessorTypes(node, methoName);
+ checkForConflictingInstanceGetterAndSuperclassMember(node);
+ }
+ if (node.isGetter()) {
+ checkForConflictingStaticGetterAndInstanceSetter(node);
+ } else if (node.isSetter()) {
+ checkForWrongNumberOfParametersForSetter(node.name, node.parameters);
+ checkForNonVoidReturnTypeForSetter(node.returnType);
+ checkForConflictingStaticSetterAndInstanceMember(node);
} else if (node.isOperator()) {
checkForOptionalParameterInOperator(node);
+ checkForWrongNumberOfParametersForOperator(node);
+ checkForNonVoidReturnTypeForOperator(node);
}
checkForConcreteClassWithAbstractMember(node);
+ checkForAllInvalidOverrideErrorCodes(node);
return super.visitMethodDeclaration(node);
} finally {
_enclosingFunction = previousFunction;
}
}
+ Object visitMethodInvocation(MethodInvocation node) {
+ checkForStaticAccessToInstanceMember(node.target, node.methodName);
+ return super.visitMethodInvocation(node);
+ }
Object visitNativeFunctionBody(NativeFunctionBody node) {
checkForNativeFunctionBodyInNonSDKCode(node);
return super.visitNativeFunctionBody(node);
}
+ Object visitPostfixExpression(PostfixExpression node) {
+ checkForAssignmentToFinal2(node.operand);
+ return super.visitPostfixExpression(node);
+ }
+ Object visitPrefixedIdentifier(PrefixedIdentifier node) {
+ checkForStaticAccessToInstanceMember(node.prefix, node.identifier);
+ return super.visitPrefixedIdentifier(node);
+ }
+ Object visitPrefixExpression(PrefixExpression node) {
+ if (node.operator.type.isIncrementOperator()) {
+ checkForAssignmentToFinal2(node.operand);
+ }
+ return super.visitPrefixExpression(node);
+ }
+ Object visitPropertyAccess(PropertyAccess node) {
+ checkForStaticAccessToInstanceMember(node.target, node.propertyName);
+ return super.visitPropertyAccess(node);
+ }
+ Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+ _isInConstructorInitializer = true;
+ try {
+ return super.visitRedirectingConstructorInvocation(node);
+ } finally {
+ _isInConstructorInitializer = false;
+ }
+ }
Object visitRethrowExpression(RethrowExpression node) {
checkForRethrowOutsideCatch(node);
return super.visitRethrowExpression(node);
@@ -7620,11 +9926,30 @@
checkForConstFormalParameter(node);
return super.visitSimpleFormalParameter(node);
}
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ checkForReferenceToDeclaredVariableInInitializer(node);
+ checkForImplicitThisReferenceInInitializer(node);
+ return super.visitSimpleIdentifier(node);
+ }
+ Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ _isInConstructorInitializer = true;
+ try {
+ return super.visitSuperConstructorInvocation(node);
+ } finally {
+ _isInConstructorInitializer = false;
+ }
+ }
Object visitSwitchStatement(SwitchStatement node) {
checkForCaseExpressionTypeImplementsEquals(node);
checkForInconsistentCaseExpressionTypes(node);
+ checkForSwitchExpressionNotAssignable(node);
+ checkForCaseBlocksNotTerminated(node);
return super.visitSwitchStatement(node);
}
+ Object visitThisExpression(ThisExpression node) {
+ checkForInvalidReferenceToThis(node);
+ return super.visitThisExpression(node);
+ }
Object visitThrowExpression(ThrowExpression node) {
checkForConstEvalThrowsException(node);
return super.visitThrowExpression(node);
@@ -7637,6 +9962,22 @@
checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME);
return super.visitTypeParameter(node);
}
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ SimpleIdentifier nameNode = node.name;
+ Expression initializerNode = node.initializer;
+ checkForInvalidAssignment2(nameNode, initializerNode);
+ nameNode.accept(this);
+ String name2 = nameNode.name;
+ javaSetAdd(_namesForReferenceToDeclaredVariableInInitializer, name2);
+ try {
+ if (initializerNode != null) {
+ initializerNode.accept(this);
+ }
+ } finally {
+ _namesForReferenceToDeclaredVariableInInitializer.remove(name2);
+ }
+ return null;
+ }
Object visitVariableDeclarationList(VariableDeclarationList node) {
checkForBuiltInIdentifierAsName2(node);
return super.visitVariableDeclarationList(node);
@@ -7649,11 +9990,12 @@
checkForNonBoolCondition(node.condition);
return super.visitWhileStatement(node);
}
+
/**
* This verifies that the passed constructor declaration does not violate any of the error codes
* relating to the initialization of fields in the enclosing class.
* @param node the {@link ConstructorDeclaration} to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see #initialFieldElementsMap
* @see CompileTimeErrorCode#FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR
* @see CompileTimeErrorCode#FINAL_INITIALIZED_MULTIPLE_TIMES
@@ -7677,12 +10019,12 @@
fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_FIELD_FORMAL;
} else if (identical(state, INIT_STATE.INIT_IN_DECLARATION)) {
if (fieldElement.isFinal() || fieldElement.isConst()) {
- _errorReporter.reportError(CompileTimeErrorCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR, formalParameter.identifier, [fieldElement.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR, formalParameter.identifier, [fieldElement.displayName]);
foundError = true;
}
} else if (identical(state, INIT_STATE.INIT_IN_FIELD_FORMAL)) {
if (fieldElement.isFinal() || fieldElement.isConst()) {
- _errorReporter.reportError(CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES, formalParameter.identifier, [fieldElement.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES, formalParameter.identifier, [fieldElement.displayName]);
foundError = true;
}
}
@@ -7701,14 +10043,14 @@
fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_INITIALIZERS;
} else if (identical(state, INIT_STATE.INIT_IN_DECLARATION)) {
if (fieldElement.isFinal() || fieldElement.isConst()) {
- _errorReporter.reportError(CompileTimeErrorCode.FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION, fieldName2, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION, fieldName2, []);
foundError = true;
}
} else if (identical(state, INIT_STATE.INIT_IN_FIELD_FORMAL)) {
- _errorReporter.reportError(CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER, fieldName2, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER, fieldName2, []);
foundError = true;
} else if (identical(state, INIT_STATE.INIT_IN_INITIALIZERS)) {
- _errorReporter.reportError(CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS, fieldName2, [fieldElement.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS, fieldName2, [fieldElement.displayName]);
foundError = true;
}
}
@@ -7716,7 +10058,181 @@
}
return foundError;
}
+
/**
+ * This checks the passed method declaration against override-error codes.
+ * @param node the {@link MethodDeclaration} to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC
+ * @see CompileTimeErrorCode#INVALID_OVERRIDE_REQUIRED
+ * @see CompileTimeErrorCode#INVALID_OVERRIDE_POSITIONAL
+ * @see CompileTimeErrorCode#INVALID_OVERRIDE_NAMED
+ * @see StaticWarningCode#INVALID_GETTER_OVERRIDE_RETURN_TYPE
+ * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_RETURN_TYPE
+ * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE
+ * @see StaticWarningCode#INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE
+ * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE
+ * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE
+ */
+ bool checkForAllInvalidOverrideErrorCodes(MethodDeclaration node) {
+ if (_enclosingClass == null || node.isStatic() || node.body is NativeFunctionBody) {
+ return false;
+ }
+ ExecutableElement executableElement = node.element;
+ if (executableElement == null) {
+ return false;
+ }
+ SimpleIdentifier methodName = node.name;
+ if (methodName.isSynthetic()) {
+ return false;
+ }
+ String methodNameStr = methodName.name;
+ ExecutableElement overriddenExecutable = _inheritanceManager.lookupInheritance(_enclosingClass, executableElement.name);
+ if (overriddenExecutable == null) {
+ if (!node.isGetter() && !node.isSetter() && !node.isOperator()) {
+ Set<ClassElement> visitedClasses = new Set<ClassElement>();
+ InterfaceType superclassType = _enclosingClass.supertype;
+ ClassElement superclassElement = superclassType == null ? null : superclassType.element;
+ while (superclassElement != null && !visitedClasses.contains(superclassElement)) {
+ javaSetAdd(visitedClasses, superclassElement);
+ List<FieldElement> fieldElts = superclassElement.fields;
+ for (FieldElement fieldElt in fieldElts) {
+ if (fieldElt.name == methodNameStr && fieldElt.isStatic()) {
+ _errorReporter.reportError2(StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC, methodName, [methodNameStr, fieldElt.enclosingElement.displayName]);
+ return true;
+ }
+ }
+ List<PropertyAccessorElement> propertyAccessorElts = superclassElement.accessors;
+ for (PropertyAccessorElement accessorElt in propertyAccessorElts) {
+ if (accessorElt.name == methodNameStr && accessorElt.isStatic()) {
+ _errorReporter.reportError2(StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC, methodName, [methodNameStr, accessorElt.enclosingElement.displayName]);
+ return true;
+ }
+ }
+ List<MethodElement> methodElements = superclassElement.methods;
+ for (MethodElement methodElement in methodElements) {
+ if (methodElement.name == methodNameStr && methodElement.isStatic()) {
+ _errorReporter.reportError2(StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC, methodName, [methodNameStr, methodElement.enclosingElement.displayName]);
+ return true;
+ }
+ }
+ superclassType = superclassElement.supertype;
+ superclassElement = superclassType == null ? null : superclassType.element;
+ }
+ }
+ return false;
+ }
+ FunctionType overridingFT = executableElement.type;
+ FunctionType overriddenFT = overriddenExecutable.type;
+ InterfaceType enclosingType = _enclosingClass.type;
+ overriddenFT = _inheritanceManager.substituteTypeArgumentsInMemberFromInheritance(overriddenFT, methodNameStr, enclosingType);
+ if (overridingFT == null || overriddenFT == null) {
+ return false;
+ }
+ Type2 overridingFTReturnType = overridingFT.returnType;
+ Type2 overriddenFTReturnType = overriddenFT.returnType;
+ List<Type2> overridingNormalPT = overridingFT.normalParameterTypes;
+ List<Type2> overriddenNormalPT = overriddenFT.normalParameterTypes;
+ List<Type2> overridingPositionalPT = overridingFT.optionalParameterTypes;
+ List<Type2> overriddenPositionalPT = overriddenFT.optionalParameterTypes;
+ Map<String, Type2> overridingNamedPT = overridingFT.namedParameterTypes;
+ Map<String, Type2> overriddenNamedPT = overriddenFT.namedParameterTypes;
+ if (overridingNormalPT.length != overriddenNormalPT.length) {
+ _errorReporter.reportError2(CompileTimeErrorCode.INVALID_OVERRIDE_REQUIRED, methodName, [overriddenNormalPT.length, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ if (overridingPositionalPT.length < overriddenPositionalPT.length) {
+ _errorReporter.reportError2(CompileTimeErrorCode.INVALID_OVERRIDE_POSITIONAL, methodName, [overriddenPositionalPT.length, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ Set<String> overridingParameterNameSet = overridingNamedPT.keys.toSet();
+ JavaIterator<String> overriddenParameterNameIterator = new JavaIterator(overriddenNamedPT.keys.toSet());
+ while (overriddenParameterNameIterator.hasNext) {
+ String overriddenParamName = overriddenParameterNameIterator.next();
+ if (!overridingParameterNameSet.contains(overriddenParamName)) {
+ _errorReporter.reportError2(CompileTimeErrorCode.INVALID_OVERRIDE_NAMED, methodName, [overriddenParamName, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ }
+ if (overriddenFTReturnType != VoidTypeImpl.instance && !overridingFTReturnType.isAssignableTo(overriddenFTReturnType)) {
+ _errorReporter.reportError2(!node.isGetter() ? StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE : StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE, methodName, [overridingFTReturnType.displayName, overriddenFTReturnType.displayName, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ FormalParameterList formalParameterList = node.parameters;
+ if (formalParameterList == null) {
+ return false;
+ }
+ NodeList<FormalParameter> parameterNodeList = formalParameterList.parameters;
+ int parameterIndex = 0;
+ for (int i = 0; i < overridingNormalPT.length; i++) {
+ if (!overridingNormalPT[i].isAssignableTo(overriddenNormalPT[i])) {
+ _errorReporter.reportError2(!node.isSetter() ? StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE : StaticWarningCode.INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE, parameterNodeList[parameterIndex], [overridingNormalPT[i].displayName, overriddenNormalPT[i].displayName, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ parameterIndex++;
+ }
+ for (int i = 0; i < overriddenPositionalPT.length; i++) {
+ if (!overridingPositionalPT[i].isAssignableTo(overriddenPositionalPT[i])) {
+ _errorReporter.reportError2(StaticWarningCode.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE, parameterNodeList[parameterIndex], [overridingPositionalPT[i].displayName, overriddenPositionalPT[i].displayName, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ parameterIndex++;
+ }
+ JavaIterator<MapEntry<String, Type2>> overriddenNamedPTIterator = new JavaIterator(getMapEntrySet(overriddenNamedPT));
+ while (overriddenNamedPTIterator.hasNext) {
+ MapEntry<String, Type2> overriddenNamedPTEntry = overriddenNamedPTIterator.next();
+ Type2 overridingType = overridingNamedPT[overriddenNamedPTEntry.getKey()];
+ if (overridingType == null) {
+ continue;
+ }
+ if (!overriddenNamedPTEntry.getValue().isAssignableTo(overridingType)) {
+ NormalFormalParameter parameterToSelect = null;
+ for (FormalParameter formalParameter in parameterNodeList) {
+ if (formalParameter is DefaultFormalParameter && identical(formalParameter.kind, ParameterKind.NAMED)) {
+ DefaultFormalParameter defaultFormalParameter = formalParameter as DefaultFormalParameter;
+ NormalFormalParameter normalFormalParameter = defaultFormalParameter.parameter;
+ if (overriddenNamedPTEntry.getKey() == normalFormalParameter.identifier.name) {
+ parameterToSelect = normalFormalParameter;
+ break;
+ }
+ }
+ }
+ if (parameterToSelect != null) {
+ _errorReporter.reportError2(StaticWarningCode.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE, parameterToSelect, [overridingType.displayName, overriddenNamedPTEntry.getValue().displayName, overriddenExecutable.enclosingElement.displayName]);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that all classes of the passed 'with' clause are valid.
+ * @param node the 'with' clause to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MIXIN_DECLARES_CONSTRUCTOR
+ * @see CompileTimeErrorCode#MIXIN_INHERITS_FROM_NOT_OBJECT
+ * @see CompileTimeErrorCode#MIXIN_REFERENCES_SUPER
+ */
+ bool checkForAllMixinErrorCodes(WithClause withClause) {
+ if (withClause == null) {
+ return false;
+ }
+ bool problemReported = false;
+ for (TypeName mixinName in withClause.mixinTypes) {
+ Type2 mixinType = mixinName.type;
+ if (mixinType is! InterfaceType) {
+ continue;
+ }
+ ClassElement mixinElement = ((mixinType as InterfaceType)).element;
+ problemReported = javaBooleanOr(problemReported, checkForMixinDeclaresConstructor(mixinName, mixinElement));
+ problemReported = javaBooleanOr(problemReported, checkForMixinInheritsNotFromObject(mixinName, mixinElement));
+ problemReported = javaBooleanOr(problemReported, checkForMixinReferencesSuper(mixinName, mixinElement));
+ }
+ return problemReported;
+ }
+
+ /**
* This checks that the return statement of the form <i>return e;</i> is not in a generative
* constructor.
* <p>
@@ -7737,47 +10253,193 @@
Type2 expectedReturnType = functionType == null ? DynamicTypeImpl.instance : functionType.returnType;
Expression returnExpression = node.expression;
bool isGenerativeConstructor = _enclosingFunction is ConstructorElement && !((_enclosingFunction as ConstructorElement)).isFactory();
- if (returnExpression != null) {
- if (isGenerativeConstructor) {
- _errorReporter.reportError(CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR, returnExpression, []);
- return true;
+ if (isGenerativeConstructor) {
+ if (returnExpression == null) {
+ return false;
}
- if (!expectedReturnType.isVoid()) {
- Type2 actualReturnType = getType(returnExpression);
- if (!actualReturnType.isAssignableTo(expectedReturnType)) {
- _errorReporter.reportError(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [actualReturnType.name, expectedReturnType.name, _enclosingFunction.name]);
- return true;
- }
+ _errorReporter.reportError2(CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR, returnExpression, []);
+ return true;
+ }
+ if (returnExpression == null) {
+ if (VoidTypeImpl.instance.isAssignableTo(expectedReturnType)) {
+ return false;
}
+ _errorReporter.reportError2(StaticWarningCode.RETURN_WITHOUT_VALUE, node, []);
+ return true;
+ }
+ Type2 staticReturnType = getStaticType(returnExpression);
+ if (expectedReturnType.isVoid()) {
+ if (staticReturnType.isVoid() || staticReturnType.isDynamic() || identical(staticReturnType, BottomTypeImpl.instance)) {
+ return false;
+ }
+ _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [staticReturnType.displayName, expectedReturnType.displayName, _enclosingFunction.displayName]);
+ return true;
+ }
+ bool isStaticAssignable = staticReturnType.isAssignableTo(expectedReturnType);
+ Type2 propagatedReturnType = getPropagatedType(returnExpression);
+ if (propagatedReturnType == null) {
+ if (isStaticAssignable) {
+ return false;
+ }
+ _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [staticReturnType.displayName, expectedReturnType.displayName, _enclosingFunction.displayName]);
+ return true;
} else {
- if (!isGenerativeConstructor && !VoidTypeImpl.instance.isAssignableTo(expectedReturnType)) {
- _errorReporter.reportError(StaticWarningCode.RETURN_WITHOUT_VALUE, node, []);
+ bool isPropagatedAssignable = propagatedReturnType.isAssignableTo(expectedReturnType);
+ if (isStaticAssignable || isPropagatedAssignable) {
+ return false;
}
+ _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [staticReturnType.displayName, expectedReturnType.displayName, _enclosingFunction.displayName]);
+ return true;
}
+ }
+
+ /**
+ * This verifies that the export namespace of the passed export directive does not export any name
+ * already exported by other export directive.
+ * @param node the export directive node to report problem on
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#AMBIGUOUS_EXPORT
+ */
+ bool checkForAmbiguousExport(ExportDirective node) {
+ if (node.element is! ExportElement) {
+ return false;
+ }
+ ExportElement exportElement = node.element as ExportElement;
+ LibraryElement exportedLibrary2 = exportElement.exportedLibrary;
+ if (exportedLibrary2 == null) {
+ return false;
+ }
+ Namespace namespace = new NamespaceBuilder().createExportNamespace(exportElement);
+ Set<String> newNames = namespace.definedNames.keys.toSet();
+ for (String name in newNames) {
+ ExportElement prevElement = _exportedNames[name];
+ if (prevElement != null && prevElement != exportElement) {
+ _errorReporter.reportError2(CompileTimeErrorCode.AMBIGUOUS_EXPORT, node, [name, prevElement.exportedLibrary.definingCompilationUnit.displayName, exportedLibrary2.definingCompilationUnit.displayName]);
+ return true;
+ } else {
+ _exportedNames[name] = exportElement;
+ }
+ }
return false;
}
+
/**
* This verifies that the passed argument definition test identifier is a parameter.
* @param node the {@link ArgumentDefinitionTest} to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#ARGUMENT_DEFINITION_TEST_NON_PARAMETER
*/
bool checkForArgumentDefinitionTestNonParameter(ArgumentDefinitionTest node) {
SimpleIdentifier identifier2 = node.identifier;
Element element2 = identifier2.element;
if (element2 != null && element2 is! ParameterElement) {
- _errorReporter.reportError(CompileTimeErrorCode.ARGUMENT_DEFINITION_TEST_NON_PARAMETER, identifier2, [identifier2.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.ARGUMENT_DEFINITION_TEST_NON_PARAMETER, identifier2, [identifier2.name]);
return true;
}
return false;
}
+
/**
+ * This verifies that the passed arguments can be assigned to their corresponding parameters.
+ * @param node the arguments to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
+ */
+ bool checkForArgumentTypeNotAssignable(ArgumentList argumentList) {
+ if (argumentList == null) {
+ return false;
+ }
+ bool problemReported = false;
+ for (Expression argument in argumentList.arguments) {
+ problemReported = javaBooleanOr(problemReported, checkForArgumentTypeNotAssignable2(argument));
+ }
+ return problemReported;
+ }
+
+ /**
+ * This verifies that the passed argument can be assigned to their corresponding parameters.
+ * @param node the argument to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
+ */
+ bool checkForArgumentTypeNotAssignable2(Expression argument) {
+ if (argument == null) {
+ return false;
+ }
+ ParameterElement parameterElement2 = argument.parameterElement;
+ if (parameterElement2 == null) {
+ return false;
+ }
+ Type2 parameterType = parameterElement2.type;
+ if (parameterType == null) {
+ return false;
+ }
+ Type2 staticType = getStaticType(argument);
+ if (staticType == null) {
+ return false;
+ }
+ if (staticType.isAssignableTo(parameterType)) {
+ return false;
+ }
+ Type2 propagatedType = getPropagatedType(argument);
+ if (propagatedType != null && propagatedType.isAssignableTo(parameterType)) {
+ return false;
+ }
+ _errorReporter.reportError2(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, argument, [(propagatedType == null ? staticType : propagatedType).displayName, parameterType.displayName]);
+ return true;
+ }
+
+ /**
+ * This verifies that left hand side of the passed assignment expression is not final.
+ * @param node the assignment expression to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ASSIGNMENT_TO_FINAL
+ */
+ bool checkForAssignmentToFinal(AssignmentExpression node) {
+ Expression leftExpression = node.leftHandSide;
+ return checkForAssignmentToFinal2(leftExpression);
+ }
+
+ /**
+ * This verifies that the passed expression is not final.
+ * @param node the expression to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ASSIGNMENT_TO_FINAL
+ */
+ bool checkForAssignmentToFinal2(Expression expression) {
+ Element element = null;
+ if (expression is Identifier) {
+ element = ((expression as Identifier)).element;
+ }
+ if (expression is PropertyAccess) {
+ element = ((expression as PropertyAccess)).propertyName.element;
+ }
+ if (element is VariableElement) {
+ VariableElement leftVar = element as VariableElement;
+ if (leftVar.isFinal()) {
+ _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_FINAL, expression, []);
+ return true;
+ }
+ return false;
+ }
+ if (element is PropertyAccessorElement) {
+ PropertyAccessorElement leftAccessor = element as PropertyAccessorElement;
+ if (!leftAccessor.isSetter()) {
+ _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_FINAL, expression, []);
+ return true;
+ }
+ return false;
+ }
+ return false;
+ }
+
+ /**
* This verifies that the passed identifier is not a keyword, and generates the passed error code
* on the identifier if it is a keyword.
* @param identifier the identifier to check to ensure that it is not a keyword
* @param errorCode if the passed identifier is a keyword then this error code is created on the
* identifier, the error code will be one of{@link CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_NAME},{@link CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME} or{@link CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME}
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_NAME
* @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME
* @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME
@@ -7785,15 +10447,16 @@
bool checkForBuiltInIdentifierAsName(SimpleIdentifier identifier, ErrorCode errorCode) {
sc.Token token2 = identifier.token;
if (identical(token2.type, sc.TokenType.KEYWORD)) {
- _errorReporter.reportError(errorCode, identifier, [identifier.name]);
+ _errorReporter.reportError2(errorCode, identifier, [identifier.name]);
return true;
}
return false;
}
+
/**
* This verifies that the passed variable declaration list does not have a built-in identifier.
* @param node the variable declaration list to check
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE
*/
bool checkForBuiltInIdentifierAsName2(VariableDeclarationList node) {
@@ -7805,7 +10468,7 @@
sc.Token token2 = simpleIdentifier.token;
if (identical(token2.type, sc.TokenType.KEYWORD)) {
if (((token2 as sc.KeywordToken)).keyword != sc.Keyword.DYNAMIC) {
- _errorReporter.reportError(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, identifier, [identifier.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, identifier, [identifier.name]);
return true;
}
}
@@ -7813,29 +10476,86 @@
}
return false;
}
+
/**
+ * This verifies that the given switch case is terminated with 'break', 'continue', 'return' or
+ * 'throw'.
+ * @param node the switch case to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#CASE_BLOCK_NOT_TERMINATED
+ */
+ bool checkForCaseBlockNotTerminated(SwitchCase node) {
+ NodeList<Statement> statements2 = node.statements;
+ if (statements2.isEmpty) {
+ ASTNode parent2 = node.parent;
+ if (parent2 is SwitchStatement) {
+ SwitchStatement switchStatement = parent2 as SwitchStatement;
+ NodeList<SwitchMember> members2 = switchStatement.members;
+ int index = members2.indexOf(node);
+ if (index != -1 && index < members2.length - 1) {
+ return false;
+ }
+ }
+ } else {
+ Statement statement = statements2[statements2.length - 1];
+ if (statement is BreakStatement || statement is ContinueStatement || statement is ReturnStatement) {
+ return false;
+ }
+ if (statement is ExpressionStatement) {
+ Expression expression2 = ((statement as ExpressionStatement)).expression;
+ if (expression2 is ThrowExpression) {
+ return false;
+ }
+ }
+ }
+ _errorReporter.reportError4(StaticWarningCode.CASE_BLOCK_NOT_TERMINATED, node.keyword, []);
+ return true;
+ }
+
+ /**
+ * This verifies that the switch cases in the given switch statement is terminated with 'break',
+ * 'continue', 'return' or 'throw'.
+ * @param node the switch statement containing the cases to be checked
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#CASE_BLOCK_NOT_TERMINATED
+ */
+ bool checkForCaseBlocksNotTerminated(SwitchStatement node) {
+ bool foundError = false;
+ NodeList<SwitchMember> members2 = node.members;
+ int lastMember = members2.length - 1;
+ for (int i = 0; i < lastMember; i++) {
+ SwitchMember member = members2[i];
+ if (member is SwitchCase) {
+ foundError = javaBooleanOr(foundError, checkForCaseBlockNotTerminated((member as SwitchCase)));
+ }
+ }
+ return foundError;
+ }
+
+ /**
* This verifies that the passed switch statement does not have a case expression with the
* operator '==' overridden.
* @param node the switch statement to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
*/
bool checkForCaseExpressionTypeImplementsEquals(SwitchStatement node) {
Expression expression2 = node.expression;
- Type2 type = expression2.staticType;
+ Type2 type = getStaticType(expression2);
if (type != null && type != _typeProvider.intType && type != _typeProvider.stringType) {
Element element2 = type.element;
if (element2 is ClassElement) {
ClassElement classElement = element2 as ClassElement;
MethodElement method = classElement.lookUpMethod("==", _currentLibrary);
if (method != null && method.enclosingElement.type != _typeProvider.objectType) {
- _errorReporter.reportError(CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, expression2, [element2.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, expression2, [element2.displayName]);
return true;
}
}
}
return false;
}
+
/**
* This verifies that the passed method declaration is abstract only if the enclosing class is
* also abstract.
@@ -7846,39 +10566,183 @@
bool checkForConcreteClassWithAbstractMember(MethodDeclaration node) {
if (node.isAbstract() && _enclosingClass != null && !_enclosingClass.isAbstract()) {
SimpleIdentifier methodName = node.name;
- _errorReporter.reportError(StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER, methodName, [methodName.name, _enclosingClass.name]);
+ _errorReporter.reportError2(StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER, methodName, [methodName.name, _enclosingClass.displayName]);
return true;
}
return false;
}
+
+ /**
+ * This verifies all possible conflicts of the constructor name with other constructors and
+ * members of the same class.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#DUPLICATE_CONSTRUCTOR_DEFAULT
+ * @see CompileTimeErrorCode#DUPLICATE_CONSTRUCTOR_NAME
+ * @see CompileTimeErrorCode#CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD
+ * @see CompileTimeErrorCode#CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD
+ */
bool checkForConflictingConstructorNameAndMember(ConstructorDeclaration node) {
ConstructorElement constructorElement = node.element;
SimpleIdentifier constructorName = node.name;
+ String name2 = constructorElement.name;
+ ClassElement classElement = constructorElement.enclosingElement;
+ List<ConstructorElement> constructors2 = classElement.constructors;
+ for (ConstructorElement otherConstructor in constructors2) {
+ if (identical(otherConstructor, constructorElement)) {
+ continue;
+ }
+ if (name2 == otherConstructor.name) {
+ if (name2 == null || name2.length == 0) {
+ _errorReporter.reportError2(CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT, node, []);
+ } else {
+ _errorReporter.reportError2(CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME, node, [name2]);
+ }
+ return true;
+ }
+ }
if (constructorName != null && constructorElement != null && !constructorName.isSynthetic()) {
- String name2 = constructorName.name;
- ClassElement classElement = constructorElement.enclosingElement;
List<FieldElement> fields2 = classElement.fields;
for (FieldElement field in fields2) {
if (field.name == name2) {
- _errorReporter.reportError(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, node, [name2]);
+ _errorReporter.reportError2(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, node, [name2]);
return true;
}
}
List<MethodElement> methods2 = classElement.methods;
for (MethodElement method in methods2) {
if (method.name == name2) {
- _errorReporter.reportError(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, node, [name2]);
+ _errorReporter.reportError2(CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, node, [name2]);
return true;
}
}
}
return false;
}
+
/**
- * This verifies that the passed constructor declaration is not 'const' if it has a non-final
+ * This verifies that the superclass of the enclosing class does not declare accessible static
+ * member with the same name as the passed instance getter/setter method declaration.
+ * @param node the method declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER
+ * @see StaticWarningCode#CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER
+ */
+ bool checkForConflictingInstanceGetterAndSuperclassMember(MethodDeclaration node) {
+ if (node.isStatic()) {
+ return false;
+ }
+ SimpleIdentifier nameNode = node.name;
+ if (nameNode == null) {
+ return false;
+ }
+ String name2 = nameNode.name;
+ if (_enclosingClass == null) {
+ return false;
+ }
+ InterfaceType enclosingType = _enclosingClass.type;
+ ExecutableElement superElement;
+ superElement = enclosingType.lookUpGetterInSuperclass(name2, _currentLibrary);
+ if (superElement == null) {
+ superElement = enclosingType.lookUpSetterInSuperclass(name2, _currentLibrary);
+ }
+ if (superElement == null) {
+ superElement = enclosingType.lookUpMethodInSuperclass(name2, _currentLibrary);
+ }
+ if (superElement == null) {
+ return false;
+ }
+ if (!superElement.isStatic()) {
+ return false;
+ }
+ ClassElement superElementClass = superElement.enclosingElement as ClassElement;
+ InterfaceType superElementType = superElementClass.type;
+ if (node.isGetter()) {
+ _errorReporter.reportError2(StaticWarningCode.CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER, nameNode, [superElementType.displayName]);
+ } else {
+ _errorReporter.reportError2(StaticWarningCode.CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER, nameNode, [superElementType.displayName]);
+ }
+ return true;
+ }
+
+ /**
+ * This verifies that the enclosing class does not have an instance member with the same name as
+ * the passed static getter method declaration.
+ * @param node the method declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER
+ */
+ bool checkForConflictingStaticGetterAndInstanceSetter(MethodDeclaration node) {
+ if (!node.isStatic()) {
+ return false;
+ }
+ SimpleIdentifier nameNode = node.name;
+ if (nameNode == null) {
+ return false;
+ }
+ String name2 = nameNode.name;
+ if (_enclosingClass == null) {
+ return false;
+ }
+ InterfaceType enclosingType = _enclosingClass.type;
+ ExecutableElement setter = enclosingType.lookUpSetter(name2, _currentLibrary);
+ if (setter == null) {
+ return false;
+ }
+ if (setter.isStatic()) {
+ return false;
+ }
+ ClassElement setterClass = setter.enclosingElement as ClassElement;
+ InterfaceType setterType = setterClass.type;
+ _errorReporter.reportError2(StaticWarningCode.CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER, nameNode, [setterType.displayName]);
+ return true;
+ }
+
+ /**
+ * This verifies that the enclosing class does not have an instance member with the same name as
+ * the passed static getter method declaration.
+ * @param node the method declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER
+ */
+ bool checkForConflictingStaticSetterAndInstanceMember(MethodDeclaration node) {
+ if (!node.isStatic()) {
+ return false;
+ }
+ SimpleIdentifier nameNode = node.name;
+ if (nameNode == null) {
+ return false;
+ }
+ String name2 = nameNode.name;
+ if (_enclosingClass == null) {
+ return false;
+ }
+ InterfaceType enclosingType = _enclosingClass.type;
+ ExecutableElement member;
+ member = enclosingType.lookUpMethod(name2, _currentLibrary);
+ if (member == null) {
+ member = enclosingType.lookUpGetter(name2, _currentLibrary);
+ }
+ if (member == null) {
+ member = enclosingType.lookUpSetter(name2, _currentLibrary);
+ }
+ if (member == null) {
+ return false;
+ }
+ if (member.isStatic()) {
+ return false;
+ }
+ ClassElement memberClass = member.enclosingElement as ClassElement;
+ InterfaceType memberType = memberClass.type;
+ _errorReporter.reportError2(StaticWarningCode.CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER, nameNode, [memberType.displayName]);
+ return true;
+ }
+
+ /**
+ * This verifies that the passed constructor declaration is 'const' then there are no non-final
* instance variable.
- * @param node the instance creation expression to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD
*/
bool checkForConstConstructorWithNonFinalField(ConstructorDeclaration node) {
@@ -7886,52 +10750,50 @@
return false;
}
ConstructorElement constructorElement = node.element;
- if (constructorElement != null) {
- ClassElement classElement = constructorElement.enclosingElement;
- List<FieldElement> elements = classElement.fields;
- for (FieldElement field in elements) {
- if (!field.isFinal() && !field.isConst() && !field.isStatic() && !field.isSynthetic()) {
- _errorReporter.reportError(CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD, node, []);
- return true;
- }
- }
+ ClassElement classElement = constructorElement.enclosingElement;
+ if (!classElement.hasNonFinalField()) {
+ return false;
}
- return false;
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD, node, []);
+ return true;
}
+
/**
* This verifies that the passed throw expression is not enclosed in a 'const' constructor
* declaration.
* @param node the throw expression expression to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
- * @see CompileTimeErrorCode#CONST_EVAL_THROWS_EXCEPTION
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#CONST_CONSTRUCTOR_THROWS_EXCEPTION
*/
bool checkForConstEvalThrowsException(ThrowExpression node) {
if (_isEnclosingConstructorConst) {
- _errorReporter.reportError(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_CONSTRUCTOR_THROWS_EXCEPTION, node, []);
return true;
}
return false;
}
+
/**
* This verifies that the passed normal formal parameter is not 'const'.
* @param node the normal formal parameter to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#CONST_FORMAL_PARAMETER
*/
bool checkForConstFormalParameter(NormalFormalParameter node) {
if (node.isConst()) {
- _errorReporter.reportError(CompileTimeErrorCode.CONST_FORMAL_PARAMETER, node, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_FORMAL_PARAMETER, node, []);
return true;
}
return false;
}
+
/**
* This verifies that the passed instance creation expression is not being invoked on an abstract
* class.
* @param node the instance creation expression to evaluate
* @param typeName the {@link TypeName} of the {@link ConstructorName} from the{@link InstanceCreationExpression}, this is the AST node that the error is attached to
* @param type the type being constructed with this {@link InstanceCreationExpression}
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see StaticWarningCode#CONST_WITH_ABSTRACT_CLASS
* @see StaticWarningCode#NEW_WITH_ABSTRACT_CLASS
*/
@@ -7940,34 +10802,116 @@
ConstructorElement element2 = node.element;
if (element2 != null && !element2.isFactory()) {
if (identical(((node.keyword as sc.KeywordToken)).keyword, sc.Keyword.CONST)) {
- _errorReporter.reportError(StaticWarningCode.CONST_WITH_ABSTRACT_CLASS, typeName, []);
+ _errorReporter.reportError2(StaticWarningCode.CONST_WITH_ABSTRACT_CLASS, typeName, []);
} else {
- _errorReporter.reportError(StaticWarningCode.NEW_WITH_ABSTRACT_CLASS, typeName, []);
+ _errorReporter.reportError2(StaticWarningCode.NEW_WITH_ABSTRACT_CLASS, typeName, []);
}
return true;
}
}
return false;
}
+
/**
- * This verifies that if the passed instance creation expression is 'const', then it is not being
- * invoked on a constructor that is not 'const'.
+ * This verifies that the passed 'const' instance creation expression is not being invoked on a
+ * constructor that is not 'const'.
+ * <p>
+ * This method assumes that the instance creation was tested to be 'const' before being called.
* @param node the instance creation expression to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#CONST_WITH_NON_CONST
*/
bool checkForConstWithNonConst(InstanceCreationExpression node) {
ConstructorElement constructorElement = node.element;
- if (node.isConst() && constructorElement != null && !constructorElement.isConst()) {
- _errorReporter.reportError(CompileTimeErrorCode.CONST_WITH_NON_CONST, node, []);
+ if (constructorElement != null && !constructorElement.isConst()) {
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_NON_CONST, node, []);
return true;
}
return false;
}
+
/**
+ * This verifies that the passed 'const' instance creation expression does not reference any type
+ * parameters.
+ * <p>
+ * This method assumes that the instance creation was tested to be 'const' before being called.
+ * @param node the instance creation expression to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#CONST_WITH_TYPE_PARAMETERS
+ */
+ bool checkForConstWithTypeParameters(InstanceCreationExpression node) {
+ ConstructorName constructorName2 = node.constructorName;
+ if (constructorName2 == null) {
+ return false;
+ }
+ TypeName typeName = constructorName2.type;
+ return checkForConstWithTypeParameters2(typeName);
+ }
+
+ /**
+ * This verifies that the passed type name does not reference any type parameters.
+ * @param typeName the type name to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#CONST_WITH_TYPE_PARAMETERS
+ */
+ bool checkForConstWithTypeParameters2(TypeName typeName) {
+ if (typeName == null) {
+ return false;
+ }
+ Identifier name2 = typeName.name;
+ if (name2 == null) {
+ return false;
+ }
+ if (name2.element is TypeVariableElement) {
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS, name2, []);
+ }
+ TypeArgumentList typeArguments2 = typeName.typeArguments;
+ if (typeArguments2 != null) {
+ bool hasError = false;
+ for (TypeName argument in typeArguments2.arguments) {
+ hasError = javaBooleanOr(hasError, checkForConstWithTypeParameters2(argument));
+ }
+ return hasError;
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that if the passed 'const' instance creation expression is being invoked on the
+ * resolved constructor.
+ * <p>
+ * This method assumes that the instance creation was tested to be 'const' before being called.
+ * @param node the instance creation expression to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#CONST_WITH_UNDEFINED_CONSTRUCTOR
+ * @see CompileTimeErrorCode#CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT
+ */
+ bool checkForConstWithUndefinedConstructor(InstanceCreationExpression node) {
+ if (node.element != null) {
+ return false;
+ }
+ ConstructorName constructorName2 = node.constructorName;
+ if (constructorName2 == null) {
+ return false;
+ }
+ TypeName type2 = constructorName2.type;
+ if (type2 == null) {
+ return false;
+ }
+ Identifier className = type2.name;
+ SimpleIdentifier name2 = constructorName2.name;
+ if (name2 != null) {
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR, name2, [className, name2]);
+ } else {
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT, constructorName2, [className]);
+ }
+ return true;
+ }
+
+ /**
* This verifies that there are no default parameters in the passed function type alias.
* @param node the function type alias to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS
*/
bool checkForDefaultValueInFunctionTypeAlias(FunctionTypeAlias node) {
@@ -7978,25 +10922,90 @@
if (formalParameter is DefaultFormalParameter) {
DefaultFormalParameter defaultFormalParameter = formalParameter as DefaultFormalParameter;
if (defaultFormalParameter.defaultValue != null) {
- _errorReporter.reportError(CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, node, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, node, []);
result = true;
}
}
}
return result;
}
+
/**
+ * This verifies the passed import has unique name among other exported libraries.
+ * @param node the export directive to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#EXPORT_DUPLICATED_LIBRARY_NAME
+ */
+ bool checkForExportDuplicateLibraryName(ExportDirective node) {
+ Element nodeElement = node.element;
+ if (nodeElement is! ExportElement) {
+ return false;
+ }
+ ExportElement nodeExportElement = nodeElement as ExportElement;
+ LibraryElement nodeLibrary = nodeExportElement.exportedLibrary;
+ if (nodeLibrary == null) {
+ return false;
+ }
+ String name2 = nodeLibrary.name;
+ LibraryElement prevLibrary = _nameToExportElement[name2];
+ if (prevLibrary != null) {
+ if (prevLibrary != nodeLibrary) {
+ _errorReporter.reportError2(StaticWarningCode.EXPORT_DUPLICATED_LIBRARY_NAME, node, [prevLibrary.definingCompilationUnit.displayName, nodeLibrary.definingCompilationUnit.displayName, name2]);
+ return true;
+ }
+ } else {
+ _nameToExportElement[name2] = nodeLibrary;
+ }
+ return false;
+ }
+
+ /**
+ * Check that if the visiting library is not system, then any passed library should not be SDK
+ * internal library.
+ * @param node the export directive to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#EXPORT_INTERNAL_LIBRARY
+ */
+ bool checkForExportInternalLibrary(ExportDirective node) {
+ if (_isInSystemLibrary) {
+ return false;
+ }
+ Element element2 = node.element;
+ if (element2 is! ExportElement) {
+ return false;
+ }
+ ExportElement exportElement = element2 as ExportElement;
+ DartSdk sdk = _currentLibrary.context.sourceFactory.dartSdk;
+ String uri2 = exportElement.uri;
+ SdkLibrary sdkLibrary = sdk.getSdkLibrary(uri2);
+ if (sdkLibrary == null) {
+ return false;
+ }
+ if (!sdkLibrary.isInternal()) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY, node, [node.uri]);
+ return true;
+ }
+
+ /**
* This verifies that the passed extends clause does not extend classes such as num or String.
* @param node the extends clause to test
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS
*/
- bool checkForExtendsDisallowedClass(ExtendsClause extendsClause) => checkForExtendsOrImplementsDisallowedClass(extendsClause.superclass, CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS);
+ bool checkForExtendsDisallowedClass(ExtendsClause extendsClause) {
+ if (extendsClause == null) {
+ return false;
+ }
+ return checkForExtendsOrImplementsDisallowedClass(extendsClause.superclass, CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS);
+ }
+
/**
* This verifies that the passed type name does not extend or implement classes such as 'num' or
* 'String'.
* @param node the type name to test
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see #checkForExtendsDisallowedClass(ExtendsClause)
* @see #checkForImplementsDisallowedClass(ImplementsClause)
* @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS
@@ -8019,29 +11028,76 @@
}
}
}
- _errorReporter.reportError(errorCode, typeName, [disallowedType.name]);
+ _errorReporter.reportError2(errorCode, typeName, [disallowedType.displayName]);
return true;
}
}
return false;
}
+
/**
+ * This verifies that the passed constructor field initializer has compatible field and
+ * initializer expression types.
+ * @param node the constructor field initializer to test
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE
+ * @see StaticWarningCode#FIELD_INITIALIZER_NOT_ASSIGNABLE
+ */
+ bool checkForFieldInitializerNotAssignable(ConstructorFieldInitializer node) {
+ Element fieldNameElement = node.fieldName.element;
+ if (fieldNameElement is! FieldElement) {
+ return false;
+ }
+ FieldElement fieldElement = fieldNameElement as FieldElement;
+ Type2 fieldType = fieldElement.type;
+ Expression expression2 = node.expression;
+ if (expression2 == null) {
+ return false;
+ }
+ Type2 staticType = getStaticType(expression2);
+ if (staticType == null) {
+ return false;
+ }
+ if (staticType.isAssignableTo(fieldType)) {
+ return false;
+ }
+ Type2 propagatedType = getPropagatedType(expression2);
+ if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) {
+ return false;
+ }
+ if (_isEnclosingConstructorConst) {
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression2, [(propagatedType == null ? staticType : propagatedType).displayName, fieldType.displayName]);
+ } else {
+ _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression2, [(propagatedType == null ? staticType : propagatedType).displayName, fieldType.displayName]);
+ }
+ return true;
+ }
+
+ /**
* This verifies that the passed field formal parameter is in a constructor declaration.
* @param node the field formal parameter to test
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
*/
- bool checkForFieldInitializerOutsideConstructor(FieldFormalParameter node) {
- ASTNode parent2 = node.parent;
- if (parent2 != null) {
- ASTNode grandparent = parent2.parent;
- if (grandparent != null && grandparent is! ConstructorDeclaration && grandparent.parent is! ConstructorDeclaration) {
- _errorReporter.reportError(CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, node, []);
+ bool checkForFieldInitializingFormalRedirectingConstructor(FieldFormalParameter node) {
+ ConstructorDeclaration constructor = node.getAncestor(ConstructorDeclaration);
+ if (constructor == null) {
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, node, []);
+ return true;
+ }
+ if (constructor.factoryKeyword != null) {
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_FACTORY_CONSTRUCTOR, node, []);
+ return true;
+ }
+ for (ConstructorInitializer initializer in constructor.initializers) {
+ if (initializer is RedirectingConstructorInvocation) {
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR, node, []);
return true;
}
}
return false;
}
+
/**
* This verifies that final fields that are declared, without any constructors in the enclosing
* class, are initialized. Cases in which there is at least one constructor are handled at the end
@@ -8066,6 +11122,7 @@
}
return foundError;
}
+
/**
* This verifies that the passed variable declaration list has only initialized variables if the
* list is final or const. This method is called by{@link #checkForFinalNotInitialized(ClassDeclaration)},{@link #visitTopLevelVariableDeclaration(TopLevelVariableDeclaration)} and{@link #visitVariableDeclarationStatement(VariableDeclarationStatement)}.
@@ -8079,31 +11136,142 @@
NodeList<VariableDeclaration> variables2 = node.variables;
for (VariableDeclaration variable in variables2) {
if (variable.initializer == null) {
- _errorReporter.reportError(CompileTimeErrorCode.FINAL_NOT_INITIALIZED, variable, [variable.name.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.FINAL_NOT_INITIALIZED, variable, [variable.name.name]);
foundError = true;
}
}
}
return foundError;
}
+
/**
* This verifies that the passed implements clause does not implement classes such as 'num' or
* 'String'.
* @param node the implements clause to test
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS
*/
bool checkForImplementsDisallowedClass(ImplementsClause implementsClause) {
+ if (implementsClause == null) {
+ return false;
+ }
bool foundError = false;
for (TypeName type in implementsClause.interfaces) {
foundError = javaBooleanOr(foundError, checkForExtendsOrImplementsDisallowedClass(type, CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS));
}
return foundError;
}
+
/**
+ * This verifies that if the passed identifier is part of constructor initializer, then it does
+ * not reference implicitly 'this' expression.
+ * @param node the simple identifier to test
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#IMPLICIT_THIS_REFERENCE_IN_INITIALIZER
+ */
+ bool checkForImplicitThisReferenceInInitializer(SimpleIdentifier node) {
+ if (!_isInConstructorInitializer) {
+ return false;
+ }
+ Element element2 = node.element;
+ if (!(element2 is MethodElement || element2 is PropertyAccessorElement)) {
+ return false;
+ }
+ ExecutableElement executableElement = element2 as ExecutableElement;
+ if (executableElement.isStatic()) {
+ return false;
+ }
+ Element enclosingElement2 = element2.enclosingElement;
+ if (enclosingElement2 is! ClassElement) {
+ return false;
+ }
+ ASTNode parent2 = node.parent;
+ if (parent2 is MethodInvocation) {
+ MethodInvocation invocation = parent2 as MethodInvocation;
+ if (identical(invocation.methodName, node) && invocation.realTarget != null) {
+ return false;
+ }
+ }
+ {
+ if (parent2 is PropertyAccess) {
+ PropertyAccess access = parent2 as PropertyAccess;
+ if (identical(access.propertyName, node) && access.realTarget != null) {
+ return false;
+ }
+ }
+ if (parent2 is PrefixedIdentifier) {
+ PrefixedIdentifier prefixed = parent2 as PrefixedIdentifier;
+ if (identical(prefixed.identifier, node)) {
+ return false;
+ }
+ }
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER, node, []);
+ return true;
+ }
+
+ /**
+ * This verifies the passed import has unique name among other imported libraries.
+ * @param node the import directive to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#IMPORT_DUPLICATED_LIBRARY_NAME
+ */
+ bool checkForImportDuplicateLibraryName(ImportDirective node) {
+ Element nodeElement = node.element;
+ if (nodeElement is! ImportElement) {
+ return false;
+ }
+ ImportElement nodeImportElement = nodeElement as ImportElement;
+ LibraryElement nodeLibrary = nodeImportElement.importedLibrary;
+ if (nodeLibrary == null) {
+ return false;
+ }
+ String name2 = nodeLibrary.name;
+ LibraryElement prevLibrary = _nameToImportElement[name2];
+ if (prevLibrary != null) {
+ if (prevLibrary != nodeLibrary) {
+ _errorReporter.reportError2(StaticWarningCode.IMPORT_DUPLICATED_LIBRARY_NAME, node, [prevLibrary.definingCompilationUnit.displayName, nodeLibrary.definingCompilationUnit.displayName, name2]);
+ return true;
+ }
+ } else {
+ _nameToImportElement[name2] = nodeLibrary;
+ }
+ return false;
+ }
+
+ /**
+ * Check that if the visiting library is not system, then any passed library should not be SDK
+ * internal library.
+ * @param node the import directive to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#IMPORT_INTERNAL_LIBRARY
+ */
+ bool checkForImportInternalLibrary(ImportDirective node) {
+ if (_isInSystemLibrary) {
+ return false;
+ }
+ Element element2 = node.element;
+ if (element2 is! ImportElement) {
+ return false;
+ }
+ ImportElement importElement = element2 as ImportElement;
+ DartSdk sdk = _currentLibrary.context.sourceFactory.dartSdk;
+ String uri2 = importElement.uri;
+ SdkLibrary sdkLibrary = sdk.getSdkLibrary(uri2);
+ if (sdkLibrary == null) {
+ return false;
+ }
+ if (!sdkLibrary.isInternal()) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY, node, [node.uri]);
+ return true;
+ }
+
+ /**
* This verifies that the passed switch statement case expressions all have the same type.
* @param node the switch statement to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#INCONSISTENT_CASE_EXPRESSION_TYPES
*/
bool checkForInconsistentCaseExpressionTypes(SwitchStatement node) {
@@ -8115,11 +11283,11 @@
SwitchCase switchCase = switchMember as SwitchCase;
Expression expression2 = switchCase.expression;
if (firstType == null) {
- firstType = expression2.staticType;
+ firstType = getBestType(expression2);
} else {
- Type2 nType = expression2.staticType;
+ Type2 nType = getBestType(expression2);
if (firstType != nType) {
- _errorReporter.reportError(CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, expression2, [expression2.toSource(), firstType.name]);
+ _errorReporter.reportError2(CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, expression2, [expression2.toSource(), firstType.displayName]);
foundError = true;
}
}
@@ -8127,39 +11295,115 @@
}
return foundError;
}
+
/**
- * This verifies that the passed assignment expression represents a valid assignment.
- * @param node the assignment expression to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * For each class declaration, this method is called which verifies that all inherited members are
+ * inherited consistently.
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticTypeWarningCode#INCONSISTENT_METHOD_INHERITANCE
+ */
+ bool checkForInconsistentMethodInheritance() {
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass);
+ Set<AnalysisError> errors = _inheritanceManager.getErrors(_enclosingClass);
+ if (errors == null || errors.isEmpty) {
+ return false;
+ }
+ for (AnalysisError error in errors) {
+ _errorReporter.reportError(error);
+ }
+ return true;
+ }
+
+ /**
+ * Given an assignment using a compound assignment operator, this verifies that the given
+ * assignment is valid.
+ * @param node the assignment expression being tested
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see StaticTypeWarningCode#INVALID_ASSIGNMENT
*/
bool checkForInvalidAssignment(AssignmentExpression node) {
Expression lhs = node.leftHandSide;
- Expression rhs = node.rightHandSide;
+ if (lhs == null) {
+ return false;
+ }
VariableElement leftElement = getVariableElement(lhs);
- Type2 leftType = (leftElement == null) ? getType(lhs) : leftElement.type;
- Type2 rightType = getType(rhs);
+ Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.type;
+ MethodElement invokedMethod = node.element;
+ if (invokedMethod == null) {
+ return false;
+ }
+ Type2 rightType = invokedMethod.type.returnType;
+ if (leftType == null || rightType == null) {
+ return false;
+ }
if (!rightType.isAssignableTo(leftType)) {
- _errorReporter.reportError(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType.name, leftType.name]);
+ _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, node.rightHandSide, [rightType.displayName, leftType.displayName]);
return true;
}
return false;
}
+
/**
+ * This verifies that the passed left hand side and right hand side represent a valid assignment.
+ * @param lhs the left hand side expression
+ * @param rhs the right hand side expression
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticTypeWarningCode#INVALID_ASSIGNMENT
+ */
+ bool checkForInvalidAssignment2(Expression lhs, Expression rhs) {
+ if (lhs == null || rhs == null) {
+ return false;
+ }
+ VariableElement leftElement = getVariableElement(lhs);
+ Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.type;
+ Type2 staticRightType = getStaticType(rhs);
+ bool isStaticAssignable = staticRightType.isAssignableTo(leftType);
+ Type2 propagatedRightType = getPropagatedType(rhs);
+ if (propagatedRightType == null) {
+ if (!isStaticAssignable) {
+ _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
+ return true;
+ }
+ } else {
+ bool isPropagatedAssignable = propagatedRightType.isAssignableTo(leftType);
+ if (!isStaticAssignable && !isPropagatedAssignable) {
+ _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that the usage of the passed 'this' is valid.
+ * @param node the 'this' expression to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#INVALID_REFERENCE_TO_THIS
+ */
+ bool checkForInvalidReferenceToThis(ThisExpression node) {
+ if (!isThisInValidContext(node)) {
+ _errorReporter.reportError2(CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, node, []);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Checks to ensure that first type argument to a map literal must be the 'String' type.
* @param arguments a non-{@code null}, non-empty {@link TypeName} node list from the respective{@link MapLiteral}
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see CompileTimeErrorCode#INVALID_TYPE_ARGUMENT_FOR_KEY
*/
bool checkForInvalidTypeArgumentForKey(NodeList<TypeName> arguments) {
TypeName firstArgument = arguments[0];
Type2 firstArgumentType = firstArgument.type;
if (firstArgumentType != null && firstArgumentType != _typeProvider.stringType) {
- _errorReporter.reportError(CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_FOR_KEY, firstArgument, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_FOR_KEY, firstArgument, []);
return true;
}
return false;
}
+
/**
* Checks to ensure that the passed {@link ListLiteral} or {@link MapLiteral} does not have a type
* parameter as a type argument.
@@ -8171,64 +11415,377 @@
bool foundError = false;
for (TypeName typeName in arguments) {
if (typeName.type is TypeVariableType) {
- _errorReporter.reportError(errorCode, typeName, [typeName.name]);
+ _errorReporter.reportError2(errorCode, typeName, [typeName.name]);
foundError = true;
}
}
return foundError;
}
+
/**
+ * This verifies that the {@link #enclosingClass} does not define members with the same name as
+ * the enclosing class.
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MEMBER_WITH_CLASS_NAME
+ */
+ bool checkForMemberWithClassName() {
+ if (_enclosingClass == null) {
+ return false;
+ }
+ String className = _enclosingClass.name;
+ if (className == null) {
+ return false;
+ }
+ bool problemReported = false;
+ for (PropertyAccessorElement accessor in _enclosingClass.accessors) {
+ if (className == accessor.name) {
+ _errorReporter.reportError3(CompileTimeErrorCode.MEMBER_WITH_CLASS_NAME, accessor.nameOffset, className.length, []);
+ problemReported = true;
+ }
+ }
+ return problemReported;
+ }
+
+ /**
+ * Check to make sure that all similarly typed accessors are of the same type (including inherited
+ * accessors).
+ * @param node The accessor currently being visited.
+ */
+ void checkForMismatchedAccessorTypes(Declaration accessorDeclaration, String accessorTextName) {
+ PropertyAccessorElement counterpartAccessor = null;
+ ExecutableElement accessorElement = accessorDeclaration.element as ExecutableElement;
+ if (accessorElement is! PropertyAccessorElement) {
+ return;
+ }
+ PropertyAccessorElement propertyAccessorElement = accessorElement as PropertyAccessorElement;
+ counterpartAccessor = propertyAccessorElement.correspondingSetter;
+ if (counterpartAccessor == null) {
+ return;
+ }
+ Type2 getterType = null;
+ Type2 setterType = null;
+ if (propertyAccessorElement.isGetter()) {
+ getterType = getGetterType(propertyAccessorElement);
+ setterType = getSetterType(counterpartAccessor);
+ } else if (propertyAccessorElement.isSetter()) {
+ setterType = getSetterType(propertyAccessorElement);
+ counterpartAccessor = propertyAccessorElement.correspondingGetter;
+ getterType = getGetterType(counterpartAccessor);
+ }
+ if (setterType != null && getterType != null && !getterType.isAssignableTo(setterType)) {
+ _errorReporter.reportError2(StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES, accessorDeclaration, [accessorTextName, setterType.displayName, getterType.displayName]);
+ }
+ }
+
+ /**
+ * This verifies that the passed mixin does not have an explicitly declared constructor.
+ * @param mixinName the node to report problem on
+ * @param mixinElement the mixing to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MIXIN_DECLARES_CONSTRUCTOR
+ */
+ bool checkForMixinDeclaresConstructor(TypeName mixinName, ClassElement mixinElement) {
+ for (ConstructorElement constructor in mixinElement.constructors) {
+ if (!constructor.isSynthetic() && !constructor.isFactory()) {
+ _errorReporter.reportError2(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, mixinName, [mixinElement.name]);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that the passed mixin has the 'Object' superclass.
+ * @param mixinName the node to report problem on
+ * @param mixinElement the mixing to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MIXIN_INHERITS_FROM_NOT_OBJECT
+ */
+ bool checkForMixinInheritsNotFromObject(TypeName mixinName, ClassElement mixinElement) {
+ InterfaceType mixinSupertype = mixinElement.supertype;
+ if (mixinSupertype != null) {
+ if (!mixinSupertype.isObject() || !mixinElement.isTypedef() && mixinElement.mixins.length != 0) {
+ _errorReporter.reportError2(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, mixinName, [mixinElement.name]);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that the passed mixin does not reference 'super'.
+ * @param mixinName the node to report problem on
+ * @param mixinElement the mixing to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MIXIN_REFERENCES_SUPER
+ */
+ bool checkForMixinReferencesSuper(TypeName mixinName, ClassElement mixinElement) {
+ if (mixinElement.hasReferenceToSuper()) {
+ _errorReporter.reportError2(CompileTimeErrorCode.MIXIN_REFERENCES_SUPER, mixinName, [mixinElement.name]);
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that the passed constructor has at most one 'super' initializer.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MULTIPLE_SUPER_INITIALIZERS
+ */
+ bool checkForMultipleSuperInitializers(ConstructorDeclaration node) {
+ int numSuperInitializers = 0;
+ for (ConstructorInitializer initializer in node.initializers) {
+ if (initializer is SuperConstructorInvocation) {
+ numSuperInitializers++;
+ if (numSuperInitializers > 1) {
+ _errorReporter.reportError2(CompileTimeErrorCode.MULTIPLE_SUPER_INITIALIZERS, initializer, []);
+ }
+ }
+ }
+ return numSuperInitializers > 0;
+ }
+
+ /**
* Checks to ensure that native function bodies can only in SDK code.
* @param node the native function body to test
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see ParserErrorCode#NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE
*/
bool checkForNativeFunctionBodyInNonSDKCode(NativeFunctionBody node) {
if (!_isInSystemLibrary) {
- _errorReporter.reportError(ParserErrorCode.NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE, node, []);
+ _errorReporter.reportError2(ParserErrorCode.NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE, node, []);
return true;
}
return false;
}
+
/**
+ * This verifies that the passed 'new' instance creation expression invokes existing constructor.
+ * <p>
+ * This method assumes that the instance creation was tested to be 'new' before being called.
+ * @param node the instance creation expression to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#NEW_WITH_UNDEFINED_CONSTRUCTOR
+ */
+ bool checkForNewWithUndefinedConstructor(InstanceCreationExpression node) {
+ if (node.element != null) {
+ return false;
+ }
+ ConstructorName constructorName2 = node.constructorName;
+ if (constructorName2 == null) {
+ return false;
+ }
+ TypeName type2 = constructorName2.type;
+ if (type2 == null) {
+ return false;
+ }
+ Identifier className = type2.name;
+ SimpleIdentifier name2 = constructorName2.name;
+ if (name2 != null) {
+ _errorReporter.reportError2(StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, name2, [className, name2]);
+ } else {
+ _errorReporter.reportError2(StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT, constructorName2, [className]);
+ }
+ return true;
+ }
+
+ /**
+ * This checks that passed class declaration overrides all members required by its superclasses
+ * and interfaces.
+ * @param node the {@link ClassDeclaration} to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE
+ * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO
+ * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE
+ * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR
+ * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS
+ */
+ bool checkForNonAbstractClassInheritsAbstractMember(ClassDeclaration node) {
+ if (_enclosingClass.isAbstract()) {
+ return false;
+ }
+ Set<ExecutableElement> missingOverrides = new Set<ExecutableElement>();
+ Set<String> methodsInEnclosingClass = new Set<String>();
+ Set<String> accessorsInEnclosingClass = new Set<String>();
+ List<MethodElement> methods2 = _enclosingClass.methods;
+ for (MethodElement method in methods2) {
+ javaSetAdd(methodsInEnclosingClass, method.name);
+ }
+ List<PropertyAccessorElement> accessors2 = _enclosingClass.accessors;
+ for (PropertyAccessorElement accessor in accessors2) {
+ javaSetAdd(accessorsInEnclosingClass, accessor.name);
+ }
+ Map<String, ExecutableElement> membersInheritedFromSuperclasses = _inheritanceManager.getMapOfMembersInheritedFromClasses(_enclosingClass);
+ for (MapEntry<String, ExecutableElement> entry in getMapEntrySet(membersInheritedFromSuperclasses)) {
+ ExecutableElement executableElt = entry.getValue();
+ if (executableElt is MethodElement) {
+ MethodElement methodElt = executableElt as MethodElement;
+ if (methodElt.isAbstract()) {
+ String methodName = entry.getKey();
+ if (!methodsInEnclosingClass.contains(methodName)) {
+ javaSetAdd(missingOverrides, executableElt);
+ }
+ }
+ } else if (executableElt is PropertyAccessorElement) {
+ PropertyAccessorElement propertyAccessorElt = executableElt as PropertyAccessorElement;
+ if (propertyAccessorElt.isAbstract()) {
+ String accessorName = entry.getKey();
+ if (!accessorsInEnclosingClass.contains(accessorName)) {
+ javaSetAdd(missingOverrides, executableElt);
+ }
+ }
+ }
+ }
+ Map<String, ExecutableElement> membersInheritedFromInterfaces = _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass);
+ for (MapEntry<String, ExecutableElement> entry in getMapEntrySet(membersInheritedFromInterfaces)) {
+ ExecutableElement executableElt = entry.getValue();
+ ExecutableElement elt = membersInheritedFromSuperclasses[executableElt.name];
+ if (elt != null) {
+ if (elt is MethodElement && !((elt as MethodElement)).isAbstract()) {
+ continue;
+ } else if (elt is PropertyAccessorElement && !((elt as PropertyAccessorElement)).isAbstract()) {
+ continue;
+ }
+ }
+ if (executableElt is MethodElement) {
+ String methodName = entry.getKey();
+ if (!methodsInEnclosingClass.contains(methodName)) {
+ javaSetAdd(missingOverrides, executableElt);
+ }
+ } else if (executableElt is PropertyAccessorElement) {
+ String accessorName = entry.getKey();
+ if (!accessorsInEnclosingClass.contains(accessorName)) {
+ javaSetAdd(missingOverrides, executableElt);
+ }
+ }
+ }
+ int missingOverridesSize = missingOverrides.length;
+ if (missingOverridesSize == 0) {
+ return false;
+ }
+ List<ExecutableElement> missingOverridesArray = new List.from(missingOverrides);
+ if (missingOverridesSize == 1) {
+ _errorReporter.reportError2(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE, node.name, [missingOverridesArray[0].enclosingElement.displayName, missingOverridesArray[0].displayName]);
+ } else if (missingOverridesSize == 2) {
+ _errorReporter.reportError2(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO, node.name, [missingOverridesArray[0].enclosingElement.displayName, missingOverridesArray[0].displayName, missingOverridesArray[1].enclosingElement.displayName, missingOverridesArray[1].displayName]);
+ } else if (missingOverridesSize == 3) {
+ _errorReporter.reportError2(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE, node.name, [missingOverridesArray[0].enclosingElement.displayName, missingOverridesArray[0].displayName, missingOverridesArray[1].enclosingElement.displayName, missingOverridesArray[1].displayName, missingOverridesArray[2].enclosingElement.displayName, missingOverridesArray[2].displayName]);
+ } else if (missingOverridesSize == 4) {
+ _errorReporter.reportError2(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR, node.name, [missingOverridesArray[0].enclosingElement.displayName, missingOverridesArray[0].displayName, missingOverridesArray[1].enclosingElement.displayName, missingOverridesArray[1].displayName, missingOverridesArray[2].enclosingElement.displayName, missingOverridesArray[2].displayName, missingOverridesArray[3].enclosingElement.displayName, missingOverridesArray[3].displayName]);
+ } else {
+ _errorReporter.reportError2(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS, node.name, [missingOverridesArray[0].enclosingElement.displayName, missingOverridesArray[0].displayName, missingOverridesArray[1].enclosingElement.displayName, missingOverridesArray[1].displayName, missingOverridesArray[2].enclosingElement.displayName, missingOverridesArray[2].displayName, missingOverridesArray[3].enclosingElement.displayName, missingOverridesArray[3].displayName, missingOverridesArray.length - 4]);
+ }
+ return true;
+ }
+
+ /**
* Checks to ensure that the expressions that need to be of type bool, are. Otherwise an error is
* reported on the expression.
* @param condition the conditional expression to test
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see StaticTypeWarningCode#NON_BOOL_CONDITION
*/
bool checkForNonBoolCondition(Expression condition) {
- Type2 conditionType = getType(condition);
+ Type2 conditionType = getStaticType(condition);
if (conditionType != null && !conditionType.isAssignableTo(_typeProvider.boolType)) {
- _errorReporter.reportError(StaticTypeWarningCode.NON_BOOL_CONDITION, condition, []);
+ _errorReporter.reportError2(StaticTypeWarningCode.NON_BOOL_CONDITION, condition, []);
return true;
}
return false;
}
+
/**
* This verifies that the passed assert statement has either a 'bool' or '() -> bool' input.
* @param node the assert statement to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see StaticTypeWarningCode#NON_BOOL_EXPRESSION
*/
bool checkForNonBoolExpression(AssertStatement node) {
Expression expression = node.condition;
- Type2 type = getType(expression);
+ Type2 type = getStaticType(expression);
if (type is InterfaceType) {
if (!type.isAssignableTo(_typeProvider.boolType)) {
- _errorReporter.reportError(StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression, []);
+ _errorReporter.reportError2(StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression, []);
return true;
}
} else if (type is FunctionType) {
FunctionType functionType = type as FunctionType;
if (functionType.typeArguments.length == 0 && !functionType.returnType.isAssignableTo(_typeProvider.boolType)) {
- _errorReporter.reportError(StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression, []);
+ _errorReporter.reportError2(StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression, []);
return true;
}
}
return false;
}
+
/**
+ * This verifies the passed map literal either:
+ * <ul>
+ * <li>has {@code const modifier}</li>
+ * <li>has explicit type arguments</li>
+ * <li>is not start of the statement</li>
+ * <ul>
+ * @param node the map literal to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#NON_CONST_MAP_AS_EXPRESSION_STATEMENT
+ */
+ bool checkForNonConstMapAsExpressionStatement(MapLiteral node) {
+ if (node.modifier != null) {
+ return false;
+ }
+ if (node.typeArguments != null) {
+ return false;
+ }
+ Statement statement = node.getAncestor(ExpressionStatement);
+ if (statement == null) {
+ return false;
+ }
+ if (statement.beginToken != node.beginToken) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION_STATEMENT, node, []);
+ return true;
+ }
+
+ /**
+ * This verifies the passed method declaration of operator {@code \[\]=}, has {@code void} return
+ * type.
+ * @param node the method declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#NON_VOID_RETURN_FOR_OPERATOR
+ */
+ bool checkForNonVoidReturnTypeForOperator(MethodDeclaration node) {
+ SimpleIdentifier name2 = node.name;
+ if (name2.name != "[]=") {
+ return false;
+ }
+ TypeName typeName = node.returnType;
+ if (typeName != null) {
+ Type2 type2 = typeName.type;
+ if (type2 != null && !type2.isVoid()) {
+ _errorReporter.reportError2(StaticWarningCode.NON_VOID_RETURN_FOR_OPERATOR, typeName, []);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies the passed setter has no return type or the {@code void} return type.
+ * @param typeName the type name to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#NON_VOID_RETURN_FOR_SETTER
+ */
+ bool checkForNonVoidReturnTypeForSetter(TypeName typeName) {
+ if (typeName != null) {
+ Type2 type2 = typeName.type;
+ if (type2 != null && !type2.isVoid()) {
+ _errorReporter.reportError2(StaticWarningCode.NON_VOID_RETURN_FOR_SETTER, typeName, []);
+ }
+ }
+ return false;
+ }
+
+ /**
* This verifies the passed operator-method declaration, does not have an optional parameter.
* <p>
* This method assumes that the method declaration was tested to be an operator declaration before
@@ -8246,12 +11803,13 @@
NodeList<FormalParameter> formalParameters = parameterList.parameters;
for (FormalParameter formalParameter in formalParameters) {
if (formalParameter.kind.isOptional()) {
- _errorReporter.reportError(CompileTimeErrorCode.OPTIONAL_PARAMETER_IN_OPERATOR, formalParameter, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.OPTIONAL_PARAMETER_IN_OPERATOR, formalParameter, []);
foundError = true;
}
}
return foundError;
}
+
/**
* This checks for named optional parameters that begin with '_'.
* @param node the default formal parameter to evaluate
@@ -8264,13 +11822,267 @@
NormalFormalParameter parameter2 = node.parameter;
SimpleIdentifier name = parameter2.identifier;
if (!name.isSynthetic() && name.name.startsWith("_")) {
- _errorReporter.reportError(CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER, node, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER, node, []);
return true;
}
}
return false;
}
+
/**
+ * This checks if the passed constructor declaration is the redirecting generative constructor and
+ * references itself directly or indirectly.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#RECURSIVE_CONSTRUCTOR_REDIRECT
+ */
+ bool checkForRecursiveConstructorRedirect(ConstructorDeclaration node) {
+ if (node.factoryKeyword != null) {
+ return false;
+ }
+ for (ConstructorInitializer initializer in node.initializers) {
+ if (initializer is RedirectingConstructorInvocation) {
+ ConstructorElement element2 = node.element;
+ if (!hasRedirectingFactoryConstructorCycle(element2)) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.RECURSIVE_CONSTRUCTOR_REDIRECT, initializer, []);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This checks if the passed constructor declaration has redirected constructor and references
+ * itself directly or indirectly.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#RECURSIVE_FACTORY_REDIRECT
+ */
+ bool checkForRecursiveFactoryRedirect(ConstructorDeclaration node) {
+ ConstructorName redirectedConstructorNode = node.redirectedConstructor;
+ if (redirectedConstructorNode == null) {
+ return false;
+ }
+ ConstructorElement element2 = node.element;
+ if (!hasRedirectingFactoryConstructorCycle(element2)) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.RECURSIVE_FACTORY_REDIRECT, redirectedConstructorNode, []);
+ return true;
+ }
+
+ /**
+ * This checks the class declaration is not a superinterface to itself.
+ * @param classElt the class element to test
+ * @param list a list containing the potentially cyclic implements path
+ * @return {@code true} if and only if an error code is generated on the passed element
+ * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE
+ * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS
+ * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS
+ */
+ bool checkForRecursiveInterfaceInheritance(ClassElement classElt, List<ClassElement> list) {
+ if (classElt == null) {
+ return false;
+ }
+ InterfaceType supertype2 = classElt.supertype;
+ list.add(classElt);
+ if (list.length != 1 && _enclosingClass == classElt) {
+ String enclosingClassName = _enclosingClass.displayName;
+ if (list.length > 2) {
+ String separator = ", ";
+ int listLength = list.length;
+ JavaStringBuilder builder = new JavaStringBuilder();
+ for (int i = 0; i < listLength; i++) {
+ builder.append(list[i].displayName);
+ if (i != listLength - 1) {
+ builder.append(separator);
+ }
+ }
+ _errorReporter.reportError3(CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE, _enclosingClass.nameOffset, enclosingClassName.length, [enclosingClassName, builder.toString()]);
+ return true;
+ } else if (list.length == 2) {
+ ErrorCode errorCode = supertype2 != null && _enclosingClass == supertype2.element ? CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS : CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS;
+ _errorReporter.reportError3(errorCode, _enclosingClass.nameOffset, enclosingClassName.length, [enclosingClassName]);
+ return true;
+ }
+ }
+ for (int i = 1; i < list.length - 1; i++) {
+ if (classElt == list[i]) {
+ list.removeAt(list.length - 1);
+ return false;
+ }
+ }
+ List<ClassElement> interfaceElements;
+ List<InterfaceType> interfaceTypes = classElt.interfaces;
+ if (supertype2 != null && !supertype2.isObject()) {
+ interfaceElements = new List<ClassElement>(interfaceTypes.length + 1);
+ interfaceElements[0] = supertype2.element;
+ for (int i = 0; i < interfaceTypes.length; i++) {
+ interfaceElements[i + 1] = interfaceTypes[i].element;
+ }
+ } else {
+ interfaceElements = new List<ClassElement>(interfaceTypes.length);
+ for (int i = 0; i < interfaceTypes.length; i++) {
+ interfaceElements[i] = interfaceTypes[i].element;
+ }
+ }
+ for (ClassElement classElt2 in interfaceElements) {
+ if (checkForRecursiveInterfaceInheritance(classElt2, list)) {
+ return true;
+ }
+ }
+ list.removeAt(list.length - 1);
+ return false;
+ }
+
+ /**
+ * This checks the passed constructor declaration has a valid combination of redirected
+ * constructor invocation(s), super constructor invocations and field initializers.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS
+ * @see CompileTimeErrorCode#SUPER_IN_REDIRECTING_CONSTRUCTOR
+ * @see CompileTimeErrorCode#FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR
+ */
+ bool checkForRedirectingConstructorErrorCodes(ConstructorDeclaration node) {
+ int numProblems = 0;
+ int numRedirections = 0;
+ for (ConstructorInitializer initializer in node.initializers) {
+ if (initializer is RedirectingConstructorInvocation) {
+ if (numRedirections > 0) {
+ _errorReporter.reportError2(CompileTimeErrorCode.MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS, initializer, []);
+ numProblems++;
+ }
+ numRedirections++;
+ }
+ }
+ if (numRedirections > 0) {
+ for (ConstructorInitializer initializer in node.initializers) {
+ if (initializer is SuperConstructorInvocation) {
+ _errorReporter.reportError2(CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR, initializer, []);
+ numProblems++;
+ }
+ if (initializer is ConstructorFieldInitializer) {
+ _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR, initializer, []);
+ numProblems++;
+ }
+ }
+ }
+ return numProblems != 0;
+ }
+
+ /**
+ * This checks if the passed constructor declaration has redirected constructor with compatible
+ * function type.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#REDIRECT_TO_INVALID_RETURN_TYPE
+ * @see StaticWarningCode#REDIRECT_TO_INVALID_FUNCTION_TYPE
+ */
+ bool checkForRedirectToInvalidFunction(ConstructorDeclaration node) {
+ ConstructorName redirectedNode = node.redirectedConstructor;
+ if (redirectedNode == null) {
+ return false;
+ }
+ ConstructorElement redirectedElement = redirectedNode.element;
+ if (redirectedElement == null) {
+ return false;
+ }
+ FunctionType redirectedType = redirectedElement.type;
+ Type2 redirectedReturnType = redirectedType.returnType;
+ FunctionType constructorType = node.element.type;
+ Type2 constructorReturnType = constructorType.returnType;
+ if (!redirectedReturnType.isSubtypeOf(constructorReturnType)) {
+ _errorReporter.reportError2(StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE, redirectedNode, [redirectedReturnType, constructorReturnType]);
+ return true;
+ }
+ if (!redirectedType.isSubtypeOf(constructorType)) {
+ _errorReporter.reportError2(StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE, redirectedNode, [redirectedType, constructorType]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This checks if the passed constructor declaration has redirected constructor and references
+ * itself directly or indirectly. TODO(scheglov)
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#REDIRECT_TO_NON_CONST_CONSTRUCTOR
+ */
+ bool checkForRedirectToNonConstConstructor(ConstructorDeclaration node) {
+ ConstructorName redirectedConstructorNode = node.redirectedConstructor;
+ if (redirectedConstructorNode == null) {
+ return false;
+ }
+ ConstructorElement element2 = node.element;
+ if (element2 == null) {
+ return false;
+ }
+ if (!element2.isConst()) {
+ return false;
+ }
+ ConstructorElement redirectedConstructor2 = element2.redirectedConstructor;
+ if (redirectedConstructor2 == null) {
+ return false;
+ }
+ if (redirectedConstructor2.isConst()) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR, redirectedConstructorNode, []);
+ return true;
+ }
+
+ /**
+ * This checks if the passed identifier is banned because it is part of the variable declaration
+ * with the same name.
+ * @param node the identifier to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER
+ */
+ bool checkForReferenceToDeclaredVariableInInitializer(SimpleIdentifier node) {
+ ASTNode parent2 = node.parent;
+ if (parent2 is PrefixedIdentifier) {
+ PrefixedIdentifier prefixedIdentifier = parent2 as PrefixedIdentifier;
+ if (identical(prefixedIdentifier.identifier, node)) {
+ return false;
+ }
+ }
+ if (parent2 is PropertyAccess) {
+ PropertyAccess propertyAccess = parent2 as PropertyAccess;
+ if (identical(propertyAccess.propertyName, node)) {
+ return false;
+ }
+ }
+ if (parent2 is MethodInvocation) {
+ MethodInvocation methodInvocation = parent2 as MethodInvocation;
+ if (methodInvocation.target != null && identical(methodInvocation.methodName, node)) {
+ return false;
+ }
+ }
+ if (parent2 is ConstructorName) {
+ ConstructorName constructorName = parent2 as ConstructorName;
+ if (identical(constructorName.name, node)) {
+ return false;
+ }
+ }
+ if (parent2 is Label) {
+ Label label = parent2 as Label;
+ if (identical(label.label, node)) {
+ return false;
+ }
+ }
+ String name2 = node.name;
+ if (!_namesForReferenceToDeclaredVariableInInitializer.contains(name2)) {
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER, node, [name2]);
+ return true;
+ }
+
+ /**
* This checks that the rethrow is inside of a catch clause.
* @param node the rethrow expression to evaluate
* @return {@code true} if and only if an error code is generated on the passed node
@@ -8278,19 +12090,74 @@
*/
bool checkForRethrowOutsideCatch(RethrowExpression node) {
if (!_isInCatchClause) {
- _errorReporter.reportError(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, node, []);
+ _errorReporter.reportError2(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, node, []);
return true;
}
return false;
}
+
/**
+ * This checks that if the given "target" is the type reference then the "name" is not the
+ * reference to a instance member.
+ * @param target the target of the name access to evaluate
+ * @param name the accessed name to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#STATIC_ACCESS_TO_INSTANCE_MEMBER
+ */
+ bool checkForStaticAccessToInstanceMember(Expression target, SimpleIdentifier name2) {
+ Element element2 = name2.element;
+ if (element2 is! ExecutableElement) {
+ return false;
+ }
+ ExecutableElement memberElement = element2 as ExecutableElement;
+ if (memberElement.isStatic()) {
+ return false;
+ }
+ if (!isTypeReference(target)) {
+ return false;
+ }
+ _errorReporter.reportError2(StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER, name2, [name2.name]);
+ return true;
+ }
+
+ /**
+ * This checks that the type of the passed 'switch' expression is assignable to the type of the
+ * 'case' members.
+ * @param node the 'switch' statement to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#SWITCH_EXPRESSION_NOT_ASSIGNABLE
+ */
+ bool checkForSwitchExpressionNotAssignable(SwitchStatement node) {
+ Expression expression2 = node.expression;
+ Type2 expressionType = getStaticType(expression2);
+ if (expressionType == null) {
+ return false;
+ }
+ NodeList<SwitchMember> members2 = node.members;
+ for (SwitchMember switchMember in members2) {
+ if (switchMember is! SwitchCase) {
+ continue;
+ }
+ SwitchCase switchCase = switchMember as SwitchCase;
+ Expression caseExpression = switchCase.expression;
+ Type2 caseType = getStaticType(caseExpression);
+ if (expressionType.isAssignableTo(caseType)) {
+ return false;
+ }
+ _errorReporter.reportError2(StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE, expression2, [expressionType, caseType]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* This verifies that the type arguments in the passed instance creation expression are all within
* their bounds as specified by the class element where the constructor \[that is being invoked\] is
* declared.
* @param node the instance creation expression to evaluate
* @param typeName the {@link TypeName} of the {@link ConstructorName} from the{@link InstanceCreationExpression}, this is the AST node that the error is attached to
* @param constructorElement the {@link ConstructorElement} from the instance creation expression
- * @return return {@code true} if and only if an error code is generated on the passed node
+ * @return {@code true} if and only if an error code is generated on the passed node
* @see StaticTypeWarningCode#TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
*/
bool checkForTypeArgumentNotMatchingBounds(InstanceCreationExpression node, ConstructorElement constructorElement, TypeName typeName) {
@@ -8304,7 +12171,7 @@
Type2 boundType = boundingElts[i].bound;
if (argType != null && boundType != null) {
if (!argType.isSubtypeOf(boundType)) {
- _errorReporter.reportError(StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, argTypeName, [argTypeName.name, boundingElts[i].name]);
+ _errorReporter.reportError2(StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, argTypeName, [argTypeName.name, boundingElts[i].displayName]);
return true;
}
}
@@ -8312,36 +12179,168 @@
}
return false;
}
+
/**
- * This verifies if the passed setter method declaration, has only one parameter.
+ * This checks that if the passed generative constructor has no explicit super constructor
+ * invocation, then super class has the default generative constructor.
+ * @param node the constructor declaration to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
+ * @see CompileTimeErrorCode#NON_GENERATIVE_CONSTRUCTOR
+ */
+ bool checkForUndefinedConstructorInInitializerImplicit(ConstructorDeclaration node) {
+ if (node.factoryKeyword != null) {
+ return false;
+ }
+ if (_enclosingClass == null) {
+ return false;
+ }
+ InterfaceType superType = _enclosingClass.supertype;
+ if (superType == null) {
+ return false;
+ }
+ ClassElement superElement = superType.element;
+ for (ConstructorInitializer constructorInitializer in node.initializers) {
+ if (constructorInitializer is SuperConstructorInvocation) {
+ return false;
+ }
+ }
+ ConstructorElement superDefaultConstructor = superElement.unnamedConstructor;
+ if (superDefaultConstructor != null) {
+ if (superDefaultConstructor.isFactory()) {
+ _errorReporter.reportError2(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node.returnType, [superDefaultConstructor]);
+ return true;
+ }
+ return false;
+ }
+ _errorReporter.reportError2(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, node.returnType, [superElement.name]);
+ return true;
+ }
+
+ /**
+ * This verifies the passed operator-method declaration, has correct number of parameters.
* <p>
- * This method assumes that the method declaration was tested to be a setter before being called.
+ * This method assumes that the method declaration was tested to be an operator declaration before
+ * being called.
* @param node the method declaration to evaluate
- * @return return {@code true} if and only if an error code is generated on the passed node
- * @see CompileTimeErrorCode#WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR
*/
- bool checkForWrongNumberOfParametersForSetter(MethodDeclaration node) {
+ bool checkForWrongNumberOfParametersForOperator(MethodDeclaration node) {
FormalParameterList parameterList = node.parameters;
if (parameterList == null) {
return false;
}
- NodeList<FormalParameter> formalParameters = parameterList.parameters;
- int numberOfParameters = formalParameters.length;
+ int numParameters = parameterList.parameters.length;
+ SimpleIdentifier nameNode = node.name;
+ if (nameNode == null) {
+ return false;
+ }
+ String name2 = nameNode.name;
+ int expected = -1;
+ if ("[]=" == name2) {
+ expected = 2;
+ } else if ("<" == name2 || ">" == name2 || "<=" == name2 || ">=" == name2 || "==" == name2 || "+" == name2 || "/" == name2 || "~/" == name2 || "*" == name2 || "%" == name2 || "|" == name2 || "^" == name2 || "&" == name2 || "<<" == name2 || ">>" == name2 || "[]" == name2) {
+ expected = 1;
+ } else if ("~" == name2) {
+ expected = 0;
+ }
+ if (expected != -1 && numParameters != expected) {
+ _errorReporter.reportError2(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR, nameNode, [name2, expected, numParameters]);
+ return true;
+ }
+ if ("-" == name2 && numParameters > 1) {
+ _errorReporter.reportError2(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS, nameNode, [numParameters]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This verifies if the passed setter parameter list have only one parameter.
+ * <p>
+ * This method assumes that the method declaration was tested to be a setter before being called.
+ * @param setterName the name of the setter to report problems on
+ * @param parameterList the parameter list to evaluate
+ * @return {@code true} if and only if an error code is generated on the passed node
+ * @see CompileTimeErrorCode#WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER
+ */
+ bool checkForWrongNumberOfParametersForSetter(SimpleIdentifier setterName, FormalParameterList parameterList) {
+ if (setterName == null) {
+ return false;
+ }
+ if (parameterList == null) {
+ return false;
+ }
+ int numberOfParameters = parameterList.parameters.length;
if (numberOfParameters != 1) {
- _errorReporter.reportError(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER, node.name, [numberOfParameters]);
+ _errorReporter.reportError2(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER, setterName, [numberOfParameters]);
return true;
}
return false;
}
+
/**
- * Return the type of the given expression that is to be used for type analysis.
+ * Return the propagated type of the given expression, or the static type if there is no
+ * propagated type information.
* @param expression the expression whose type is to be returned
- * @return the type of the given expression
+ * @return the propagated or static type of the given expression, whichever is best
*/
- Type2 getType(Expression expression) {
+ Type2 getBestType(Expression expression) {
+ Type2 type = getPropagatedType(expression);
+ if (type == null) {
+ type = getStaticType(expression);
+ }
+ return type;
+ }
+
+ /**
+ * Returns the Type (return type) for a given getter.
+ * @param propertyAccessorElement
+ * @return The type of the given getter.
+ */
+ Type2 getGetterType(PropertyAccessorElement propertyAccessorElement) {
+ FunctionType functionType = propertyAccessorElement.type;
+ if (functionType != null) {
+ return functionType.returnType;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the propagated type of the given expression that is to be used for type analysis.
+ * @param expression the expression whose type is to be returned
+ * @return the propagated type of the given expression
+ */
+ Type2 getPropagatedType(Expression expression) => expression.propagatedType;
+
+ /**
+ * Returns the Type (first and only parameter) for a given setter.
+ * @param propertyAccessorElement
+ * @return The type of the given setter.
+ */
+ Type2 getSetterType(PropertyAccessorElement propertyAccessorElement) {
+ List<ParameterElement> setterParameters = propertyAccessorElement.parameters;
+ if (setterParameters.length == 0) {
+ return null;
+ }
+ return setterParameters[0].type;
+ }
+
+ /**
+ * Return the static type of the given expression that is to be used for type analysis.
+ * @param expression the expression whose type is to be returned
+ * @return the static type of the given expression
+ */
+ Type2 getStaticType(Expression expression) {
Type2 type = expression.staticType;
- return type == null ? _dynamicType : type;
+ if (type == null) {
+ return _dynamicType;
+ }
+ return type;
}
+
/**
* Return the variable element represented by the given expression, or {@code null} if there is no
* such element.
@@ -8357,7 +12356,51 @@
}
return null;
}
+
+ /**
+ * @return {@code true} if the given constructor redirects to itself, directly or indirectly
+ */
+ bool hasRedirectingFactoryConstructorCycle(ConstructorElement element) {
+ Set<ConstructorElement> constructors = new Set<ConstructorElement>();
+ ConstructorElement current = element;
+ while (current != null) {
+ if (constructors.contains(current)) {
+ return identical(current, element);
+ }
+ javaSetAdd(constructors, current);
+ current = current.redirectedConstructor;
+ if (current is ConstructorMember) {
+ current = ((current as ConstructorMember)).baseElement;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param node the 'this' expression to analyze
+ * @return {@code true} if the given 'this' expression is in the valid context
+ */
+ bool isThisInValidContext(ThisExpression node) {
+ for (ASTNode n = node; n != null; n = n.parent) {
+ if (n is CompilationUnit) {
+ return false;
+ }
+ if (n is ConstructorDeclaration) {
+ ConstructorDeclaration constructor = n as ConstructorDeclaration;
+ return constructor.factoryKeyword == null;
+ }
+ if (n is ConstructorFieldInitializer) {
+ return false;
+ }
+ if (n is MethodDeclaration) {
+ MethodDeclaration method = n as MethodDeclaration;
+ return !method.isStatic();
+ }
+ }
+ return false;
+ }
}
+
/**
* This enum holds one of four states of a field initialization state through a constructor
* signature, not initialized, initialized in the field declaration, initialized in the field
@@ -8370,14 +12413,18 @@
static final INIT_STATE INIT_IN_DEFAULT_VALUE = new INIT_STATE('INIT_IN_DEFAULT_VALUE', 3);
static final INIT_STATE INIT_IN_INITIALIZERS = new INIT_STATE('INIT_IN_INITIALIZERS', 4);
static final List<INIT_STATE> values = [NOT_INIT, INIT_IN_DECLARATION, INIT_IN_FIELD_FORMAL, INIT_IN_DEFAULT_VALUE, INIT_IN_INITIALIZERS];
- final String __name;
- final int __ordinal;
- int get ordinal => __ordinal;
- INIT_STATE(this.__name, this.__ordinal) {
+
+ /// The name of this enum constant, as declared in the enum declaration.
+ final String name;
+
+ /// The position in the enum declaration.
+ final int ordinal;
+ INIT_STATE(this.name, this.ordinal) {
}
- int compareTo(INIT_STATE other) => __ordinal - other.__ordinal;
- String toString() => __name;
+ int compareTo(INIT_STATE other) => ordinal - other.ordinal;
+ String toString() => name;
}
+
/**
* The enumeration {@code ResolverErrorCode} defines the error codes used for errors detected by the
* resolver. The convention for this class is for the name of the error code to indicate the problem
@@ -8390,30 +12437,35 @@
static final ResolverErrorCode CONTINUE_LABEL_ON_SWITCH = new ResolverErrorCode('CONTINUE_LABEL_ON_SWITCH', 1, ErrorType.COMPILE_TIME_ERROR, "A continue label resolves to switch, must be loop or switch member");
static final ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_WITH_PART = new ResolverErrorCode('MISSING_LIBRARY_DIRECTIVE_WITH_PART', 2, ErrorType.COMPILE_TIME_ERROR, "Libraries that have parts must have a library directive");
static final List<ResolverErrorCode> values = [BREAK_LABEL_ON_SWITCH_MEMBER, CONTINUE_LABEL_ON_SWITCH, MISSING_LIBRARY_DIRECTIVE_WITH_PART];
- final String __name;
- final int __ordinal;
- int get ordinal => __ordinal;
+
+ /// The name of this enum constant, as declared in the enum declaration.
+ final String name;
+
+ /// The position in the enum declaration.
+ final int ordinal;
+
/**
* The type of this error.
*/
ErrorType _type;
+
/**
* The message template used to create the message to be displayed for this error.
*/
String _message;
+
/**
* Initialize a newly created error code to have the given type and message.
* @param type the type of this error
* @param message the message template used to create the message to be displayed for the error
*/
- ResolverErrorCode(this.__name, this.__ordinal, ErrorType type, String message) {
+ ResolverErrorCode(this.name, this.ordinal, ErrorType type, String message) {
this._type = type;
this._message = message;
}
ErrorSeverity get errorSeverity => _type.severity;
String get message => _message;
ErrorType get type => _type;
- bool needsRecompilation() => true;
- int compareTo(ResolverErrorCode other) => __ordinal - other.__ordinal;
- String toString() => __name;
-}
+ int compareTo(ResolverErrorCode other) => ordinal - other.ordinal;
+ String toString() => name;
+}
« no previous file with comments | « pkg/analyzer_experimental/lib/src/generated/parser.dart ('k') | pkg/analyzer_experimental/lib/src/generated/scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698