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