Chromium Code Reviews| Index: pkg/compiler/lib/src/compiler.dart |
| diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart |
| index c60a44cc268c589ed69d451c89caa30e17a00e85..772b03670a533030e497c0bfdd9071a475287ee0 100644 |
| --- a/pkg/compiler/lib/src/compiler.dart |
| +++ b/pkg/compiler/lib/src/compiler.dart |
| @@ -428,7 +428,7 @@ abstract class Backend { |
| /// This method is called when all new libraries loaded through |
| /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports |
| /// have been computed. |
| - Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) { |
| + Future onLibrariesLoaded(LoadedLibraries loadedLibraries) { |
| return new Future.value(); |
| } |
| @@ -921,6 +921,7 @@ abstract class Compiler implements DiagnosticListener { |
| bool enabledFunctionApply = false; |
| bool enabledInvokeOn = false; |
| bool hasIsolateSupport = false; |
| + final bool enableExperimentalMirrors; |
| Stopwatch progress; |
| @@ -969,6 +970,7 @@ abstract class Compiler implements DiagnosticListener { |
| this.useContentSecurityPolicy: false, |
| this.suppressWarnings: false, |
| bool hasIncrementalSupport: false, |
| + this.enableExperimentalMirrors: false, |
| this.enableAsyncAwait: false, |
| this.enableEnums: false, |
| api.CompilerOutputProvider outputProvider, |
| @@ -1223,9 +1225,67 @@ abstract class Compiler implements DiagnosticListener { |
| /// |
| /// The method returns a [Future] allowing for the loading of additional |
| /// libraries. |
| - Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) { |
| + Future onLibrariesLoaded(LoadedLibraries loadedLibraries) { |
| return new Future.sync(() { |
| - if (!loadedLibraries.containsKey(DART_CORE)) return new Future.value(); |
| + if (!loadedLibraries.containsLibrary(DART_CORE)) { |
| + return null; |
| + } |
| + if (!enableExperimentalMirrors && |
| + loadedLibraries.containsLibrary(DART_MIRRORS)) { |
| + // TODO(johnniwinther): Move computation of dependencies to the library |
| + // loader. |
| + Uri rootUri = loadedLibraries.rootUri; |
| + Set<String> importChains = new Set<String>(); |
| + // The maximum number of full imports chains to process. |
| + final int chainLimit = 10000; |
| + // The maximum number of imports chains to show. |
| + final int compactChainLimit = verbose ? 20 : 10; |
| + int chainCount = 0; |
| + bool limitExceeded = false; |
| + loadedLibraries.forEachImportChain(DART_MIRRORS, |
| + callback:(Link<Uri> importChainReversed) { |
|
floitsch
2014/11/18 15:50:01
space after ':'.
Johnni Winther
2014/11/19 08:52:19
Done.
|
| + Link<CodeLocation> compactImportChain = const Link<CodeLocation>(); |
| + CodeLocation currentCodeLocation = |
| + new UriLocation(importChainReversed.head); |
| + compactImportChain = compactImportChain.prepend(currentCodeLocation); |
| + for (Link<Uri> link = importChainReversed.tail; |
| + !link.isEmpty; |
| + link = link.tail) { |
| + Uri uri = link.head; |
| + if (!currentCodeLocation.inSameLocation(uri)) { |
| + currentCodeLocation = |
| + verbose ? new UriLocation(uri) : new CodeLocation(uri); |
| + compactImportChain = |
| + compactImportChain.prepend(currentCodeLocation); |
| + } |
| + } |
| + String importChain = |
| + compactImportChain.map((CodeLocation codeLocation) { |
| + return codeLocation.relativize(rootUri); |
|
floitsch
2014/11/18 15:50:01
This indentation just doesn't work for me... (even
Johnni Winther
2014/11/19 08:52:19
Done. Didn't like it either.
|
| + }).join(' => '); |
| + |
| + if (!importChains.contains(importChain)) { |
| + if (importChains.length > compactChainLimit) { |
| + importChains.add('...'); |
| + return false; |
| + } else { |
| + importChains.add(importChain); |
| + } |
| + } |
| + |
| + chainCount++; |
| + if (chainCount > chainLimit) { |
| + // Assume there are more import chains. |
| + importChains.add('...'); |
| + return false; |
| + } |
| + return true; |
| + }); |
| + reportWarning(NO_LOCATION_SPANNABLE, |
| + MessageKind.IMPORT_EXPERIMENTAL_MIRRORS, |
| + {'importChain': importChains.join( |
| + MessageKind.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)}); |
| + } |
| functionClass.ensureResolved(this); |
| functionApplyMethod = functionClass.lookupLocalMember('apply'); |
| @@ -1235,8 +1295,8 @@ abstract class Compiler implements DiagnosticListener { |
| coreLibrary.find('proxy')).value; |
| // TODO(johnniwinther): Move this to the JavaScript backend. |
| - LibraryElement jsHelperLibrary = |
| - loadedLibraries[js_backend.JavaScriptBackend.DART_JS_HELPER]; |
| + LibraryElement jsHelperLibrary = loadedLibraries.getLibrary( |
| + js_backend.JavaScriptBackend.DART_JS_HELPER); |
| if (jsHelperLibrary != null) { |
| patchConstant = resolver.constantCompiler.compileConstant( |
| jsHelperLibrary.find('patch')).value; |
| @@ -1963,40 +2023,29 @@ abstract class Compiler implements DiagnosticListener { |
| /// If [assumeInUserCode] is `true`, [element] is assumed to be in user code |
| /// if no entrypoints have been set. |
| bool inUserCode(Element element, {bool assumeInUserCode: false}) { |
| - List<Uri> entrypoints = <Uri>[]; |
| + if (element == null) return false; |
| + Iterable<CodeLocation> userCodeLocations = |
| + computeUserCodeLocations(assumeInUserCode: assumeInUserCode); |
| + Uri libraryUri = element.library.canonicalUri; |
| + return userCodeLocations.any( |
| + (CodeLocation codeLocation) => codeLocation.inSameLocation(libraryUri)); |
| + } |
| + |
| + Iterable<CodeLocation> computeUserCodeLocations( |
| + {bool assumeInUserCode: false}) { |
| + List<CodeLocation> userCodeLocations = <CodeLocation>[]; |
| if (mainApp != null) { |
| - entrypoints.add(mainApp.canonicalUri); |
| + userCodeLocations.add(new CodeLocation(mainApp.canonicalUri)); |
| } |
| if (librariesToAnalyzeWhenRun != null) { |
| - entrypoints.addAll(librariesToAnalyzeWhenRun); |
| + userCodeLocations.addAll(librariesToAnalyzeWhenRun.map( |
| + (Uri uri) => new CodeLocation(uri))); |
| } |
| - if (entrypoints.isEmpty && assumeInUserCode) { |
| + if (userCodeLocations.isEmpty && assumeInUserCode) { |
| // Assume in user code since [mainApp] has not been set yet. |
| - return true; |
| + userCodeLocations.add(const AnyLocation()); |
| } |
| - if (element == null) return false; |
| - Uri libraryUri = element.library.canonicalUri; |
| - if (libraryUri.scheme == 'package') { |
| - for (Uri uri in entrypoints) { |
| - if (uri.scheme != 'package') continue; |
| - int slashPos = libraryUri.path.indexOf('/'); |
| - if (slashPos != -1) { |
| - String packageName = libraryUri.path.substring(0, slashPos + 1); |
| - if (uri.path.startsWith(packageName)) { |
| - return true; |
| - } |
| - } else { |
| - if (libraryUri.path == uri.path) { |
| - return true; |
| - } |
| - } |
| - } |
| - } else { |
| - for (Uri uri in entrypoints) { |
| - if (libraryUri.scheme == uri.scheme) return true; |
| - } |
| - } |
| - return false; |
| + return userCodeLocations; |
| } |
| /// Return a canonical URI for the source of [element]. |
| @@ -2188,3 +2237,86 @@ class GenericTask extends CompilerTask { |
| GenericTask(this.name, Compiler compiler) |
| : super(compiler); |
| } |
| + |
| +/// [CodeLocation] divides uris into different classes. |
| +/// |
| +/// These are used to group uris from user code, platform libraries and |
| +/// packages. |
| +abstract class CodeLocation { |
| + /// Returns `true` if [uri] is in this code location. |
| + bool inSameLocation(Uri uri); |
| + |
| + /// Returns the uri of this location relative to [baseUri]. |
| + String relativize(Uri baseUri); |
| + |
| + factory CodeLocation(Uri uri) { |
| + if (uri.scheme == 'package') { |
| + int slashPos = uri.path.indexOf('/'); |
| + if (slashPos != -1) { |
| + String packageName = uri.path.substring(0, slashPos); |
| + return new PackageLocation(packageName); |
| + } else { |
| + return new UriLocation(uri); |
| + } |
| + } else { |
| + return new SchemeLocation(uri); |
| + } |
| + } |
| +} |
| + |
| +/// A code location defined by the scheme of the uri. |
| +/// |
| +/// Used for non-package uris, such as 'dart', 'file', and 'http'. |
| +class SchemeLocation implements CodeLocation { |
| + final Uri uri; |
| + |
| + SchemeLocation(this.uri); |
| + |
| + bool inSameLocation(Uri uri) { |
| + return this.uri.scheme == uri.scheme; |
| + } |
| + |
| + String relativize(Uri baseUri) { |
| + return uri_extras.relativize(baseUri, uri, false); |
| + } |
| +} |
| + |
| +/// A code location defined by the package name. |
| +/// |
| +/// Used for package uris, separated by their `package names`, that is, the |
| +/// 'foo' of 'package:foo/bar.dart'. |
| +class PackageLocation implements CodeLocation { |
| + final String packageName; |
| + |
| + PackageLocation(this.packageName); |
| + |
| + bool inSameLocation(Uri uri) { |
| + return uri.scheme == 'package' && uri.path.startsWith('$packageName/'); |
| + } |
| + |
| + String relativize(Uri baseUri) => 'package:$packageName'; |
| +} |
| + |
| +/// A code location defined by the whole uri. |
| +/// |
| +/// Used for package uris with no package name. For instance 'package:foo.dart'. |
| +class UriLocation implements CodeLocation { |
| + final Uri uri; |
| + |
| + UriLocation(this.uri); |
| + |
| + bool inSameLocation(Uri uri) => this.uri == uri; |
| + |
| + String relativize(Uri baseUri) { |
| + return uri_extras.relativize(baseUri, uri, false); |
| + } |
| +} |
| + |
| +/// A code location that contains any uri. |
| +class AnyLocation implements CodeLocation { |
| + const AnyLocation(); |
| + |
| + bool inSameLocation(Uri uri) => true; |
| + |
| + String relativize(Uri baseUri) => '$baseUri'; |
| +} |