| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library analyzer.src.dart.constant.utilities; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/visitor.dart'; |
| 11 import 'package:analyzer/dart/element/element.dart'; |
| 12 import 'package:analyzer/src/dart/ast/utilities.dart'; |
| 13 import 'package:analyzer/src/dart/element/element.dart'; |
| 14 import 'package:analyzer/src/dart/element/handle.dart' |
| 15 show ConstructorElementHandle; |
| 16 import 'package:analyzer/src/dart/element/member.dart'; |
| 17 import 'package:analyzer/src/generated/engine.dart'; |
| 18 import 'package:analyzer/src/generated/source.dart' show Source; |
| 19 import 'package:analyzer/src/task/dart.dart'; |
| 20 |
| 21 ConstructorElementImpl getConstructorImpl(ConstructorElement constructor) { |
| 22 while (constructor is ConstructorMember) { |
| 23 constructor = (constructor as ConstructorMember).baseElement; |
| 24 } |
| 25 if (constructor is ConstructorElementHandle) { |
| 26 constructor = (constructor as ConstructorElementHandle).actualElement; |
| 27 } |
| 28 return constructor; |
| 29 } |
| 30 |
| 31 /** |
| 32 * Callback used by [ReferenceFinder] to report that a dependency was found. |
| 33 */ |
| 34 typedef void ReferenceFinderCallback(ConstantEvaluationTarget dependency); |
| 35 |
| 36 /** |
| 37 * An [AstCloner] that copies the necessary information from the AST to allow |
| 38 * constants to be evaluated. |
| 39 */ |
| 40 class ConstantAstCloner extends AstCloner { |
| 41 ConstantAstCloner() : super(true); |
| 42 |
| 43 @override |
| 44 ConstructorName visitConstructorName(ConstructorName node) { |
| 45 ConstructorName name = super.visitConstructorName(node); |
| 46 name.staticElement = node.staticElement; |
| 47 return name; |
| 48 } |
| 49 |
| 50 @override |
| 51 InstanceCreationExpression visitInstanceCreationExpression( |
| 52 InstanceCreationExpression node) { |
| 53 InstanceCreationExpression expression = |
| 54 super.visitInstanceCreationExpression(node); |
| 55 expression.staticElement = node.staticElement; |
| 56 return expression; |
| 57 } |
| 58 |
| 59 @override |
| 60 RedirectingConstructorInvocation visitRedirectingConstructorInvocation( |
| 61 RedirectingConstructorInvocation node) { |
| 62 RedirectingConstructorInvocation invocation = |
| 63 super.visitRedirectingConstructorInvocation(node); |
| 64 invocation.staticElement = node.staticElement; |
| 65 return invocation; |
| 66 } |
| 67 |
| 68 @override |
| 69 SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) { |
| 70 SimpleIdentifier identifier = super.visitSimpleIdentifier(node); |
| 71 identifier.staticElement = node.staticElement; |
| 72 return identifier; |
| 73 } |
| 74 |
| 75 @override |
| 76 SuperConstructorInvocation visitSuperConstructorInvocation( |
| 77 SuperConstructorInvocation node) { |
| 78 SuperConstructorInvocation invocation = |
| 79 super.visitSuperConstructorInvocation(node); |
| 80 invocation.staticElement = node.staticElement; |
| 81 return invocation; |
| 82 } |
| 83 |
| 84 @override |
| 85 TypeName visitTypeName(TypeName node) { |
| 86 TypeName typeName = super.visitTypeName(node); |
| 87 typeName.type = node.type; |
| 88 return typeName; |
| 89 } |
| 90 } |
| 91 |
| 92 /** |
| 93 * A visitor used to traverse the AST structures of all of the compilation units |
| 94 * being resolved and build the full set of dependencies for all constant |
| 95 * expressions. |
| 96 */ |
| 97 class ConstantExpressionsDependenciesFinder extends RecursiveAstVisitor { |
| 98 /** |
| 99 * The constants whose values need to be computed. |
| 100 */ |
| 101 HashSet<ConstantEvaluationTarget> dependencies = |
| 102 new HashSet<ConstantEvaluationTarget>(); |
| 103 |
| 104 @override |
| 105 void visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 106 if (node.isConst) { |
| 107 _find(node); |
| 108 } else { |
| 109 super.visitInstanceCreationExpression(node); |
| 110 } |
| 111 } |
| 112 |
| 113 @override |
| 114 void visitListLiteral(ListLiteral node) { |
| 115 if (node.constKeyword != null) { |
| 116 _find(node); |
| 117 } else { |
| 118 super.visitListLiteral(node); |
| 119 } |
| 120 } |
| 121 |
| 122 @override |
| 123 void visitMapLiteral(MapLiteral node) { |
| 124 if (node.constKeyword != null) { |
| 125 _find(node); |
| 126 } else { |
| 127 super.visitMapLiteral(node); |
| 128 } |
| 129 } |
| 130 |
| 131 @override |
| 132 void visitSwitchCase(SwitchCase node) { |
| 133 _find(node.expression); |
| 134 node.statements.accept(this); |
| 135 } |
| 136 |
| 137 void _find(Expression node) { |
| 138 if (node != null) { |
| 139 ReferenceFinder referenceFinder = new ReferenceFinder(dependencies.add); |
| 140 node.accept(referenceFinder); |
| 141 } |
| 142 } |
| 143 } |
| 144 |
| 145 /** |
| 146 * A visitor used to traverse the AST structures of all of the compilation units |
| 147 * being resolved and build tables of the constant variables, constant |
| 148 * constructors, constant constructor invocations, and annotations found in |
| 149 * those compilation units. |
| 150 */ |
| 151 class ConstantFinder extends RecursiveAstVisitor<Object> { |
| 152 final AnalysisContext context; |
| 153 final Source source; |
| 154 final Source librarySource; |
| 155 |
| 156 /** |
| 157 * The elements and AST nodes whose constant values need to be computed. |
| 158 */ |
| 159 List<ConstantEvaluationTarget> constantsToCompute = |
| 160 <ConstantEvaluationTarget>[]; |
| 161 |
| 162 /** |
| 163 * A flag indicating whether instance variables marked as "final" should be |
| 164 * treated as "const". |
| 165 */ |
| 166 bool treatFinalInstanceVarAsConst = false; |
| 167 |
| 168 ConstantFinder(this.context, this.source, this.librarySource); |
| 169 |
| 170 @override |
| 171 Object visitAnnotation(Annotation node) { |
| 172 super.visitAnnotation(node); |
| 173 ElementAnnotation elementAnnotation = node.elementAnnotation; |
| 174 if (elementAnnotation == null) { |
| 175 // Analyzer ignores annotations on "part of" directives. |
| 176 assert(node.parent is PartOfDirective); |
| 177 } else { |
| 178 constantsToCompute.add(elementAnnotation); |
| 179 } |
| 180 return null; |
| 181 } |
| 182 |
| 183 @override |
| 184 Object visitClassDeclaration(ClassDeclaration node) { |
| 185 bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst; |
| 186 if (node.element.constructors.any((ConstructorElement e) => e.isConst)) { |
| 187 // Instance vars marked "final" need to be included in the dependency |
| 188 // graph, since constant constructors implicitly use the values in their |
| 189 // initializers. |
| 190 treatFinalInstanceVarAsConst = true; |
| 191 } |
| 192 try { |
| 193 return super.visitClassDeclaration(node); |
| 194 } finally { |
| 195 treatFinalInstanceVarAsConst = prevTreatFinalInstanceVarAsConst; |
| 196 } |
| 197 } |
| 198 |
| 199 @override |
| 200 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 201 super.visitConstructorDeclaration(node); |
| 202 if (node.constKeyword != null) { |
| 203 ConstructorElement element = node.element; |
| 204 if (element != null) { |
| 205 constantsToCompute.add(element); |
| 206 constantsToCompute.addAll(element.parameters); |
| 207 } |
| 208 } |
| 209 return null; |
| 210 } |
| 211 |
| 212 @override |
| 213 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 214 super.visitDefaultFormalParameter(node); |
| 215 Expression defaultValue = node.defaultValue; |
| 216 if (defaultValue != null && node.element != null) { |
| 217 constantsToCompute.add(node.element); |
| 218 } |
| 219 return null; |
| 220 } |
| 221 |
| 222 @override |
| 223 Object visitVariableDeclaration(VariableDeclaration node) { |
| 224 super.visitVariableDeclaration(node); |
| 225 Expression initializer = node.initializer; |
| 226 VariableElement element = node.element; |
| 227 if (initializer != null && |
| 228 (node.isConst || |
| 229 treatFinalInstanceVarAsConst && |
| 230 element is FieldElement && |
| 231 node.isFinal && |
| 232 !element.isStatic)) { |
| 233 if (element != null) { |
| 234 constantsToCompute.add(element); |
| 235 } |
| 236 } |
| 237 return null; |
| 238 } |
| 239 } |
| 240 |
| 241 /** |
| 242 * An object used to add reference information for a given variable to the |
| 243 * bi-directional mapping used to order the evaluation of constants. |
| 244 */ |
| 245 class ReferenceFinder extends RecursiveAstVisitor<Object> { |
| 246 /** |
| 247 * The callback which should be used to report any dependencies that were |
| 248 * found. |
| 249 */ |
| 250 final ReferenceFinderCallback _callback; |
| 251 |
| 252 /** |
| 253 * Initialize a newly created reference finder to find references from a given |
| 254 * variable to other variables and to add those references to the given graph. |
| 255 * The [_callback] will be invoked for every dependency found. |
| 256 */ |
| 257 ReferenceFinder(this._callback); |
| 258 |
| 259 @override |
| 260 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 261 if (node.isConst) { |
| 262 ConstructorElement constructor = getConstructorImpl(node.staticElement); |
| 263 if (constructor != null) { |
| 264 _callback(constructor); |
| 265 } |
| 266 } |
| 267 return super.visitInstanceCreationExpression(node); |
| 268 } |
| 269 |
| 270 @override |
| 271 Object visitLabel(Label node) { |
| 272 // We are visiting the "label" part of a named expression in a function |
| 273 // call (presumably a constructor call), e.g. "const C(label: ...)". We |
| 274 // don't want to visit the SimpleIdentifier for the label because that's a |
| 275 // reference to a function parameter that needs to be filled in; it's not a |
| 276 // constant whose value we depend on. |
| 277 return null; |
| 278 } |
| 279 |
| 280 @override |
| 281 Object visitRedirectingConstructorInvocation( |
| 282 RedirectingConstructorInvocation node) { |
| 283 super.visitRedirectingConstructorInvocation(node); |
| 284 ConstructorElement target = getConstructorImpl(node.staticElement); |
| 285 if (target != null) { |
| 286 _callback(target); |
| 287 } |
| 288 return null; |
| 289 } |
| 290 |
| 291 @override |
| 292 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 293 Element element = node.staticElement; |
| 294 if (element is PropertyAccessorElement) { |
| 295 element = (element as PropertyAccessorElement).variable; |
| 296 } |
| 297 if (element is VariableElement && element.isConst) { |
| 298 _callback(element); |
| 299 } |
| 300 return null; |
| 301 } |
| 302 |
| 303 @override |
| 304 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 305 super.visitSuperConstructorInvocation(node); |
| 306 ConstructorElement constructor = getConstructorImpl(node.staticElement); |
| 307 if (constructor != null) { |
| 308 _callback(constructor); |
| 309 } |
| 310 return null; |
| 311 } |
| 312 } |
| OLD | NEW |