| OLD | NEW |
| 1 library di.generator; | 1 library di.generator; |
| 2 | 2 |
| 3 import 'package:analyzer/src/generated/java_io.dart'; | 3 import 'package:analyzer/src/generated/java_io.dart'; |
| 4 import 'package:analyzer/src/generated/source_io.dart'; | 4 import 'package:analyzer/src/generated/source_io.dart'; |
| 5 import 'package:analyzer/src/generated/ast.dart'; | 5 import 'package:analyzer/src/generated/ast.dart'; |
| 6 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; | 6 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; |
| 7 import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk; | 7 import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk; |
| 8 import 'package:analyzer/src/generated/element.dart'; | 8 import 'package:analyzer/src/generated/element.dart'; |
| 9 import 'package:analyzer/src/generated/engine.dart'; | 9 import 'package:analyzer/src/generated/engine.dart'; |
| 10 import 'package:path/path.dart' as path; | |
| 11 | 10 |
| 12 import 'dart:io'; | 11 import 'dart:io'; |
| 13 | 12 |
| 14 const String PACKAGE_PREFIX = 'package:'; | 13 const String PACKAGE_PREFIX = 'package:'; |
| 15 const String DART_PACKAGE_PREFIX = 'dart:'; | 14 const String DART_PACKAGE_PREFIX = 'dart:'; |
| 16 const List<String> _DEFAULT_INJECTABLE_ANNOTATIONS = | |
| 17 const ['di.annotations.Injectable']; | |
| 18 | 15 |
| 19 main(List<String> args) { | 16 main(args) { |
| 20 if (args.length < 4) { | 17 if (args.length < 4) { |
| 21 print('Usage: generator path_to_sdk file_to_resolve annotations output [pack
age_roots+]'); | 18 print('Usage: generator path_to_sdk file_to_resolve annotations output [pack
age_roots+]'); |
| 22 exit(0); | 19 exit(0); |
| 23 } | 20 } |
| 24 | 21 |
| 25 var pathToSdk = args[0]; | 22 var pathToSdk = args[0]; |
| 26 var entryPoint = args[1]; | 23 var entryPoint = args[1]; |
| 27 var classAnnotations = args[2].split(',') | 24 var classAnnotations = args[2].split(','); |
| 28 ..addAll(_DEFAULT_INJECTABLE_ANNOTATIONS); | |
| 29 var output = args[3]; | 25 var output = args[3]; |
| 30 var packageRoots = (args.length < 5) ? [Platform.packageRoot] : args.sublist(4
); | 26 var packageRoots = (args.length < 5) ? [Platform.packageRoot] : args.sublist(4
); |
| 31 | 27 |
| 32 print('pathToSdk: $pathToSdk'); | 28 print('pathToSdk: $pathToSdk'); |
| 33 print('entryPoint: $entryPoint'); | 29 print('entryPoint: $entryPoint'); |
| 34 print('classAnnotations: ${classAnnotations.join(', ')}'); | 30 print('classAnnotations: ${classAnnotations.join(', ')}'); |
| 35 print('output: $output'); | 31 print('output: $output'); |
| 36 print('packageRoots: $packageRoots'); | 32 print('packageRoots: $packageRoots'); |
| 37 | 33 |
| 38 var code = generateCode(entryPoint, classAnnotations, pathToSdk, packageRoots,
output); | 34 var code = generateCode(entryPoint, classAnnotations, pathToSdk, packageRoots)
; |
| 39 code.forEach((chunk, code) { | 35 code.forEach((chunk, code) { |
| 40 String fileName = output; | 36 String fileName = output; |
| 41 if (chunk.library != null) { | 37 if (chunk.library != null) { |
| 42 var lastDot = fileName.lastIndexOf('.'); | 38 var lastDot = fileName.lastIndexOf('.'); |
| 43 fileName = fileName.substring(0, lastDot) + '-' + chunk.library.name + fil
eName.substring(lastDot); | 39 fileName = fileName.substring(0, lastDot) + '-' + chunk.library.name + fil
eName.substring(lastDot); |
| 44 } | 40 } |
| 45 new File(fileName).writeAsStringSync(code); | 41 new File(fileName).writeAsStringSync(code); |
| 46 }); | 42 }); |
| 47 } | 43 } |
| 48 | 44 |
| 49 Map<Chunk, String> generateCode(String entryPoint, List<String> classAnnotations
, | 45 Map<Chunk, String> generateCode(String entryPoint, List<String> classAnnotations
, |
| 50 String pathToSdk, List<String> packageRoots, String outputFilename) { | 46 String pathToSdk, List<String> packageRoots) { |
| 51 var c = new SourceCrawler(pathToSdk, packageRoots); | 47 var c = new SourceCrawler(pathToSdk, packageRoots); |
| 52 List<String> imports = <String>[]; | 48 List<String> imports = <String>[]; |
| 53 Map<Chunk, List<ClassElement>> typeFactoryTypes = <Chunk, List<ClassElement>>{
}; | 49 Map<Chunk, List<ClassElement>> typeFactoryTypes = <Chunk, List<ClassElement>>{
}; |
| 54 Map<String, String> typeToImport = new Map<String, String>(); | 50 Map<String, String> typeToImport = new Map<String, String>(); |
| 55 c.crawl(entryPoint, (CompilationUnitElement compilationUnit, SourceFile source
) { | 51 c.crawl(entryPoint, (CompilationUnitElement compilationUnit, SourceFile source
) { |
| 56 new CompilationUnitVisitor(c.context, source, classAnnotations, imports, | 52 new CompilationUnitVisitor(c.context, source, classAnnotations, imports, |
| 57 typeToImport, typeFactoryTypes, outputFilename).visit(compilationUnit,
source); | 53 typeToImport, typeFactoryTypes).visit(compilationUnit, source); |
| 58 }); | 54 }); |
| 59 return printLibraryCode(typeToImport, imports, typeFactoryTypes); | 55 return printLibraryCode(typeToImport, imports, typeFactoryTypes); |
| 60 } | 56 } |
| 61 | 57 |
| 62 Map<Chunk, String> printLibraryCode(Map<String, String> typeToImport, | 58 Map<Chunk, String> printLibraryCode(Map<String, String> typeToImport, |
| 63 List<String> imports, Map<Chunk, List<ClassElement>> typeFactoryTypes) { | 59 List<String> imports, Map<Chunk, List<ClassElement>> typeFactoryTypes) { |
| 64 Map<Chunk, StringBuffer> factories = <Chunk, StringBuffer>{}; | 60 Map<Chunk, StringBuffer> factories = <Chunk, StringBuffer>{}; |
| 65 Map<Chunk, String> result = <Chunk, String>{}; | 61 Map<Chunk, String> result = <Chunk, String>{}; |
| 66 typeFactoryTypes.forEach((Chunk chunk, List<ClassElement> classes) { | 62 typeFactoryTypes.forEach((Chunk chunk, List<ClassElement> classes) { |
| 67 List<String> requiredImports = <String>[]; | 63 List<String> requiredImports = <String>[]; |
| 68 String resolveClassIdentifier(InterfaceType type) { | 64 String resolveClassIdentifier(InterfaceType type) { |
| 69 if (type.element.library.isDartCore) { | 65 if (type.element.library.isDartCore) { |
| 70 return type.name; | 66 return type.name; |
| 71 } | 67 } |
| 72 String import = typeToImport[getCanonicalName(type)]; | 68 String import = typeToImport[getCanonicalName(type)]; |
| 73 if (!requiredImports.contains(import)) { | 69 if (!requiredImports.contains(import)) { |
| 74 requiredImports.add(import); | 70 requiredImports.add(import); |
| 75 } | 71 } |
| 76 String prefix = _calculateImportPrefix(import, imports); | 72 return 'import_${imports.indexOf(import)}.${type.name}'; |
| 77 return '$prefix.${type.name}'; | |
| 78 } | 73 } |
| 79 factories[chunk] = new StringBuffer(); | 74 factories[chunk] = new StringBuffer(); |
| 80 classes.forEach((ClassElement clazz) { | 75 classes.forEach((ClassElement clazz) { |
| 81 StringBuffer factory = new StringBuffer(); | 76 StringBuffer factory = new StringBuffer(); |
| 82 bool skip = false; | 77 bool skip = false; |
| 83 factory.write('${resolveClassIdentifier(clazz.type)}: (f) => '); | 78 factory.write( |
| 79 '${resolveClassIdentifier(clazz.type)}: (f) => '); |
| 84 factory.write('new ${resolveClassIdentifier(clazz.type)}('); | 80 factory.write('new ${resolveClassIdentifier(clazz.type)}('); |
| 85 ConstructorElement constr = | 81 ConstructorElement constr = |
| 86 clazz.constructors.firstWhere((c) => c.name.isEmpty, | 82 clazz.constructors.firstWhere((c) => c.name.isEmpty, |
| 87 orElse: () { | 83 orElse: () { |
| 88 throw 'Unable to find default constructor for ' | 84 throw 'Unable to find default constructor for $clazz in ${clazz.sour
ce}'; |
| 89 '$clazz in ${clazz.source}'; | |
| 90 }); | 85 }); |
| 91 factory.write(constr.parameters.map((param) { | 86 factory.write(constr.parameters.map((param) { |
| 92 if (param.type.element is! ClassElement) { | 87 if (param.type.element is! ClassElement) { |
| 93 throw 'Unable to resolve type for constructor parameter ' | 88 throw 'Unable to resolve type for constructor parameter ' |
| 94 '"${param.name}" for type "$clazz" in ${clazz.source}'; | 89 '"${param.name}" for type "$clazz" in ${clazz.source}'; |
| 95 } | 90 } |
| 96 if (_isParameterized(param)) { | 91 if (_isParameterized(param)) { |
| 97 print('WARNING: parameterized types are not supported: ' | 92 print('WARNING: parameterized types are not supported: $param in $claz
z in ${clazz.source}. Skipping!'); |
| 98 '$param in $clazz in ${clazz.source}. Skipping!'); | |
| 99 skip = true; | 93 skip = true; |
| 100 } | 94 } |
| 101 var annotations = []; | 95 return 'f(${resolveClassIdentifier(param.type)})'; |
| 102 if (param.metadata.isNotEmpty) { | |
| 103 annotations = param.metadata.map( | |
| 104 (item) => resolveClassIdentifier(item.element.returnType)); | |
| 105 } | |
| 106 StringBuffer output = | |
| 107 new StringBuffer('f(${resolveClassIdentifier(param.type)}'); | |
| 108 if (annotations.isNotEmpty) { | |
| 109 output.write(', ${annotations.first}'); | |
| 110 } | |
| 111 output.write(')'); | |
| 112 return output; | |
| 113 }).join(', ')); | 96 }).join(', ')); |
| 114 factory.write('),\n'); | 97 factory.write('),\n'); |
| 115 if (!skip) { | 98 if (!skip) { |
| 116 factories[chunk].write(factory); | 99 factories[chunk].write(factory); |
| 117 } | 100 } |
| 118 }); | 101 }); |
| 119 StringBuffer code = new StringBuffer(); | 102 StringBuffer code = new StringBuffer(); |
| 120 String libSuffix = chunk.library == null ? '' : '.${chunk.library.name}'; | 103 String libSuffix = chunk.library == null ? '' : '.${chunk.library.name}'; |
| 121 code.write('library di.generated.type_factories$libSuffix;\n'); | 104 code.write('library di.generated.type_factories$libSuffix;\n'); |
| 122 requiredImports.forEach((import) { | 105 requiredImports.forEach((import) { |
| 123 String prefix = _calculateImportPrefix(import, imports); | 106 code.write ('import "$import" as import_${imports.indexOf(import)};\n'); |
| 124 code.write ('import "$import" as $prefix;\n'); | |
| 125 }); | 107 }); |
| 126 code..write('var typeFactories = {\n${factories[chunk]}\n};\n') | 108 code..write('var typeFactories = {\n${factories[chunk]}\n};\n') |
| 127 ..write('main() {}\n'); | 109 ..write('main() {}\n'); |
| 128 result[chunk] = code.toString(); | 110 result[chunk] = code.toString(); |
| 129 }); | 111 }); |
| 130 | 112 |
| 131 return result; | 113 return result; |
| 132 } | 114 } |
| 133 | 115 |
| 134 String _calculateImportPrefix(String import, List<String> imports) => | |
| 135 'import_${imports.indexOf(import)}'; | |
| 136 | |
| 137 _isParameterized(ParameterElement param) { | 116 _isParameterized(ParameterElement param) { |
| 138 String typeName = param.type.toString(); | 117 String typeName = param.type.toString(); |
| 139 | 118 |
| 140 if (typeName.indexOf('<') > -1) { | 119 if (typeName.indexOf('<') > -1) { |
| 141 String parameters = | 120 String parameters = |
| 142 typeName.substring(typeName.indexOf('<') + 1, typeName.length - 1); | 121 typeName.substring(typeName.indexOf('<') + 1, typeName.length - 1); |
| 143 return parameters.split(', ').any((p) => p != 'dynamic'); | 122 return parameters.split(', ').any((p) => p != 'dynamic'); |
| 144 } | 123 } |
| 145 return false; | 124 return false; |
| 146 } | 125 } |
| 147 | 126 |
| 148 class CompilationUnitVisitor { | 127 class CompilationUnitVisitor { |
| 149 List<String> imports; | 128 List<String> imports; |
| 150 Map<String, String> typeToImport; | 129 Map<String, String> typeToImport; |
| 151 Map<Chunk, List<ClassElement>> typeFactoryTypes; | 130 Map<Chunk, List<ClassElement>> typeFactoryTypes; |
| 152 List<String> classAnnotations; | 131 List<String> classAnnotations; |
| 153 SourceFile source; | 132 SourceFile source; |
| 154 AnalysisContext context; | 133 AnalysisContext context; |
| 155 String outputFilename; | |
| 156 | 134 |
| 157 CompilationUnitVisitor(this.context, this.source, | 135 CompilationUnitVisitor(this.context, this.source, |
| 158 this.classAnnotations, this.imports, this.typeToImport, | 136 this.classAnnotations, this.imports, this.typeToImport, |
| 159 this.typeFactoryTypes, this.outputFilename); | 137 this.typeFactoryTypes); |
| 160 | 138 |
| 161 visit(CompilationUnitElement compilationUnit, SourceFile source) { | 139 visit(CompilationUnitElement compilationUnit, SourceFile source) { |
| 162 if (typeFactoryTypes[source.chunk] == null) { | |
| 163 typeFactoryTypes[source.chunk] = <ClassElement>[]; | |
| 164 } | |
| 165 visitLibrary(compilationUnit.enclosingElement, source); | 140 visitLibrary(compilationUnit.enclosingElement, source); |
| 166 | 141 |
| 167 List<ClassElement> types = <ClassElement>[]; | 142 List<ClassElement> types = <ClassElement>[]; |
| 168 types.addAll(compilationUnit.types); | 143 types.addAll(compilationUnit.types); |
| 169 | 144 |
| 170 for (CompilationUnitElement part in compilationUnit.enclosingElement.parts)
{ | 145 for (CompilationUnitElement part in compilationUnit.enclosingElement.parts)
{ |
| 171 types.addAll(part.types); | 146 types.addAll(part.types); |
| 172 } | 147 } |
| 173 | 148 |
| 174 types.forEach((clazz) => visitClassElement(clazz, source)); | 149 types.forEach((clazz) => visitClassElement(clazz, source)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 188 (ann.element as ConstructorElement).enclosingElement.type) == | 163 (ann.element as ConstructorElement).enclosingElement.type) == |
| 189 'di.annotations.Injectables') { | 164 'di.annotations.Injectables') { |
| 190 var listLiteral = | 165 var listLiteral = |
| 191 library.metadata[annotationIdx].arguments.arguments.first; | 166 library.metadata[annotationIdx].arguments.arguments.first; |
| 192 for (Expression expr in listLiteral.elements) { | 167 for (Expression expr in listLiteral.elements) { |
| 193 Element element = (expr as SimpleIdentifier).bestElement; | 168 Element element = (expr as SimpleIdentifier).bestElement; |
| 194 if (element == null || element is! ClassElement) { | 169 if (element == null || element is! ClassElement) { |
| 195 throw 'Unable to resolve type "$expr" from @Injectables ' | 170 throw 'Unable to resolve type "$expr" from @Injectables ' |
| 196 'in ${library.element.source}'; | 171 'in ${library.element.source}'; |
| 197 } | 172 } |
| 173 if (typeFactoryTypes[source.chunk] == null) { |
| 174 typeFactoryTypes[source.chunk] = <ClassElement>[]; |
| 175 } |
| 198 if (!typeFactoryTypes[source.chunk].contains(element)) { | 176 if (!typeFactoryTypes[source.chunk].contains(element)) { |
| 199 typeFactoryTypes[source.chunk].add(element as ClassElement); | 177 typeFactoryTypes[source.chunk].add(element as ClassElement); |
| 200 } | 178 } |
| 201 } | 179 } |
| 202 } | 180 } |
| 203 annotationIdx++; | 181 annotationIdx++; |
| 204 }); | 182 }); |
| 205 } | 183 } |
| 206 }); | 184 }); |
| 207 } | 185 } |
| 208 | 186 |
| 209 visitClassElement(ClassElement classElement, SourceFile source) { | 187 visitClassElement(ClassElement classElement, SourceFile source) { |
| 210 if (classElement.name.startsWith('_')) { | 188 if (classElement.name.startsWith('_')) { |
| 211 return; // ignore private classes. | 189 return; // ignore private classes. |
| 212 } | 190 } |
| 213 var importUri = source.entryPointImport; | 191 typeToImport[getCanonicalName(classElement.type)] = |
| 214 if (Uri.parse(importUri).scheme == '') { | 192 source.entryPointImport; |
| 215 importUri = path.relative(importUri, from: path.dirname(outputFilename)); | 193 if (!imports.contains(source.entryPointImport)) { |
| 216 } | 194 imports.add(source.entryPointImport); |
| 217 typeToImport[getCanonicalName(classElement.type)] = importUri; | |
| 218 if (!imports.contains(importUri)) { | |
| 219 imports.add(importUri); | |
| 220 } | 195 } |
| 221 for (ElementAnnotation ann in classElement.metadata) { | 196 for (ElementAnnotation ann in classElement.metadata) { |
| 222 if (ann.element is ConstructorElement) { | 197 if (ann.element is ConstructorElement) { |
| 223 ConstructorElement con = ann.element; | 198 ConstructorElement con = ann.element; |
| 224 if (classAnnotations | 199 if (classAnnotations |
| 225 .contains(getQualifiedName(con.enclosingElement.type))) { | 200 .contains(getQualifiedName(con.enclosingElement.type))) { |
| 226 if (typeFactoryTypes[source.chunk] == null) { | 201 if (typeFactoryTypes[source.chunk] == null) { |
| 227 typeFactoryTypes[source.chunk] = <ClassElement>[]; | 202 typeFactoryTypes[source.chunk] = <ClassElement>[]; |
| 228 } | 203 } |
| 229 if (!typeFactoryTypes[source.chunk].contains(classElement)) { | 204 if (!typeFactoryTypes[source.chunk].contains(classElement)) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 250 typedef CompilationUnitCrawler(CompilationUnitElement compilationUnit, | 225 typedef CompilationUnitCrawler(CompilationUnitElement compilationUnit, |
| 251 SourceFile source); | 226 SourceFile source); |
| 252 | 227 |
| 253 class SourceCrawler { | 228 class SourceCrawler { |
| 254 final List<String> packageRoots; | 229 final List<String> packageRoots; |
| 255 final String sdkPath; | 230 final String sdkPath; |
| 256 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); | 231 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); |
| 257 | 232 |
| 258 SourceCrawler(this.sdkPath, this.packageRoots); | 233 SourceCrawler(this.sdkPath, this.packageRoots); |
| 259 | 234 |
| 260 void crawl(String entryPoint, CompilationUnitCrawler _visitor, | 235 void crawl(String entryPoint, CompilationUnitCrawler _visitor) { |
| 261 {bool preserveComments : false}) { | |
| 262 JavaSystemIO.setProperty("com.google.dart.sdk", sdkPath); | 236 JavaSystemIO.setProperty("com.google.dart.sdk", sdkPath); |
| 263 DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; | 237 DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; |
| 264 | 238 |
| 265 AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl(); | 239 AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl(); |
| 266 contextOptions.cacheSize = 256; | 240 contextOptions.cacheSize = 256; |
| 267 contextOptions.preserveComments = preserveComments; | 241 contextOptions.preserveComments = false; |
| 268 contextOptions.analyzeFunctionBodies = false; | 242 contextOptions.analyzeFunctionBodies = false; |
| 269 context.analysisOptions = contextOptions; | 243 context.analysisOptions = contextOptions; |
| 270 sdk.context.analysisOptions = contextOptions; | 244 sdk.context.analysisOptions = contextOptions; |
| 271 | 245 |
| 272 var packageUriResolver = | 246 var packageUriResolver = |
| 273 new PackageUriResolver(packageRoots.map( | 247 new PackageUriResolver(packageRoots.map( |
| 274 (pr) => new JavaFile.fromUri(new Uri.file(pr))).toList()); | 248 (pr) => new JavaFile.fromUri(new Uri.file(pr))).toList()); |
| 275 context.sourceFactory = new SourceFactory([ | 249 context.sourceFactory = new SourceFactory.con2([ |
| 276 new DartUriResolver(sdk), | 250 new DartUriResolver(sdk), |
| 277 new FileUriResolver(), | 251 new FileUriResolver(), |
| 278 packageUriResolver | 252 packageUriResolver |
| 279 ]); | 253 ]); |
| 280 | 254 |
| 281 var entryPointFile; | 255 var entryPointFile; |
| 282 var entryPointImport; | 256 var entryPointImport; |
| 283 if (entryPoint.startsWith(PACKAGE_PREFIX)) { | 257 if (entryPoint.startsWith(PACKAGE_PREFIX)) { |
| 284 entryPointFile = new JavaFile(packageUriResolver | 258 entryPointFile = new JavaFile(packageUriResolver |
| 285 .resolveAbsolute(Uri.parse(entryPoint)).toString()); | 259 .resolveAbsolute(context.sourceFactory.contentCache, |
| 260 Uri.parse(entryPoint)).toString()); |
| 286 entryPointImport = entryPoint; | 261 entryPointImport = entryPoint; |
| 287 } else { | 262 } else { |
| 288 entryPointFile = new JavaFile(entryPoint); | 263 entryPointFile = new JavaFile(entryPoint); |
| 289 entryPointImport = entryPointFile.getAbsolutePath(); | 264 entryPointImport = entryPointFile.getAbsolutePath(); |
| 290 } | 265 } |
| 291 | 266 |
| 292 Source source = new FileBasedSource.con1(entryPointFile); | 267 Source source = new FileBasedSource.con1( |
| 268 context.sourceFactory.contentCache, entryPointFile); |
| 293 ChangeSet changeSet = new ChangeSet(); | 269 ChangeSet changeSet = new ChangeSet(); |
| 294 changeSet.addedSource(source); | 270 changeSet.added(source); |
| 295 context.applyChanges(changeSet); | 271 context.applyChanges(changeSet); |
| 296 LibraryElement rootLib = context.computeLibraryElement(source); | 272 LibraryElement rootLib = context.computeLibraryElement(source); |
| 297 CompilationUnit resolvedUnit = | 273 CompilationUnit resolvedUnit = |
| 298 context.resolveCompilationUnit(source, rootLib); | 274 context.resolveCompilationUnit(source, rootLib); |
| 299 | 275 |
| 300 var sourceFile = new SourceFile( | 276 var sourceFile = new SourceFile( |
| 301 entryPointFile.getAbsolutePath(), | 277 entryPointFile.getAbsolutePath(), |
| 302 entryPointImport, | 278 entryPointImport, |
| 303 resolvedUnit, | 279 resolvedUnit, |
| 304 resolvedUnit.element, | 280 resolvedUnit.element, |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 | 466 |
| 491 SourceFile(this.canonicalPath, this.entryPointImport, this.compilationUnit, | 467 SourceFile(this.canonicalPath, this.entryPointImport, this.compilationUnit, |
| 492 this.compilationUnitElement, this.chunk); | 468 this.compilationUnitElement, this.chunk); |
| 493 | 469 |
| 494 operator ==(o) { | 470 operator ==(o) { |
| 495 if (o is String) return o == canonicalPath; | 471 if (o is String) return o == canonicalPath; |
| 496 if (o is! SourceFile) return false; | 472 if (o is! SourceFile) return false; |
| 497 return o.canonicalPath == canonicalPath; | 473 return o.canonicalPath == canonicalPath; |
| 498 } | 474 } |
| 499 } | 475 } |
| OLD | NEW |