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