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

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

Issue 184893003: New analyzer snapshot. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 3e6f1aaf36b7b3c9fcc49881c4bf781a61cfd87e..14b74b95650a91eedce2bbb78a4effa7aa1654be 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -64,6 +64,14 @@ class AngularCompilationUnitBuilder {
if (node is! SimpleStringLiteral) {
return null;
}
+ SimpleStringLiteral literal = node as SimpleStringLiteral;
+ // maybe has AngularElement
+ {
+ Element element = literal.toolkitElement;
+ if (element is AngularElement) {
+ return element;
+ }
+ }
// prepare enclosing ClassDeclaration
ClassDeclaration classDeclaration = node.getAncestor(ClassDeclaration);
if (classDeclaration == null) {
@@ -83,17 +91,17 @@ class AngularCompilationUnitBuilder {
return toolkitObject;
}
}
+ // try selector
+ if (toolkitObject is AngularHasSelectorElement) {
+ AngularHasSelectorElement hasSelector = toolkitObject;
+ AngularSelectorElement selector = hasSelector.selector;
+ if (isNameCoveredByLiteral(selector, node)) {
+ return selector;
+ }
+ }
// try properties of AngularComponentElement
if (toolkitObject is AngularComponentElement) {
AngularComponentElement component = toolkitObject;
- // try selector
- {
- AngularSelectorElement selector = component.selector;
- if (isNameCoveredByLiteral(selector, node)) {
- return selector;
- }
- }
- // try properties
properties = component.properties;
}
// try properties of AngularDirectiveElement
@@ -129,11 +137,17 @@ class AngularCompilationUnitBuilder {
static AngularSelectorElement parseSelector(int offset, String text) {
// [attribute]
if (StringUtilities.startsWithChar(text, 0x5B) && StringUtilities.endsWithChar(text, 0x5D)) {
- int nameOffset = offset + "[".length;
+ int nameOffset = offset + 1;
String attributeName = text.substring(1, text.length - 1);
// TODO(scheglov) report warning if there are spaces between [ and identifier
return new HasAttributeSelectorElementImpl(attributeName, nameOffset);
}
+ // .class
+ if (StringUtilities.startsWithChar(text, 0x2E)) {
+ int nameOffset = offset + 1;
+ String className = text.substring(1, text.length);
+ return new AngularHasClassSelectorElementImpl(className, nameOffset);
+ }
// tag[attribute]
if (StringUtilities.endsWithChar(text, 0x5D)) {
int index = StringUtilities.indexOf1(text, 0, 0x5B);
@@ -147,7 +161,7 @@ class AngularCompilationUnitBuilder {
}
// tag
if (StringUtilities.isTagName(text)) {
- return new IsTagSelectorElementImpl(text, offset);
+ return new AngularTagSelectorElementImpl(text, offset);
}
return null;
}
@@ -215,6 +229,11 @@ class AngularCompilationUnitBuilder {
Source _source;
/**
+ * The compilation unit with built Dart element models.
+ */
+ CompilationUnit _unit;
+
+ /**
* The [ClassDeclaration] that is currently being analyzed.
*/
ClassDeclaration _classDeclaration;
@@ -239,20 +258,21 @@ class AngularCompilationUnitBuilder {
*
* @param errorListener the listener to which errors will be reported.
* @param source the source containing the unit that will be analyzed
+ * @param unit the compilation unit with built Dart element models
*/
- AngularCompilationUnitBuilder(AnalysisErrorListener errorListener, Source source) {
+ AngularCompilationUnitBuilder(AnalysisErrorListener errorListener, Source source, CompilationUnit unit) {
this._errorListener = errorListener;
this._source = source;
+ this._unit = unit;
}
/**
* Builds Angular specific element models and adds them to the existing Dart elements.
- *
- * @param unit the compilation unit with built Dart element models
*/
- void build(CompilationUnit unit) {
+ void build() {
+ parseViews();
// process classes
- for (CompilationUnitMember unitMember in unit.declarations) {
+ for (CompilationUnitMember unitMember in _unit.declarations) {
if (unitMember is ClassDeclaration) {
this._classDeclaration = unitMember;
this._classElement = _classDeclaration.element as ClassElementImpl;
@@ -403,7 +423,8 @@ class AngularCompilationUnitBuilder {
element.templateUriOffset = templateUriOffset;
element.styleUri = styleUri;
element.styleUriOffset = styleUriOffset;
- element.properties = parseNgComponentProperties(true);
+ element.properties = parseNgComponentProperties();
+ element.scopeProperties = parseScopeProperties();
_classToolkitObjects.add(element);
}
}
@@ -411,12 +432,10 @@ class AngularCompilationUnitBuilder {
/**
* Parses [AngularPropertyElement]s from [annotation] and [classDeclaration].
*/
- List<AngularPropertyElement> parseNgComponentProperties(bool fromFields) {
+ List<AngularPropertyElement> parseNgComponentProperties() {
List<AngularPropertyElement> properties = [];
parseNgComponentProperties_fromMap(properties);
- if (fromFields) {
- parseNgComponentProperties_fromFields(properties);
- }
+ parseNgComponentProperties_fromFields(properties);
return new List.from(properties);
}
@@ -582,7 +601,7 @@ class AngularCompilationUnitBuilder {
int offset = _annotation.offset;
AngularDirectiveElementImpl element = new AngularDirectiveElementImpl(offset);
element.selector = selector;
- element.properties = parseNgComponentProperties(false);
+ element.properties = parseNgComponentProperties();
_classToolkitObjects.add(element);
}
}
@@ -602,6 +621,25 @@ class AngularCompilationUnitBuilder {
}
}
+ List<AngularScopePropertyElement> parseScopeProperties() {
+ List<AngularScopePropertyElement> properties = [];
+ _classDeclaration.accept(new RecursiveASTVisitor_AngularCompilationUnitBuilder_parseScopeProperties(properties));
+ return new List.from(properties);
+ }
+
+ /**
+ * Create [AngularViewElement] for each valid <code>view('template.html')</code> invocation,
+ * where <code>view</code> is <code>ViewFactory</code>.
+ */
+ void parseViews() {
+ List<AngularViewElement> views = [];
+ _unit.accept(new RecursiveASTVisitor_AngularCompilationUnitBuilder_parseViews(views));
+ if (!views.isEmpty) {
+ List<AngularViewElement> viewArray = new List.from(views);
+ (_unit.element as CompilationUnitElementImpl).angularViews = viewArray;
+ }
+ }
+
void reportError(ASTNode node, ErrorCode errorCode, List<Object> arguments) {
int offset = node.offset;
int length = node.length;
@@ -622,6 +660,130 @@ class AngularCompilationUnitBuilder {
}
}
+class RecursiveASTVisitor_AngularCompilationUnitBuilder_parseScopeProperties extends RecursiveASTVisitor<Object> {
+ List<AngularScopePropertyElement> properties;
+
+ RecursiveASTVisitor_AngularCompilationUnitBuilder_parseScopeProperties(this.properties) : super();
+
+ Object visitAssignmentExpression(AssignmentExpression node) {
+ addProperty(node);
+ return super.visitAssignmentExpression(node);
+ }
+
+ void addProperty(AssignmentExpression node) {
+ // try to find "name" in scope[name]
+ SimpleStringLiteral nameNode = getNameNode(node.leftHandSide);
+ if (nameNode == null) {
+ return;
+ }
+ // prepare unique
+ String name = nameNode.stringValue;
+ if (hasPropertyWithName(name)) {
+ return;
+ }
+ // do add property
+ int nameOffset = nameNode.valueOffset;
+ AngularScopePropertyElement property = new AngularScopePropertyElementImpl(name, nameOffset, node.rightHandSide.bestType);
+ nameNode.toolkitElement = property;
+ properties.add(property);
+ }
+
+ SimpleStringLiteral getNameNode(Expression node) {
+ if (node is IndexExpression) {
+ IndexExpression indexExpression = node;
+ Expression target = indexExpression.target;
+ Expression index = indexExpression.index;
+ if (index is SimpleStringLiteral && isContext(target)) {
+ return index;
+ }
+ }
+ return null;
+ }
+
+ bool hasPropertyWithName(String name) {
+ for (AngularScopePropertyElement property in properties) {
+ if (property.name == name) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool isContext(Expression target) {
+ if (target is PrefixedIdentifier) {
+ PrefixedIdentifier prefixed = target;
+ SimpleIdentifier prefix = prefixed.prefix;
+ SimpleIdentifier identifier = prefixed.identifier;
+ return (identifier.name == "context") && isScope(prefix);
+ }
+ return false;
+ }
+
+ bool isScope(Expression target) {
+ if (target != null) {
+ Type2 type = target.bestType;
+ if (type is InterfaceType) {
+ InterfaceType interfaceType = type;
+ return interfaceType.name == "Scope";
+ }
+ }
+ return false;
+ }
+}
+
+class RecursiveASTVisitor_AngularCompilationUnitBuilder_parseViews extends RecursiveASTVisitor<Object> {
+ List<AngularViewElement> views;
+
+ RecursiveASTVisitor_AngularCompilationUnitBuilder_parseViews(this.views) : super();
+
+ Object visitMethodInvocation(MethodInvocation node) {
+ addView(node);
+ return super.visitMethodInvocation(node);
+ }
+
+ void addView(MethodInvocation node) {
+ // only one argument
+ List<Expression> arguments = node.argumentList.arguments;
+ if (arguments.length != 1) {
+ return;
+ }
+ // String literal
+ Expression argument = arguments[0];
+ if (argument is! SimpleStringLiteral) {
+ return;
+ }
+ SimpleStringLiteral literal = argument as SimpleStringLiteral;
+ // just view('template')
+ if (node.realTarget != null) {
+ return;
+ }
+ // should be ViewFactory
+ if (!isViewFactory(node.methodName)) {
+ return;
+ }
+ // add AngularViewElement
+ String templateUri = literal.stringValue;
+ int templateUriOffset = literal.valueOffset;
+ views.add(new AngularViewElementImpl(templateUri, templateUriOffset));
+ }
+
+ bool isViewFactory(Expression target) {
+ if (target is SimpleIdentifier) {
+ SimpleIdentifier identifier = target;
+ Element element = identifier.staticElement;
+ if (element is VariableElement) {
+ VariableElement variable = element;
+ Type2 type = variable.type;
+ if (type is InterfaceType) {
+ InterfaceType interfaceType = type;
+ return interfaceType.name == "ViewFactory";
+ }
+ }
+ }
+ return false;
+ }
+}
+
/**
* Instances of the class `CompilationUnitBuilder` build an element model for a single
* compilation unit.
@@ -828,7 +990,7 @@ class ElementBuilder extends RecursiveASTVisitor<Object> {
_inFunction = wasInFunction;
}
SimpleIdentifier constructorName = node.name;
- ConstructorElementImpl element = new ConstructorElementImpl(constructorName);
+ ConstructorElementImpl element = new ConstructorElementImpl.con1(constructorName);
if (node.factoryKeyword != null) {
element.factory = true;
}
@@ -1327,7 +1489,7 @@ class ElementBuilder extends RecursiveASTVisitor<Object> {
* @return the [ConstructorElement]s array with the single default constructor element
*/
List<ConstructorElement> createDefaultConstructors(InterfaceTypeImpl interfaceType) {
- ConstructorElementImpl constructor = new ConstructorElementImpl(null);
+ ConstructorElementImpl constructor = new ConstructorElementImpl.con1(null);
constructor.synthetic = true;
constructor.returnType = interfaceType;
FunctionTypeImpl type = new FunctionTypeImpl.con1(constructor);
@@ -1855,7 +2017,7 @@ class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
* @return the HTML element that was built
* @throws AnalysisException if the analysis could not be performed
*/
- HtmlElementImpl buildHtmlElement(Source source) => buildHtmlElement2(source, source.modificationStamp, _context.parseHtmlUnit(source));
+ HtmlElementImpl buildHtmlElement(Source source) => buildHtmlElement2(source, _context.getModificationStamp(source), _context.parseHtmlUnit(source));
/**
* Build the HTML element for the given source.
@@ -1924,7 +2086,7 @@ class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
parseUriWithException(scriptSourcePath);
Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
script.scriptSource = scriptSource;
- if (scriptSource == null || !scriptSource.exists()) {
+ if (!_context.exists(scriptSource)) {
reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute, [scriptSourcePath]);
}
} on URISyntaxException catch (exception) {
@@ -2863,6 +3025,12 @@ class DeadCodeVerifier extends RecursiveASTVisitor<Object> {
* expression, or simple infinite loop such as `while(true)`.
*/
class ExitDetector extends GeneralizingASTVisitor<bool> {
+ /**
+ * Set to `true` when a `break` is encountered, and reset to `false` when a
+ * `do`, `while`, `for` or `switch` block is entered.
+ */
+ bool _enclosingBlockContainsBreak = false;
+
bool visitArgumentList(ArgumentList node) => visitExpressions(node.arguments);
bool visitAsExpression(AsExpression node) => node.expression.accept(this);
@@ -2903,7 +3071,10 @@ class ExitDetector extends GeneralizingASTVisitor<bool> {
bool visitBlockFunctionBody(BlockFunctionBody node) => node.block.accept(this);
- bool visitBreakStatement(BreakStatement node) => false;
+ bool visitBreakStatement(BreakStatement node) {
+ _enclosingBlockContainsBreak = true;
+ return false;
+ }
bool visitCascadeExpression(CascadeExpression node) {
Expression target = node.target;
@@ -2931,37 +3102,74 @@ class ExitDetector extends GeneralizingASTVisitor<bool> {
bool visitContinueStatement(ContinueStatement node) => false;
bool visitDoStatement(DoStatement node) {
- Expression conditionExpression = node.condition;
- if (conditionExpression.accept(this)) {
- return true;
- }
- // TODO(jwren) Do we want to take all constant expressions into account?
- if (conditionExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = conditionExpression;
- if (booleanLiteral.value) {
- return node.body.accept(this);
+ bool outerBreakValue = _enclosingBlockContainsBreak;
+ _enclosingBlockContainsBreak = false;
+ try {
+ Expression conditionExpression = node.condition;
+ if (conditionExpression.accept(this)) {
+ return true;
}
+ // TODO(jwren) Do we want to take all constant expressions into account?
+ if (conditionExpression is BooleanLiteral) {
+ BooleanLiteral booleanLiteral = conditionExpression;
+ // If do {} while (true), and the body doesn't return or the body doesn't have a break, then
+ // return true.
+ bool blockReturns = node.body.accept(this);
+ if (booleanLiteral.value && (blockReturns || !_enclosingBlockContainsBreak)) {
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ _enclosingBlockContainsBreak = outerBreakValue;
}
- return false;
}
bool visitEmptyStatement(EmptyStatement node) => false;
bool visitExpressionStatement(ExpressionStatement node) => node.expression.accept(this);
- bool visitForEachStatement(ForEachStatement node) => node.iterator.accept(this);
+ bool visitForEachStatement(ForEachStatement node) {
+ bool outerBreakValue = _enclosingBlockContainsBreak;
+ _enclosingBlockContainsBreak = false;
+ try {
+ return node.iterator.accept(this);
+ } finally {
+ _enclosingBlockContainsBreak = outerBreakValue;
+ }
+ }
bool visitForStatement(ForStatement node) {
- if (node.variables != null && visitVariableDeclarations(node.variables.variables)) {
- return true;
- }
- if (node.initialization != null && node.initialization.accept(this)) {
- return true;
- }
- if (node.condition != null && node.condition.accept(this)) {
- return true;
+ bool outerBreakValue = _enclosingBlockContainsBreak;
+ _enclosingBlockContainsBreak = false;
+ try {
+ if (node.variables != null && visitVariableDeclarations(node.variables.variables)) {
+ return true;
+ }
+ if (node.initialization != null && node.initialization.accept(this)) {
+ return true;
+ }
+ Expression conditionExpression = node.condition;
+ if (conditionExpression != null && conditionExpression.accept(this)) {
+ return true;
+ }
+ if (visitExpressions(node.updaters)) {
+ return true;
+ }
+ // TODO(jwren) Do we want to take all constant expressions into account?
+ // If for(; true; ) (or for(;;)), and the body doesn't return or the body doesn't have a
+ // break, then return true.
+ bool implicitOrExplictTrue = conditionExpression == null || (conditionExpression is BooleanLiteral && conditionExpression.value);
+ if (implicitOrExplictTrue) {
+ bool blockReturns = node.body.accept(this);
+ if (blockReturns || !_enclosingBlockContainsBreak) {
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ _enclosingBlockContainsBreak = outerBreakValue;
}
- return visitExpressions(node.updaters);
}
bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) => false;
@@ -3057,25 +3265,31 @@ class ExitDetector extends GeneralizingASTVisitor<bool> {
bool visitSwitchDefault(SwitchDefault node) => visitStatements(node.statements);
bool visitSwitchStatement(SwitchStatement node) {
- bool hasDefault = false;
- NodeList<SwitchMember> memberList = node.members;
- List<SwitchMember> members = new List.from(memberList);
- for (int i = 0; i < members.length; i++) {
- SwitchMember switchMember = members[i];
- if (switchMember is SwitchDefault) {
- hasDefault = true;
- // If this is the last member and there are no statements, return false
- if (switchMember.statements.isEmpty && i + 1 == members.length) {
+ bool outerBreakValue = _enclosingBlockContainsBreak;
+ _enclosingBlockContainsBreak = false;
+ try {
+ bool hasDefault = false;
+ NodeList<SwitchMember> memberList = node.members;
+ List<SwitchMember> members = new List.from(memberList);
+ for (int i = 0; i < members.length; i++) {
+ SwitchMember switchMember = members[i];
+ if (switchMember is SwitchDefault) {
+ hasDefault = true;
+ // If this is the last member and there are no statements, return false
+ if (switchMember.statements.isEmpty && i + 1 == members.length) {
+ return false;
+ }
+ }
+ // For switch members with no statements, don't visit the children, otherwise, return false if
+ // no return is found in the children statements
+ if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
return false;
}
}
- // For switch members with no statements, don't visit the children, otherwise, return false if
- // no return is found in the children statements
- if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
- return false;
- }
+ return hasDefault;
+ } finally {
+ _enclosingBlockContainsBreak = outerBreakValue;
}
- return hasDefault;
}
bool visitThisExpression(ThisExpression node) => false;
@@ -3116,18 +3330,27 @@ class ExitDetector extends GeneralizingASTVisitor<bool> {
}
bool visitWhileStatement(WhileStatement node) {
- Expression conditionExpression = node.condition;
- if (conditionExpression.accept(this)) {
- return true;
- }
- // TODO(jwren) Do we want to take all constant expressions into account?
- if (conditionExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = conditionExpression;
- if (booleanLiteral.value) {
- return node.body.accept(this);
+ bool outerBreakValue = _enclosingBlockContainsBreak;
+ _enclosingBlockContainsBreak = false;
+ try {
+ Expression conditionExpression = node.condition;
+ if (conditionExpression.accept(this)) {
+ return true;
+ }
+ // TODO(jwren) Do we want to take all constant expressions into account?
+ if (conditionExpression is BooleanLiteral) {
+ BooleanLiteral booleanLiteral = conditionExpression;
+ // If while(true), and the body doesn't return or the body doesn't have a break, then return
+ // true.
+ bool blockReturns = node.body.accept(this);
+ if (booleanLiteral.value && (blockReturns || !_enclosingBlockContainsBreak)) {
+ return true;
+ }
}
+ return false;
+ } finally {
+ _enclosingBlockContainsBreak = outerBreakValue;
}
- return false;
}
bool visitExpressions(NodeList<Expression> expressions) {
@@ -3176,6 +3399,11 @@ class HintGenerator {
bool _enableDart2JSHints = false;
+ /**
+ * The inheritance manager used to find overridden methods.
+ */
+ InheritanceManager _manager;
+
HintGenerator(List<CompilationUnit> compilationUnits, AnalysisContext context, AnalysisErrorListener errorListener) {
this._compilationUnits = compilationUnits;
this._context = context;
@@ -3183,6 +3411,7 @@ class HintGenerator {
LibraryElement library = compilationUnits[0].element.library;
_importsVerifier = new ImportsVerifier(library);
_enableDart2JSHints = context.analysisOptions.dart2jsHint;
+ _manager = new InheritanceManager(compilationUnits[0].element.library);
}
void generateForLibrary() {
@@ -3210,15 +3439,16 @@ class HintGenerator {
void generateForCompilationUnit(CompilationUnit unit, Source source) {
ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
- _importsVerifier.visitCompilationUnit(unit);
+ unit.accept(_importsVerifier);
// dead code analysis
- new DeadCodeVerifier(errorReporter).visitCompilationUnit(unit);
+ unit.accept(new DeadCodeVerifier(errorReporter));
// dart2js analysis
if (_enableDart2JSHints) {
- new Dart2JSVerifier(errorReporter).visitCompilationUnit(unit);
+ unit.accept(new Dart2JSVerifier(errorReporter));
}
// Dart best practices
- new BestPracticesVerifier(errorReporter).visitCompilationUnit(unit);
+ unit.accept(new BestPracticesVerifier(errorReporter));
+ unit.accept(new OverrideVerifier(_manager, errorReporter));
// Find to-do comments
new ToDoFinder(errorReporter).findIn(unit);
}
@@ -3565,6 +3795,77 @@ class ImportsVerifier extends RecursiveASTVisitor<Object> {
}
/**
+ * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
+ * unit to verify that if they have an override annotation it is being used correctly.
+ */
+class OverrideVerifier extends RecursiveASTVisitor<Object> {
+ /**
+ * The inheritance manager used to find overridden methods.
+ */
+ InheritanceManager _manager;
+
+ /**
+ * The error reporter used to report errors.
+ */
+ ErrorReporter _errorReporter;
+
+ /**
+ * Initialize a newly created verifier to look for inappropriate uses of the override annotation.
+ *
+ * @param manager the inheritance manager used to find overridden methods
+ * @param errorReporter the error reporter used to report errors
+ */
+ OverrideVerifier(InheritanceManager manager, ErrorReporter errorReporter) {
+ this._manager = manager;
+ this._errorReporter = errorReporter;
+ }
+
+ Object visitMethodDeclaration(MethodDeclaration node) {
+ ExecutableElement element = node.element;
+ if (isOverride(element)) {
+ if (getOverriddenMember(element) == null) {
+ if (element is MethodElement) {
+ _errorReporter.reportError3(HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name, []);
+ } else if (element is PropertyAccessorElement) {
+ if (element.isGetter) {
+ _errorReporter.reportError3(HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name, []);
+ } else {
+ _errorReporter.reportError3(HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name, []);
+ }
+ }
+ }
+ }
+ return super.visitMethodDeclaration(node);
+ }
+
+ /**
+ * Return the member that overrides the given member.
+ *
+ * @param member the member that overrides the returned member
+ * @return the member that overrides the given member
+ */
+ ExecutableElement getOverriddenMember(ExecutableElement member) {
+ LibraryElement library = member.library;
+ if (library == null) {
+ return null;
+ }
+ ClassElement classElement = member.getAncestor(ClassElement);
+ if (classElement == null) {
+ return null;
+ }
+ return _manager.lookupInheritance(classElement, member.name);
+ }
+
+ /**
+ * Return `true` if the given element has an override annotation associated with it.
+ *
+ * @param element the element being tested
+ * @return `true` if the element has an override annotation associated with it
+ */
+ bool isOverride(Element element) => element != null && element.isOverride;
+}
+
+/**
* Instances of the class `PubVerifier` traverse an AST structure looking for deviations from
* pub best practices.
*/
@@ -3615,7 +3916,7 @@ class PubVerifier extends RecursiveASTVisitor<Object> {
if (StringUtilities.startsWith4(fullName, fullNameIndex - 4, 0x2F, 0x6C, 0x69, 0x62)) {
String relativePubspecPath = path.substring(0, pathIndex + 3) + _PUBSPEC_YAML;
Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePubspecPath);
- if (pubspecSource != null && pubspecSource.exists()) {
+ if (_context.exists(pubspecSource)) {
// Files inside the lib directory hierarchy should not reference files outside
_errorReporter.reportError3(PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE, uriLiteral, []);
}
@@ -3657,7 +3958,7 @@ class PubVerifier extends RecursiveASTVisitor<Object> {
Source source = getSource(uriLiteral);
String relativePubspecPath = path.substring(0, pathIndex) + _PUBSPEC_YAML;
Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePubspecPath);
- if (pubspecSource == null || !pubspecSource.exists()) {
+ if (!_context.exists(pubspecSource)) {
return false;
}
String fullName = getSourceFullName(source);
@@ -4971,33 +5272,36 @@ class ElementResolver extends SimpleASTVisitor<Object> {
* Checks if the given expression is the reference to the type, if it is then the
* [ClassElement] is returned, otherwise `null` is returned.
*
- * @param expr the expression to evaluate
+ * @param expression the expression to evaluate
* @return the [ClassElement] if the given expression is the reference to the type, and
* `null` otherwise
*/
- static ClassElementImpl getTypeReference(Expression expr) {
- if (expr is Identifier) {
- Identifier identifier = expr;
- if (identifier.staticElement is ClassElementImpl) {
- return identifier.staticElement as ClassElementImpl;
+ static ClassElementImpl getTypeReference(Expression expression) {
+ if (expression is Identifier) {
+ Element staticElement = expression.staticElement;
+ if (staticElement is ClassElementImpl) {
+ return staticElement;
}
}
return null;
}
/**
+ * Return `true` if the given identifier is the return type of a constructor declaration.
+ *
* @return `true` if the given identifier is the return type of a constructor declaration.
*/
- static bool isConstructorReturnType(SimpleIdentifier node) {
- ASTNode parent = node.parent;
+ static bool isConstructorReturnType(SimpleIdentifier identifier) {
+ ASTNode parent = identifier.parent;
if (parent is ConstructorDeclaration) {
- ConstructorDeclaration constructor = parent;
- return identical(constructor.returnType, node);
+ return identical(parent.returnType, identifier);
}
return false;
}
/**
+ * Return `true` if the given identifier is the return type of a factory constructor.
+ *
* @return `true` if the given identifier is the return type of a factory constructor
* declaration.
*/
@@ -5011,10 +5315,10 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
/**
- * Checks if the given 'super' expression is used in the valid context.
+ * Return `true` if the given 'super' expression is used in a valid context.
*
* @param node the 'super' expression to analyze
- * @return `true` if the given 'super' expression is in the valid context
+ * @return `true` if the 'super' expression is in a valid context
*/
static bool isSuperInValidContext(SuperExpression node) {
for (ASTNode n = node; n != null; n = n.parent) {
@@ -5113,22 +5417,10 @@ class ElementResolver extends SimpleASTVisitor<Object> {
Type2 propagatedType = getPropagatedType(leftHandSide);
MethodElement propagatedMethod = lookUpMethod(leftHandSide, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
- bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
- //
- // If we are about to generate the hint (propagated version of this warning), then check
- // that the member is not in a subtype of the propagated type.
- //
- if (shouldReportMissingMember_propagated) {
- if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
- shouldReportMissingMember_propagated = false;
- }
- }
- if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
- ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_METHOD : HintCode.UNDEFINED_METHOD) as ErrorCode;
- _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissingMember_static ? staticType.element : propagatedType.element, errorCode, operator, [
- methodName,
- shouldReportMissingMember_static ? staticType.displayName : propagatedType.displayName]);
+ if (shouldReportMissingMember(staticType, staticMethod)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(staticType.element, StaticTypeWarningCode.UNDEFINED_METHOD, operator, [methodName, staticType.displayName]);
+ } else if (_enableHints && shouldReportMissingMember(propagatedType, propagatedMethod) && !memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(propagatedType.element, HintCode.UNDEFINED_METHOD, operator, [methodName, propagatedType.displayName]);
}
}
}
@@ -5147,22 +5439,10 @@ class ElementResolver extends SimpleASTVisitor<Object> {
Type2 propagatedType = getPropagatedType(leftOperand);
MethodElement propagatedMethod = lookUpMethod(leftOperand, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
- bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
- //
- // If we are about to generate the hint (propagated version of this warning), then check
- // that the member is not in a subtype of the propagated type.
- //
- if (shouldReportMissingMember_propagated) {
- if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
- shouldReportMissingMember_propagated = false;
- }
- }
- if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
- ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode;
- _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissingMember_static ? staticType.element : propagatedType.element, errorCode, operator, [
- methodName,
- shouldReportMissingMember_static ? staticType.displayName : propagatedType.displayName]);
+ if (shouldReportMissingMember(staticType, staticMethod)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]);
+ } else if (_enableHints && shouldReportMissingMember(propagatedType, propagatedMethod) && !memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(propagatedType.element, HintCode.UNDEFINED_OPERATOR, operator, [methodName, propagatedType.displayName]);
}
}
}
@@ -5170,11 +5450,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
Object visitBreakStatement(BreakStatement node) {
- SimpleIdentifier labelNode = node.label;
- LabelElementImpl labelElement = lookupLabel(node, labelNode);
- if (labelElement != null && labelElement.isOnSwitchMember) {
- _resolver.reportError9(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode, []);
- }
+ lookupLabel(node, node.label);
return null;
}
@@ -5275,17 +5551,18 @@ class ElementResolver extends SimpleASTVisitor<Object> {
ConstructorElement element = node.element;
if (element is ConstructorElementImpl) {
ConstructorElementImpl constructorElement = element;
- // set redirected factory constructor
ConstructorName redirectedNode = node.redirectedConstructor;
if (redirectedNode != null) {
+ // set redirected factory constructor
ConstructorElement redirectedElement = redirectedNode.staticElement;
constructorElement.redirectedConstructor = redirectedElement;
- }
- // set redirected generate constructor
- for (ConstructorInitializer initializer in node.initializers) {
- if (initializer is RedirectingConstructorInvocation) {
- ConstructorElement redirectedElement = initializer.staticElement;
- constructorElement.redirectedConstructor = redirectedElement;
+ } else {
+ // set redirected generative constructor
+ for (ConstructorInitializer initializer in node.initializers) {
+ if (initializer is RedirectingConstructorInvocation) {
+ ConstructorElement redirectedElement = initializer.staticElement;
+ constructorElement.redirectedConstructor = redirectedElement;
+ }
}
}
setMetadata(constructorElement, node);
@@ -5298,11 +5575,6 @@ class ElementResolver extends SimpleASTVisitor<Object> {
ClassElement enclosingClass = _resolver.enclosingClass;
FieldElement fieldElement = enclosingClass.getField(fieldName.name);
fieldName.staticElement = fieldElement;
- if (fieldElement == null || fieldElement.isSynthetic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
- } else if (fieldElement.isStatic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName]);
- }
return null;
}
@@ -5312,13 +5584,16 @@ class ElementResolver extends SimpleASTVisitor<Object> {
return null;
} else if (type is! InterfaceType) {
// TODO(brianwilkerson) Report these errors.
- ASTNode parent = node.parent;
- if (parent is InstanceCreationExpression) {
- if (parent.isConst) {
- } else {
- }
- } else {
- }
+ // ASTNode parent = node.getParent();
+ // if (parent instanceof InstanceCreationExpression) {
+ // if (((InstanceCreationExpression) parent).isConst()) {
+ // // CompileTimeErrorCode.CONST_WITH_NON_TYPE
+ // } else {
+ // // StaticWarningCode.NEW_WITH_NON_TYPE
+ // }
+ // } else {
+ // // This is part of a redirecting factory constructor; not sure which error code to use
+ // }
return null;
}
// look up ConstructorElement
@@ -5336,11 +5611,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
Object visitContinueStatement(ContinueStatement node) {
- SimpleIdentifier labelNode = node.label;
- LabelElementImpl labelElement = lookupLabel(node, labelNode);
- if (labelElement != null && labelElement.isOnSwitchStatement) {
- _resolver.reportError9(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode, []);
- }
+ lookupLabel(node, node.label);
return null;
}
@@ -5362,38 +5633,6 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
Object visitFieldFormalParameter(FieldFormalParameter node) {
- String fieldName = node.identifier.name;
- ClassElement classElement = _resolver.enclosingClass;
- if (classElement != null) {
- FieldElement fieldElement = classElement.getField(fieldName);
- if (fieldElement == null || fieldElement.isSynthetic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
- } else {
- ParameterElement parameterElement = node.element;
- if (parameterElement is FieldFormalParameterElementImpl) {
- FieldFormalParameterElementImpl fieldFormal = parameterElement;
- Type2 declaredType = fieldFormal.type;
- Type2 fieldType = fieldElement.type;
- if (fieldElement.isSynthetic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
- } else if (fieldElement.isStatic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
- } else if (declaredType != null && fieldType != null && !declaredType.isAssignableTo(fieldType)) {
- _resolver.reportError9(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
- }
- } else {
- if (fieldElement.isSynthetic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
- } else if (fieldElement.isStatic) {
- _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
- }
- }
- }
- }
- // else {
- // // TODO(jwren) Report error, constructor initializer variable is a top level element
- // // (Either here or in ErrorVerifier#checkForAllFinalInitializedErrorCodes)
- // }
setMetadata2(node.element, node);
return super.visitFieldFormalParameter(node);
}
@@ -5673,22 +5912,10 @@ class ElementResolver extends SimpleASTVisitor<Object> {
Type2 propagatedType = getPropagatedType(operand);
MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
- bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
- //
- // If we are about to generate the hint (propagated version of this warning), then check
- // that the member is not in a subtype of the propagated type.
- //
- if (shouldReportMissingMember_propagated) {
- if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
- shouldReportMissingMember_propagated = false;
- }
- }
- if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
- ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode;
- _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissingMember_static ? staticType.element : propagatedType.element, errorCode, node.operator, [
- methodName,
- shouldReportMissingMember_static ? staticType.displayName : propagatedType.displayName]);
+ if (shouldReportMissingMember(staticType, staticMethod)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [methodName, staticType.displayName]);
+ } else if (_enableHints && shouldReportMissingMember(propagatedType, propagatedMethod) && !memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(propagatedType.element, HintCode.UNDEFINED_OPERATOR, node.operator, [methodName, propagatedType.displayName]);
}
return null;
}
@@ -5758,26 +5985,14 @@ class ElementResolver extends SimpleASTVisitor<Object> {
String methodName = getPrefixOperator(node);
Type2 staticType = getStaticType(operand);
MethodElement staticMethod = lookUpMethod(operand, staticType, methodName);
- node.staticElement = staticMethod;
- Type2 propagatedType = getPropagatedType(operand);
- MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
- node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
- bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
- //
- // If we are about to generate the hint (propagated version of this warning), then check
- // that the member is not in a subtype of the propagated type.
- //
- if (shouldReportMissingMember_propagated) {
- if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
- shouldReportMissingMember_propagated = false;
- }
- }
- if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
- ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode;
- _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissingMember_static ? staticType.element : propagatedType.element, errorCode, operator, [
- methodName,
- shouldReportMissingMember_static ? staticType.displayName : propagatedType.displayName]);
+ node.staticElement = staticMethod;
+ Type2 propagatedType = getPropagatedType(operand);
+ MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
+ node.propagatedElement = propagatedMethod;
+ if (shouldReportMissingMember(staticType, staticMethod)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]);
+ } else if (_enableHints && shouldReportMissingMember(propagatedType, propagatedMethod) && !memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
+ _resolver.reportErrorProxyConditionalAnalysisError3(propagatedType.element, HintCode.UNDEFINED_OPERATOR, operator, [methodName, propagatedType.displayName]);
}
}
return null;
@@ -6054,16 +6269,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
*/
bool checkForUndefinedIndexOperator(IndexExpression node, Expression target, String methodName, MethodElement staticMethod, MethodElement propagatedMethod, Type2 staticType, Type2 propagatedType) {
bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
- bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
- //
- // If we are about to generate the hint (propagated version of this warning), then check
- // that the member is not in a subtype of the propagated type.
- //
- if (shouldReportMissingMember_propagated) {
- if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
- shouldReportMissingMember_propagated = false;
- }
- }
+ bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints && shouldReportMissingMember(propagatedType, propagatedMethod) && !memberFoundInSubclass(propagatedType.element, methodName, true, false);
if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
sc.Token leftBracket = node.leftBracket;
sc.Token rightBracket = node.rightBracket;
@@ -6708,12 +6914,13 @@ class ElementResolver extends SimpleASTVisitor<Object> {
return sc.TokenType.STAR;
} else if (operator == sc.TokenType.TILDE_SLASH_EQ) {
return sc.TokenType.TILDE_SLASH;
+ } else {
+ // Internal error: Unmapped assignment operator.
+ AnalysisEngine.instance.logger.logError("Failed to map ${operator.lexeme} to it's corresponding operator");
+ return operator;
}
break;
}
- // Internal error: Unmapped assignment operator.
- AnalysisEngine.instance.logger.logError("Failed to map ${operator.lexeme} to it's corresponding operator");
- return operator;
}
void resolveAnnotationConstructorInvocationArguments(Annotation annotation, ConstructorElement constructor) {
@@ -7486,6 +7693,133 @@ class IncrementalResolver {
*/
class InheritanceManager {
/**
+ * Given some array of [ExecutableElement]s, this method creates a synthetic element as
+ * described in the Superinterfaces section of Inheritance and Overriding.
+ *
+ * TODO (jwren) Copy contents from the Spec into this javadoc.
+ *
+ * TODO (jwren) Associate a propagated type to the synthetic method element using least upper
+ * bound calls
+ */
+ static ExecutableElement computeMergedExecutableElement(List<ExecutableElement> elementArrayToMerge) {
+ int h = getNumOfPositionalParameters(elementArrayToMerge[0]);
+ int r = getNumOfRequiredParameters(elementArrayToMerge[0]);
+ Set<String> namedParametersList = new Set<String>();
+ for (int i = 1; i < elementArrayToMerge.length; i++) {
+ ExecutableElement element = elementArrayToMerge[i];
+ int numOfPositionalParams = getNumOfPositionalParameters(element);
+ if (h < numOfPositionalParams) {
+ h = numOfPositionalParams;
+ }
+ int numOfRequiredParams = getNumOfRequiredParameters(element);
+ if (r > numOfRequiredParams) {
+ r = numOfRequiredParams;
+ }
+ namedParametersList.addAll(getNamedParameterNames(element));
+ }
+ if (r > h) {
+ return null;
+ }
+ return createSyntheticExecutableElement(elementArrayToMerge, elementArrayToMerge[0].displayName, r, h - r, new List.from(namedParametersList));
+ }
+
+ /**
+ * Used by [computeMergedExecutableElement] to actually create the
+ * synthetic element.
+ *
+ * @param elementArrayToMerge the array used to create the synthetic element
+ * @param name the name of the method, getter or setter
+ * @param numOfRequiredParameters the number of required parameters
+ * @param numOfPositionalParameters the number of positional parameters
+ * @param namedParameters the list of [String]s that are the named parameters
+ * @return the created synthetic element
+ */
+ static ExecutableElement createSyntheticExecutableElement(List<ExecutableElement> elementArrayToMerge, String name, int numOfRequiredParameters, int numOfPositionalParameters, List<String> namedParameters) {
+ DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
+ SimpleIdentifier nameIdentifier = new SimpleIdentifier(new sc.StringToken(sc.TokenType.IDENTIFIER, name, 0));
+ ExecutableElementImpl executable;
+ if (elementArrayToMerge[0] is MethodElement) {
+ MultiplyInheritedMethodElementImpl unionedMethod = new MultiplyInheritedMethodElementImpl(nameIdentifier);
+ unionedMethod.inheritedElements = elementArrayToMerge;
+ executable = unionedMethod;
+ } else {
+ MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor = new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
+ unionedPropertyAccessor.getter = (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
+ unionedPropertyAccessor.setter = (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
+ unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
+ executable = unionedPropertyAccessor;
+ }
+ int numOfParameters = numOfRequiredParameters + numOfPositionalParameters + namedParameters.length;
+ List<ParameterElement> parameters = new List<ParameterElement>(numOfParameters);
+ int i = 0;
+ for (int j = 0; j < numOfRequiredParameters; j++, i++) {
+ ParameterElementImpl parameter = new ParameterElementImpl.con2("", 0);
+ parameter.type = dynamicType;
+ parameter.parameterKind = ParameterKind.REQUIRED;
+ parameters[i] = parameter;
+ }
+ for (int k = 0; k < numOfPositionalParameters; k++, i++) {
+ ParameterElementImpl parameter = new ParameterElementImpl.con2("", 0);
+ parameter.type = dynamicType;
+ parameter.parameterKind = ParameterKind.POSITIONAL;
+ parameters[i] = parameter;
+ }
+ for (int m = 0; m < namedParameters.length; m++, i++) {
+ ParameterElementImpl parameter = new ParameterElementImpl.con2(namedParameters[m], 0);
+ parameter.type = dynamicType;
+ parameter.parameterKind = ParameterKind.NAMED;
+ parameters[i] = parameter;
+ }
+ executable.returnType = dynamicType;
+ executable.parameters = parameters;
+ FunctionTypeImpl methodType = new FunctionTypeImpl.con1(executable);
+ executable.type = methodType;
+ return executable;
+ }
+
+ /**
+ * Given some [ExecutableElement], return the list of named parameters.
+ */
+ static List<String> getNamedParameterNames(ExecutableElement executableElement) {
+ List<String> namedParameterNames = new List<String>();
+ List<ParameterElement> parameters = executableElement.parameters;
+ for (int i = 0; i < parameters.length; i++) {
+ ParameterElement parameterElement = parameters[i];
+ if (identical(parameterElement.parameterKind, ParameterKind.NAMED)) {
+ namedParameterNames.add(parameterElement.name);
+ }
+ }
+ return namedParameterNames;
+ }
+
+ /**
+ * Given some [ExecutableElement] return the number of parameters of the specified kind.
+ */
+ static int getNumOfParameters(ExecutableElement executableElement, ParameterKind parameterKind) {
+ int parameterCount = 0;
+ List<ParameterElement> parameters = executableElement.parameters;
+ for (int i = 0; i < parameters.length; i++) {
+ ParameterElement parameterElement = parameters[i];
+ if (identical(parameterElement.parameterKind, parameterKind)) {
+ parameterCount++;
+ }
+ }
+ return parameterCount;
+ }
+
+ /**
+ * Given some [ExecutableElement] return the number of positional parameters.
+ *
+ * Note: by positional we mean [ParameterKind#REQUIRED] or [ParameterKind#POSITIONAL].
+ */
+ static int getNumOfPositionalParameters(ExecutableElement executableElement) => getNumOfParameters(executableElement, ParameterKind.REQUIRED) + getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
+
+ /**
+ * Given some [ExecutableElement] return the number of required parameters.
+ */
+ static int getNumOfRequiredParameters(ExecutableElement executableElement) => getNumOfParameters(executableElement, ParameterKind.REQUIRED);
+
+ /**
* The [LibraryElement] that is managed by this manager.
*/
LibraryElement _library;
@@ -7700,7 +8034,7 @@ class InheritanceManager {
//
List<InterfaceType> mixins = classElt.mixins;
for (int i = mixins.length - 1; i >= 0; i--) {
- recordMapWithClassMembers(resultMap, mixins[i]);
+ recordMapWithClassMembersFromMixin(resultMap, mixins[i]);
}
_classLookup[classElt] = resultMap;
return resultMap;
@@ -7868,37 +8202,75 @@ class InheritanceManager {
return resultMap;
}
//
- // Union all of the maps together, grouping the ExecutableElements into sets.
+ // Union all of the lookupMaps together into unionMap, grouping the ExecutableElements into a
+ // list where none of the elements are equal where equality is determined by having equal
+ // function types. (We also take note too of the kind of the element: ()->int and () -> int may
+ // not be equal if one is a getter and the other is a method.)
//
- Map<String, Set<ExecutableElement>> unionMap = new Map<String, Set<ExecutableElement>>();
+ Map<String, List<ExecutableElement>> unionMap = new Map<String, List<ExecutableElement>>();
for (MemberMap lookupMap in lookupMaps) {
- for (int i = 0; i < lookupMap.size; i++) {
+ int lookupMapSize = lookupMap.size;
+ for (int i = 0; i < lookupMapSize; i++) {
+ // Get the string key, if null, break.
String key = lookupMap.getKey(i);
if (key == null) {
break;
}
- Set<ExecutableElement> set = unionMap[key];
- if (set == null) {
- set = new Set<ExecutableElement>();
- unionMap[key] = set;
+ // Get the list value out of the unionMap
+ List<ExecutableElement> list = unionMap[key];
+ // If we haven't created such a map for this key yet, do create it and put the list entry
+ // into the unionMap.
+ if (list == null) {
+ list = new List<ExecutableElement>();
+ unionMap[key] = list;
+ }
+ // Fetch the entry out of this lookupMap
+ ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
+ if (list.isEmpty) {
+ // If the list is empty, just the new value
+ list.add(newExecutableElementEntry);
+ } else {
+ // Otherwise, only add the newExecutableElementEntry if it isn't already in the list, this
+ // covers situation where a class inherits two methods (or two getters) that are
+ // identical.
+ bool alreadyInList = false;
+ bool isMethod1 = newExecutableElementEntry is MethodElement;
+ for (ExecutableElement executableElementInList in list) {
+ bool isMethod2 = executableElementInList is MethodElement;
+ if (identical(isMethod1, isMethod2) && executableElementInList.type == newExecutableElementEntry.type) {
+ alreadyInList = true;
+ break;
+ }
+ }
+ if (!alreadyInList) {
+ list.add(newExecutableElementEntry);
+ }
}
- set.add(lookupMap.getValue(i));
}
}
//
- // Loop through the entries in the union map, adding them to the resultMap appropriately.
+ // Loop through the entries in the unionMap, adding them to the resultMap appropriately.
//
- for (MapEntry<String, Set<ExecutableElement>> entry in getMapEntrySet(unionMap)) {
+ for (MapEntry<String, List<ExecutableElement>> entry in getMapEntrySet(unionMap)) {
String key = entry.getKey();
- Set<ExecutableElement> set = entry.getValue();
- int numOfEltsWithMatchingNames = set.length;
+ List<ExecutableElement> list = entry.getValue();
+ int numOfEltsWithMatchingNames = list.length;
if (numOfEltsWithMatchingNames == 1) {
- resultMap.put(key, new JavaIterator(set).next());
+ //
+ // Example: class A inherits only 1 method named 'm'. Since it is the only such method, it
+ // is inherited.
+ // Another example: class A inherits 2 methods named 'm' from 2 different interfaces, but
+ // they both have the same signature, so it is the method inherited.
+ //
+ resultMap.put(key, list[0]);
} else {
+ //
+ // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
+ //
bool allMethods = true;
bool allSetters = true;
bool allGetters = true;
- for (ExecutableElement executableElement in set) {
+ for (ExecutableElement executableElement in list) {
if (executableElement is PropertyAccessorElement) {
allMethods = false;
if (executableElement.isSetter) {
@@ -7911,14 +8283,20 @@ class InheritanceManager {
allSetters = false;
}
}
+ //
+ // If there isn't a mixture of methods with getters, then continue, otherwise create a
+ // warning.
+ //
if (allMethods || allGetters || allSetters) {
+ //
// Compute the element whose type is the subtype of all of the other types.
- List<ExecutableElement> elements = new List.from(set);
+ //
+ List<ExecutableElement> elements = new List.from(list);
List<FunctionType> executableElementTypes = new List<FunctionType>(numOfEltsWithMatchingNames);
for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
executableElementTypes[i] = elements[i].type;
}
- bool foundSubtypeOfAllTypes = false;
+ List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
FunctionType subtype = executableElementTypes[i];
if (subtype == null) {
@@ -7934,19 +8312,49 @@ class InheritanceManager {
}
}
if (subtypeOfAllTypes) {
- foundSubtypeOfAllTypes = true;
- resultMap.put(key, elements[i]);
- break;
+ subtypesOfAllOtherTypesIndexes.add(i);
}
}
- if (!foundSubtypeOfAllTypes) {
- reportError(classElt, classElt.nameOffset, classElt.displayName.length, StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [key]);
+ //
+ // The following is split into three cases determined by the number of elements in subtypesOfAllOtherTypes
+ //
+ if (subtypesOfAllOtherTypesIndexes.length == 1) {
+ //
+ // Example: class A inherited only 2 method named 'm'. One has the function type
+ // '() -> dynamic' and one has the function type '([int]) -> dynamic'. Since the second
+ // method is a subtype of all the others, it is the inherited method.
+ // Tests: InheritanceManagerTest.test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
+ //
+ resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
+ } else {
+ if (subtypesOfAllOtherTypesIndexes.isEmpty) {
+ //
+ // Example: class A inherited only 2 method named 'm'. One has the function type
+ // '() -> int' and one has the function type '() -> String'. Since neither is a subtype
+ // of the other, we create a warning, and have this class inherit nothing.
+ //
+ String firstTwoFuntionTypesStr = "${executableElementTypes[0].toString()}, ${executableElementTypes[1].toString()}";
+ reportError(classElt, classElt.nameOffset, classElt.displayName.length, StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [key, firstTwoFuntionTypesStr]);
+ } else {
+ //
+ // Example: class A inherits 2 methods named 'm'. One has the function type
+ // '(int) -> dynamic' and one has the function type '(num) -> dynamic'. Since they are
+ // both a subtype of the other, a synthetic function '(dynamic) -> dynamic' is
+ // inherited.
+ // Tests: test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_*
+ //
+ List<ExecutableElement> elementArrayToMerge = new List<ExecutableElement>(subtypesOfAllOtherTypesIndexes.length);
+ for (int i = 0; i < elementArrayToMerge.length; i++) {
+ elementArrayToMerge[i] = elements[subtypesOfAllOtherTypesIndexes[i]];
+ }
+ ExecutableElement mergedExecutableElement = computeMergedExecutableElement(elementArrayToMerge);
+ if (mergedExecutableElement != null) {
+ resultMap.put(key, mergedExecutableElement);
+ }
+ }
}
} else {
- if (!allMethods && !allGetters) {
- reportError(classElt, classElt.nameOffset, classElt.displayName.length, StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD, [key]);
- }
- resultMap.remove(entry.getKey());
+ reportError(classElt, classElt.nameOffset, classElt.displayName.length, StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD, [key]);
}
}
}
@@ -8003,6 +8411,38 @@ class InheritanceManager {
}
/**
+ * Similar to [recordMapWithClassMembers], but only puts values
+ * into the map if the additional executable doesn't replace a concrete member with an abstract
+ * member, ex: NonErrorResolverTest.test_nonAbstractClassInheritsAbstractMemberOne_mixin_*()
+ *
+ * @param map some non-`null` map to put the methods and accessors from the passed
+ * [ClassElement] into
+ * @param type the type that will be recorded into the passed map
+ */
+ void recordMapWithClassMembersFromMixin(MemberMap map, InterfaceType type) {
+ List<MethodElement> methods = type.methods;
+ for (MethodElement method in methods) {
+ if (method.isAccessibleIn(_library) && !method.isStatic) {
+ String methodName = method.name;
+ ExecutableElement elementInMap = map.get(methodName);
+ if (elementInMap == null || (elementInMap != null && !method.isAbstract)) {
+ map.put(methodName, method);
+ }
+ }
+ }
+ List<PropertyAccessorElement> accessors = type.accessors;
+ for (PropertyAccessorElement accessor in accessors) {
+ if (accessor.isAccessibleIn(_library) && !accessor.isStatic) {
+ String accessorName = accessor.name;
+ ExecutableElement elementInMap = map.get(accessorName);
+ if (elementInMap == null || (elementInMap != null && !accessor.isAbstract)) {
+ map.put(accessorName, accessor);
+ }
+ }
+ }
+ }
+
+ /**
* This method is used to report errors on when they are found computing inheritance information.
* See [ErrorVerifier#checkForInconsistentMethodInheritance] to see where these generated
* error codes are reported back into the analysis engine.
@@ -8292,7 +8732,7 @@ class Library {
try {
parseUriWithException(uriContent);
Source source = _analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
- if (source == null || !source.exists()) {
+ if (!_analysisContext.exists(source)) {
_errorListener.onError(new AnalysisError.con2(librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent]));
}
return source;
@@ -8371,7 +8811,7 @@ class LibraryElementBuilder {
/**
* The name of the function used as an entry point.
*/
- static String _ENTRY_POINT_NAME = "main";
+ static String ENTRY_POINT_NAME = "main";
/**
* Initialize a newly created library element builder.
@@ -8417,7 +8857,7 @@ class LibraryElementBuilder {
PartDirective partDirective = directive;
StringLiteral partUri = partDirective.uri;
Source partSource = library.getSource(partDirective);
- if (partSource != null && partSource.exists()) {
+ if (_analysisContext.exists(partSource)) {
hasPartDirective = true;
CompilationUnitElementImpl part = builder.buildCompilationUnit(partSource, library.getAST(partSource));
part.uri = library.getUri(partDirective);
@@ -8493,7 +8933,7 @@ class LibraryElementBuilder {
*/
FunctionElement findEntryPoint(CompilationUnitElementImpl element) {
for (FunctionElement function in element.functions) {
- if (function.name == _ENTRY_POINT_NAME) {
+ if (function.name == ENTRY_POINT_NAME) {
return function;
}
}
@@ -8955,6 +9395,13 @@ class LibraryResolver {
LibraryElementImpl libraryElement = library.libraryElement;
libraryElement.imports = new List.from(imports);
libraryElement.exports = new List.from(exports);
+ if (libraryElement.entryPoint == null) {
+ Namespace namespace = new NamespaceBuilder().createExportNamespace2(libraryElement);
+ Element element = namespace.get(LibraryElementBuilder.ENTRY_POINT_NAME);
+ if (element is FunctionElement) {
+ libraryElement.entryPoint = element;
+ }
+ }
}
}
@@ -9126,7 +9573,6 @@ class LibraryResolver {
*/
Library createLibrary(Source librarySource) {
Library library = new Library(analysisContext, _errorListener, librarySource);
- library.definingCompilationUnit;
_libraryMap[librarySource] = library;
return library;
}
@@ -9158,7 +9604,7 @@ class LibraryResolver {
* @return the library object that was created
*/
Library createLibraryOrNull(Source librarySource) {
- if (!librarySource.exists()) {
+ if (!analysisContext.exists(librarySource)) {
return null;
}
Library library = new Library(analysisContext, _errorListener, librarySource);
@@ -9247,7 +9693,7 @@ class LibraryResolver {
try {
for (Source source in library.compilationUnitSources) {
CompilationUnit ast = library.getAST(source);
- new AngularCompilationUnitBuilder(_errorListener, source).build(ast);
+ new AngularCompilationUnitBuilder(_errorListener, source, ast).build();
}
} finally {
timeCounter.stop();
@@ -9450,14 +9896,6 @@ class MemberMap {
*/
class ProxyConditionalAnalysisError {
/**
- * Return `true` if the given element represents a class that has the proxy annotation.
- *
- * @param element the class being tested
- * @return `true` if the given element represents a class that has the proxy annotation
- */
- static bool classHasProxyAnnotation(Element element) => (element is ClassElement) && element.isProxy;
-
- /**
* The enclosing [ClassElement], this is what will determine if the error code should, or
* should not, be generated on the source.
*/
@@ -9469,8 +9907,8 @@ class ProxyConditionalAnalysisError {
final AnalysisError analysisError;
/**
- * Instantiate a new ProxyConditionalErrorCode with some enclosing element and the conditional
- * analysis error.
+ * Instantiate a new [ProxyConditionalAnalysisError] with some enclosing element and the
+ * conditional analysis error.
*
* @param enclosingElement the enclosing element
* @param analysisError the conditional analysis error
@@ -9484,7 +9922,12 @@ class ProxyConditionalAnalysisError {
*
* @return `true` iff the enclosing class has the proxy annotation
*/
- bool shouldIncludeErrorCode() => !classHasProxyAnnotation(_enclosingElement);
+ bool shouldIncludeErrorCode() {
+ if (_enclosingElement is ClassElement) {
+ return !(_enclosingElement as ClassElement).isOrInheritsProxy;
+ }
+ return true;
+ }
}
/**
@@ -13888,6 +14331,24 @@ class TypeResolverVisitor extends ScopedVisitor {
}
if (classElement != null && superclassType != null) {
classElement.supertype = superclassType;
+ ClassElement superclassElement = superclassType.element;
+ if (superclassElement != null) {
+ List<ConstructorElement> constructors = superclassElement.constructors;
+ int count = constructors.length;
+ if (count > 0) {
+ List<Type2> parameterTypes = TypeParameterTypeImpl.getTypes(superclassType.typeParameters);
+ List<Type2> argumentTypes = getArgumentTypes(node.superclass.typeArguments, parameterTypes);
+ InterfaceType classType = classElement.type;
+ List<ConstructorElement> implicitConstructors = new List<ConstructorElement>();
+ for (int i = 0; i < count; i++) {
+ ConstructorElement explicitConstructor = constructors[i];
+ if (!explicitConstructor.isFactory) {
+ implicitConstructors.add(createImplicitContructor(classType, explicitConstructor, parameterTypes, argumentTypes));
+ }
+ }
+ classElement.constructors = new List.from(implicitConstructors);
+ }
+ }
}
resolve(classElement, node.withClause, node.implementsClause);
return null;
@@ -14328,6 +14789,73 @@ class TypeResolverVisitor extends ScopedVisitor {
}
/**
+ * Create an implicit constructor that is copied from the given constructor, but that is in the
+ * given class.
+ *
+ * @param classType the class in which the implicit constructor is defined
+ * @param explicitConstructor the constructor on which the implicit constructor is modeled
+ * @param parameterTypes the types to be replaced when creating parameters
+ * @param argumentTypes the types with which the parameters are to be replaced
+ * @return the implicit constructor that was created
+ */
+ ConstructorElement createImplicitContructor(InterfaceType classType, ConstructorElement explicitConstructor, List<Type2> parameterTypes, List<Type2> argumentTypes) {
+ ConstructorElementImpl implicitConstructor = new ConstructorElementImpl.con2(explicitConstructor.name, -1);
+ implicitConstructor.synthetic = true;
+ implicitConstructor.redirectedConstructor = explicitConstructor;
+ implicitConstructor.const2 = explicitConstructor.isConst;
+ implicitConstructor.returnType = classType;
+ List<ParameterElement> explicitParameters = explicitConstructor.parameters;
+ int count = explicitParameters.length;
+ if (count > 0) {
+ List<ParameterElement> implicitParameters = new List<ParameterElement>(count);
+ for (int i = 0; i < count; i++) {
+ ParameterElement explicitParameter = explicitParameters[i];
+ ParameterElementImpl implicitParameter = new ParameterElementImpl.con2(explicitParameter.name, -1);
+ implicitParameter.const3 = explicitParameter.isConst;
+ implicitParameter.final2 = explicitParameter.isFinal;
+ implicitParameter.parameterKind = explicitParameter.parameterKind;
+ implicitParameter.synthetic = true;
+ implicitParameter.type = explicitParameter.type.substitute2(argumentTypes, parameterTypes);
+ implicitParameters[i] = implicitParameter;
+ }
+ implicitConstructor.parameters = implicitParameters;
+ }
+ FunctionTypeImpl type = new FunctionTypeImpl.con1(implicitConstructor);
+ type.typeArguments = classType.typeArguments;
+ implicitConstructor.type = type;
+ return implicitConstructor;
+ }
+
+ /**
+ * Return an array of argument types that corresponds to the array of parameter types and that are
+ * derived from the given list of type arguments.
+ *
+ * @param typeArguments the type arguments from which the types will be taken
+ * @param parameterTypes the parameter types that must be matched by the type arguments
+ * @return the argument types that correspond to the parameter types
+ */
+ List<Type2> getArgumentTypes(TypeArgumentList typeArguments, List<Type2> parameterTypes) {
+ DynamicTypeImpl dynamic = DynamicTypeImpl.instance;
+ int parameterCount = parameterTypes.length;
+ List<Type2> types = new List<Type2>(parameterCount);
+ if (typeArguments == null) {
+ for (int i = 0; i < parameterCount; i++) {
+ types[i] = dynamic;
+ }
+ } else {
+ NodeList<TypeName> arguments = typeArguments.arguments;
+ int argumentCount = Math.min(arguments.length, parameterCount);
+ for (int i = 0; i < argumentCount; i++) {
+ types[i] = arguments[i].type;
+ }
+ for (int i = argumentCount; i < parameterCount; i++) {
+ types[i] = dynamic;
+ }
+ }
+ return types;
+ }
+
+ /**
* Return the class element that represents the class whose name was provided.
*
* @param identifier the name from the declaration of a class
@@ -16432,16 +16960,16 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
ExecutableElement _enclosingFunction;
/**
- * The number of return statements found in the method or function that we are currently visiting
- * that have a return value.
+ * The return statements found in the method or function that we are currently visiting that have
+ * a return value.
*/
- int _returnWithCount = 0;
+ List<ReturnStatement> _returnsWith = new List<ReturnStatement>();
/**
- * The number of return statements found in the method or function that we are currently visiting
- * that do not have a return value.
+ * The return statements found in the method or function that we are currently visiting that do
+ * not have a return value.
*/
- int _returnWithoutCount = 0;
+ List<ReturnStatement> _returnsWithout = new List<ReturnStatement>();
/**
* This map is initialized when visiting the contents of a class declaration. If the visitor is
@@ -16544,16 +17072,27 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
Object visitBlockFunctionBody(BlockFunctionBody node) {
- int previousReturnWithCount = _returnWithCount;
- int previousReturnWithoutCount = _returnWithoutCount;
+ List<ReturnStatement> previousReturnsWith = _returnsWith;
+ List<ReturnStatement> previousReturnsWithout = _returnsWithout;
try {
- _returnWithCount = 0;
- _returnWithoutCount = 0;
+ _returnsWith = new List<ReturnStatement>();
+ _returnsWithout = new List<ReturnStatement>();
super.visitBlockFunctionBody(node);
checkForMixedReturns(node);
} finally {
- _returnWithCount = previousReturnWithCount;
- _returnWithoutCount = previousReturnWithoutCount;
+ _returnsWith = previousReturnsWith;
+ _returnsWithout = previousReturnsWithout;
+ }
+ return null;
+ }
+
+ Object visitBreakStatement(BreakStatement node) {
+ SimpleIdentifier labelNode = node.label;
+ if (labelNode != null) {
+ Element labelElement = labelNode.staticElement;
+ if (labelElement is LabelElementImpl && labelElement.isOnSwitchMember) {
+ _errorReporter.reportError3(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode, []);
+ }
}
return null;
}
@@ -16669,6 +17208,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
_isInConstructorInitializer = true;
try {
+ checkForInvalidField(node);
checkForFieldInitializerNotAssignable(node);
return super.visitConstructorFieldInitializer(node);
} finally {
@@ -16676,6 +17216,17 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
}
+ Object visitContinueStatement(ContinueStatement node) {
+ SimpleIdentifier labelNode = node.label;
+ if (labelNode != null) {
+ Element labelElement = labelNode.staticElement;
+ if (labelElement is LabelElementImpl && labelElement.isOnSwitchStatement) {
+ _errorReporter.reportError3(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode, []);
+ }
+ }
+ return null;
+ }
+
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
checkForInvalidAssignment2(node.identifier, node.defaultValue);
checkForDefaultValueInFunctionTypedParameter(node);
@@ -16711,7 +17262,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
_isInStaticVariableDeclaration = node.isStatic;
_isInInstanceVariableDeclaration = !_isInStaticVariableDeclaration;
try {
- checkForAllInvalidOverrideErrorCodes2(node);
+ checkForAllInvalidOverrideErrorCodes3(node);
return super.visitFieldDeclaration(node);
} finally {
_isInStaticVariableDeclaration = false;
@@ -16720,6 +17271,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
Object visitFieldFormalParameter(FieldFormalParameter node) {
+ checkForValidField(node);
checkForConstFormalParameter(node);
checkForPrivateOptionalParameter(node);
checkForFieldInitializingFormalRedirectingConstructor(node);
@@ -16892,7 +17444,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
checkForConflictingInstanceMethodSetter(node);
}
checkForConcreteClassWithAbstractMember(node);
- checkForAllInvalidOverrideErrorCodes3(node);
+ checkForAllInvalidOverrideErrorCodes4(node);
return super.visitMethodDeclaration(node);
} finally {
_enclosingFunction = previousFunction;
@@ -16978,9 +17530,9 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
Object visitReturnStatement(ReturnStatement node) {
if (node.expression == null) {
- _returnWithoutCount++;
+ _returnsWithout.add(node);
} else {
- _returnWithCount++;
+ _returnsWith.add(node);
}
checkForAllReturnStatementErrorCodes(node);
return super.visitReturnStatement(node);
@@ -17195,6 +17747,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
* This checks the passed executable element against override-error codes.
*
* @param executableElement a non-null [ExecutableElement] to evaluate
+ * @param overriddenExecutable the element that the executableElement is overriding
* @param parameters the parameters of the executable element
* @param errorNameTarget the node to report problems on
* @return `true` if and only if an error code is generated on the passed node
@@ -17210,10 +17763,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
* @see StaticWarningCode#INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE
* @see StaticWarningCode#INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES
*/
- bool checkForAllInvalidOverrideErrorCodes(ExecutableElement executableElement, List<ParameterElement> parameters, List<ASTNode> parameterLocations, SimpleIdentifier errorNameTarget) {
- String executableElementName = executableElement.name;
- bool executableElementPrivate = Identifier.isPrivateName(executableElementName);
- ExecutableElement overriddenExecutable = _inheritanceManager.lookupInheritance(_enclosingClass, executableElementName);
+ bool checkForAllInvalidOverrideErrorCodes(ExecutableElement executableElement, ExecutableElement overriddenExecutable, List<ParameterElement> parameters, List<ASTNode> parameterLocations, SimpleIdentifier errorNameTarget) {
bool isGetter = false;
bool isSetter = false;
if (executableElement is PropertyAccessorElement) {
@@ -17221,12 +17771,14 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
isGetter = accessorElement.isGetter;
isSetter = accessorElement.isSetter;
}
+ String executableElementName = executableElement.name;
// SWC.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC
if (overriddenExecutable == null) {
if (!isGetter && !isSetter && !executableElement.isOperator) {
Set<ClassElement> visitedClasses = new Set<ClassElement>();
InterfaceType superclassType = _enclosingClass.supertype;
ClassElement superclassElement = superclassType == null ? null : superclassType.element;
+ bool executableElementPrivate = Identifier.isPrivateName(executableElementName);
while (superclassElement != null && !visitedClasses.contains(superclassElement)) {
visitedClasses.add(superclassElement);
LibraryElement superclassLibrary = superclassElement.library;
@@ -17467,13 +18019,50 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
+ * This checks the passed executable element against override-error codes. This method computes
+ * the passed executableElement is overriding and calls
+ * [checkForAllInvalidOverrideErrorCodes]
+ * when the [InheritanceManager] returns a [MultiplyInheritedExecutableElement], this
+ * method loops through the array in the [MultiplyInheritedExecutableElement].
+ *
+ * @param executableElement a non-null [ExecutableElement] to evaluate
+ * @param parameters the parameters of the executable element
+ * @param errorNameTarget the node to report problems on
+ * @return `true` if and only if an error code is generated on the passed node
+ */
+ bool checkForAllInvalidOverrideErrorCodes2(ExecutableElement executableElement, List<ParameterElement> parameters, List<ASTNode> parameterLocations, SimpleIdentifier errorNameTarget) {
+ //
+ // Compute the overridden executable from the InheritanceManager
+ //
+ ExecutableElement overriddenExecutable = _inheritanceManager.lookupInheritance(_enclosingClass, executableElement.name);
+ //
+ // If the result is a MultiplyInheritedExecutableElement call
+ // checkForAllInvalidOverrideErrorCodes on all of the elements, until an error is found.
+ //
+ if (overriddenExecutable is MultiplyInheritedExecutableElement) {
+ MultiplyInheritedExecutableElement multiplyInheritedElement = overriddenExecutable;
+ List<ExecutableElement> overriddenElement = multiplyInheritedElement.inheritedElements;
+ for (int i = 0; i < overriddenElement.length; i++) {
+ if (checkForAllInvalidOverrideErrorCodes(executableElement, overriddenElement[i], parameters, parameterLocations, errorNameTarget)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ //
+ // Otherwise, just call checkForAllInvalidOverrideErrorCodes.
+ //
+ return checkForAllInvalidOverrideErrorCodes(executableElement, overriddenExecutable, parameters, parameterLocations, errorNameTarget);
+ }
+
+ /**
* This checks the passed field declaration against override-error codes.
*
* @param node the [MethodDeclaration] to evaluate
* @return `true` if and only if an error code is generated on the passed node
* @see #checkForAllInvalidOverrideErrorCodes(ExecutableElement)
*/
- bool checkForAllInvalidOverrideErrorCodes2(FieldDeclaration node) {
+ bool checkForAllInvalidOverrideErrorCodes3(FieldDeclaration node) {
if (_enclosingClass == null || node.isStatic) {
return false;
}
@@ -17488,10 +18077,10 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
PropertyAccessorElement setter = element.setter;
SimpleIdentifier fieldName = field.name;
if (getter != null) {
- hasProblems = javaBooleanOr(hasProblems, checkForAllInvalidOverrideErrorCodes(getter, ParameterElementImpl.EMPTY_ARRAY, ASTNode.EMPTY_ARRAY, fieldName));
+ hasProblems = javaBooleanOr(hasProblems, checkForAllInvalidOverrideErrorCodes2(getter, ParameterElementImpl.EMPTY_ARRAY, ASTNode.EMPTY_ARRAY, fieldName));
}
if (setter != null) {
- hasProblems = javaBooleanOr(hasProblems, checkForAllInvalidOverrideErrorCodes(setter, setter.parameters, <ASTNode> [fieldName], fieldName));
+ hasProblems = javaBooleanOr(hasProblems, checkForAllInvalidOverrideErrorCodes2(setter, setter.parameters, <ASTNode> [fieldName], fieldName));
}
}
return hasProblems;
@@ -17504,7 +18093,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
* @return `true` if and only if an error code is generated on the passed node
* @see #checkForAllInvalidOverrideErrorCodes(ExecutableElement)
*/
- bool checkForAllInvalidOverrideErrorCodes3(MethodDeclaration node) {
+ bool checkForAllInvalidOverrideErrorCodes4(MethodDeclaration node) {
if (_enclosingClass == null || node.isStatic || node.body is NativeFunctionBody) {
return false;
}
@@ -17519,7 +18108,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
FormalParameterList formalParameterList = node.parameters;
NodeList<FormalParameter> parameterList = formalParameterList != null ? formalParameterList.parameters : null;
List<ASTNode> parameters = parameterList != null ? new List.from(parameterList) : null;
- return checkForAllInvalidOverrideErrorCodes(executableElement, executableElement.parameters, parameters, methodName);
+ return checkForAllInvalidOverrideErrorCodes2(executableElement, executableElement.parameters, parameters, methodName);
}
/**
@@ -17831,7 +18420,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
return true;
}
if (variable.isFinal) {
- _errorReporter.reportError3(StaticWarningCode.ASSIGNMENT_TO_FINAL, expression, []);
+ _errorReporter.reportError3(StaticWarningCode.ASSIGNMENT_TO_FINAL, expression, [variable.name]);
return true;
}
return false;
@@ -18807,11 +19396,11 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
*/
bool checkForFieldInitializerNotAssignable(ConstructorFieldInitializer node) {
// prepare field element
- Element fieldNameElement = node.fieldName.staticElement;
- if (fieldNameElement is! FieldElement) {
+ Element staticElement = node.fieldName.staticElement;
+ if (staticElement is! FieldElement) {
return false;
}
- FieldElement fieldElement = fieldNameElement as FieldElement;
+ FieldElement fieldElement = staticElement as FieldElement;
// prepare field type
Type2 fieldType = fieldElement.type;
// prepare expression type
@@ -19214,7 +19803,13 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
return false;
}
if (!rightType.isAssignableTo(leftType)) {
- _errorReporter.reportError3(StaticTypeWarningCode.INVALID_ASSIGNMENT, node.rightHandSide, [rightType.displayName, leftType.displayName]);
+ String leftName = leftType.displayName;
+ String rightName = rightType.displayName;
+ if (leftName == rightName) {
+ leftName = getExtendedDisplayName(leftType);
+ rightName = getExtendedDisplayName(rightType);
+ }
+ _errorReporter.reportError3(StaticTypeWarningCode.INVALID_ASSIGNMENT, node.rightHandSide, [rightName, leftName]);
return true;
}
return false;
@@ -19237,7 +19832,13 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
Type2 staticRightType = getStaticType(rhs);
bool isStaticAssignable = staticRightType.isAssignableTo(leftType);
if (!isStaticAssignable) {
- _errorReporter.reportError3(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
+ String leftName = leftType.displayName;
+ String rightName = staticRightType.displayName;
+ if (leftName == rightName) {
+ leftName = getExtendedDisplayName(leftType);
+ rightName = getExtendedDisplayName(staticRightType);
+ }
+ _errorReporter.reportError3(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightName, leftName]);
return true;
}
// TODO(brianwilkerson) Define a hint corresponding to the warning and report it if appropriate.
@@ -19255,6 +19856,27 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
+ * Check the given initializer to ensure that the field being initialized is a valid field.
+ *
+ * @param node the field initializer being checked
+ */
+ void checkForInvalidField(ConstructorFieldInitializer node) {
+ SimpleIdentifier fieldName = node.fieldName;
+ Element staticElement = fieldName.staticElement;
+ if (staticElement is FieldElement) {
+ FieldElement fieldElement = staticElement;
+ if (fieldElement.isSynthetic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ } else if (fieldElement.isStatic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName]);
+ }
+ } else {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+ return;
+ }
+ }
+
+ /**
* This verifies that the usage of the passed 'this' is valid.
*
* @param node the 'this' expression to evaluate
@@ -19488,8 +20110,15 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
* @see StaticWarningCode#MIXED_RETURN_TYPES
*/
bool checkForMixedReturns(BlockFunctionBody node) {
- if (_returnWithCount > 0 && _returnWithoutCount > 0) {
- _errorReporter.reportError3(StaticWarningCode.MIXED_RETURN_TYPES, node, []);
+ int withCount = _returnsWith.length;
+ int withoutCount = _returnsWithout.length;
+ if (withCount > 0 && withoutCount > 0) {
+ for (int i = 0; i < withCount; i++) {
+ _errorReporter.reportError6(StaticWarningCode.MIXED_RETURN_TYPES, _returnsWith[i].keyword, []);
+ }
+ for (int i = 0; i < withoutCount; i++) {
+ _errorReporter.reportError6(StaticWarningCode.MIXED_RETURN_TYPES, _returnsWithout[i].keyword, []);
+ }
return true;
}
return false;
@@ -19702,8 +20331,8 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
if (memberName == null) {
break;
}
- // If the element is defined in Object, skip it.
- if ((executableElt.enclosingElement as ClassElement).type.isObject) {
+ // If the element is not synthetic and can be determined to be defined in Object, skip it.
+ if (executableElt.enclosingElement != null && (executableElt.enclosingElement as ClassElement).type.isObject) {
continue;
}
// Reference the type of the enclosing class
@@ -19747,7 +20376,12 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
List<ExecutableElement> missingOverridesArray = new List.from(missingOverrides);
List<String> stringMembersArrayListSet = new List<String>();
for (int i = 0; i < missingOverridesArray.length; i++) {
- String newStrMember = "${missingOverridesArray[i].enclosingElement.displayName}.${missingOverridesArray[i].displayName}";
+ String newStrMember;
+ if (missingOverridesArray[i].enclosingElement != null) {
+ newStrMember = "${missingOverridesArray[i].enclosingElement.displayName}.${missingOverridesArray[i].displayName}";
+ } else {
+ newStrMember = missingOverridesArray[i].displayName;
+ }
if (!stringMembersArrayListSet.contains(newStrMember)) {
stringMembersArrayListSet.add(newStrMember);
}
@@ -20533,6 +21167,36 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
return true;
}
+ void checkForValidField(FieldFormalParameter node) {
+ ParameterElement element = node.element;
+ if (element is FieldFormalParameterElement) {
+ FieldElement fieldElement = element.field;
+ if (fieldElement == null || fieldElement.isSynthetic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [node.identifier.name]);
+ } else {
+ ParameterElement parameterElement = node.element;
+ if (parameterElement is FieldFormalParameterElementImpl) {
+ FieldFormalParameterElementImpl fieldFormal = parameterElement;
+ Type2 declaredType = fieldFormal.type;
+ Type2 fieldType = fieldElement.type;
+ if (fieldElement.isSynthetic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [node.identifier.name]);
+ } else if (fieldElement.isStatic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [node.identifier.name]);
+ } else if (declaredType != null && fieldType != null && !declaredType.isAssignableTo(fieldType)) {
+ _errorReporter.reportError3(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
+ }
+ } else {
+ if (fieldElement.isSynthetic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [node.identifier.name]);
+ } else if (fieldElement.isStatic) {
+ _errorReporter.reportError3(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [node.identifier.name]);
+ }
+ }
+ }
+ }
+ }
+
/**
* This verifies the passed operator-method declaration, has correct number of parameters.
*
@@ -20660,6 +21324,24 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
+ * Return a display name for the given type that includes the path to the compilation unit in
+ * which the type is defined.
+ *
+ * @param type the type for which an extended display name is to be returned
+ * @return a display name that can help distiguish between two types with the same name
+ */
+ String getExtendedDisplayName(Type2 type) {
+ Element element = type.element;
+ if (element != null) {
+ Source source = element.source;
+ if (source != null) {
+ return "${type.displayName} (${source.fullName})";
+ }
+ }
+ return type.displayName;
+ }
+
+ /**
* Returns the Type (return type) for a given getter.
*
* @param propertyAccessorElement
@@ -20932,88 +21614,6 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
bool isUserDefinedObject(EvaluationResultImpl result) => result == null || (result is ValidResult && result.isUserDefinedObject);
-
- /**
- * Return `true` iff the passed [ClassElement] has a concrete implementation of the
- * passed accessor name in the superclass chain.
- */
- bool memberHasConcreteAccessorImplementationInSuperclassChain(ClassElement classElement, String accessorName, List<ClassElement> superclassChain) {
- if (superclassChain.contains(classElement)) {
- return false;
- } else {
- superclassChain.add(classElement);
- }
- for (PropertyAccessorElement accessor in classElement.accessors) {
- if (accessor.name == accessorName) {
- if (!accessor.isAbstract) {
- return true;
- }
- }
- }
- for (InterfaceType mixinType in classElement.mixins) {
- if (mixinType != null) {
- ClassElement mixinElement = mixinType.element;
- if (mixinElement != null) {
- for (PropertyAccessorElement accessor in mixinElement.accessors) {
- if (accessor.name == accessorName) {
- if (!accessor.isAbstract) {
- return true;
- }
- }
- }
- }
- }
- }
- InterfaceType superType = classElement.supertype;
- if (superType != null) {
- ClassElement superClassElt = superType.element;
- if (superClassElt != null) {
- return memberHasConcreteAccessorImplementationInSuperclassChain(superClassElt, accessorName, superclassChain);
- }
- }
- return false;
- }
-
- /**
- * Return `true` iff the passed [ClassElement] has a concrete implementation of the
- * passed method name in the superclass chain.
- */
- bool memberHasConcreteMethodImplementationInSuperclassChain(ClassElement classElement, String methodName, List<ClassElement> superclassChain) {
- if (superclassChain.contains(classElement)) {
- return false;
- } else {
- superclassChain.add(classElement);
- }
- for (MethodElement method in classElement.methods) {
- if (method.name == methodName) {
- if (!method.isAbstract) {
- return true;
- }
- }
- }
- for (InterfaceType mixinType in classElement.mixins) {
- if (mixinType != null) {
- ClassElement mixinElement = mixinType.element;
- if (mixinElement != null) {
- for (MethodElement method in mixinElement.methods) {
- if (method.name == methodName) {
- if (!method.isAbstract) {
- return true;
- }
- }
- }
- }
- }
- }
- InterfaceType superType = classElement.supertype;
- if (superType != null) {
- ClassElement superClassElt = superType.element;
- if (superClassElt != null) {
- return memberHasConcreteMethodImplementationInSuperclassChain(superClassElt, methodName, superclassChain);
- }
- }
- return false;
- }
}
/**

Powered by Google App Engine
This is Rietveld 408576698