| 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>, …, 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>, …, 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>, …, a<sub>n</sub>)</i> or the form <i>new
|
| @@ -4905,31 +6283,39 @@
|
| * form <i>const T(a<sub>1</sub>, …, 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> <E>\[e<sub>1</sub>, …, e<sub>n</sub>\]</i> or the form
|
| @@ -4938,16 +6324,41 @@
|
| * the form <i>\[e<sub>1</sub>, …, e<sub>n</sub>\]</i> is {@code List<dynamic>}.</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> <String, V> {k<sub>1</sub>:e<sub>1</sub>, …,
|
| @@ -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>, …, 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;
|
| +}
|
|
|