| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; |
| 5 import 'dart:collection'; | 6 import 'dart:collection'; |
| 6 import 'dart:io' as io; | 7 import 'dart:io' as io; |
| 7 | 8 |
| 8 import 'package:analyzer/dart/element/element.dart'; | |
| 9 import 'package:analyzer/file_system/file_system.dart' | 9 import 'package:analyzer/file_system/file_system.dart' |
| 10 show File, Folder, ResourceProvider, ResourceUriResolver; | 10 show File, Folder, ResourceProvider, ResourceUriResolver; |
| 11 import 'package:analyzer/file_system/physical_file_system.dart'; | 11 import 'package:analyzer/file_system/physical_file_system.dart'; |
| 12 import 'package:analyzer/source/package_map_resolver.dart'; | 12 import 'package:analyzer/source/package_map_resolver.dart'; |
| 13 import 'package:analyzer/src/context/builder.dart'; | 13 import 'package:analyzer/src/context/builder.dart'; |
| 14 import 'package:analyzer/src/dart/analysis/driver.dart'; |
| 15 import 'package:analyzer/src/dart/analysis/file_state.dart'; |
| 14 import 'package:analyzer/src/dart/sdk/sdk.dart'; | 16 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| 15 import 'package:analyzer/src/generated/engine.dart'; | 17 import 'package:analyzer/src/generated/engine.dart' hide AnalysisResult; |
| 16 import 'package:analyzer/src/generated/sdk.dart'; | 18 import 'package:analyzer/src/generated/sdk.dart'; |
| 17 import 'package:analyzer/src/generated/source.dart'; | 19 import 'package:analyzer/src/generated/source.dart'; |
| 18 import 'package:analyzer/src/generated/source_io.dart'; | 20 import 'package:analyzer/src/generated/source_io.dart'; |
| 19 import 'package:analyzer/src/lint/io.dart'; | 21 import 'package:analyzer/src/lint/io.dart'; |
| 20 import 'package:analyzer/src/lint/linter.dart'; | 22 import 'package:analyzer/src/lint/linter.dart'; |
| 21 import 'package:analyzer/src/lint/project.dart'; | 23 import 'package:analyzer/src/lint/project.dart'; |
| 22 import 'package:analyzer/src/lint/registry.dart'; | 24 import 'package:analyzer/src/lint/registry.dart'; |
| 23 import 'package:analyzer/src/services/lint.dart'; | 25 import 'package:analyzer/src/services/lint.dart'; |
| 24 import 'package:analyzer/src/util/sdk.dart'; | 26 import 'package:analyzer/src/util/sdk.dart'; |
| 27 import 'package:front_end/src/base/performace_logger.dart'; |
| 28 import 'package:front_end/src/incremental/byte_store.dart'; |
| 25 import 'package:package_config/packages.dart' show Packages; | 29 import 'package:package_config/packages.dart' show Packages; |
| 26 import 'package:package_config/packages_file.dart' as pkgfile show parse; | 30 import 'package:package_config/packages_file.dart' as pkgfile show parse; |
| 27 import 'package:package_config/src/packages_impl.dart' show MapPackages; | 31 import 'package:package_config/src/packages_impl.dart' show MapPackages; |
| 28 import 'package:path/path.dart' as p; | 32 import 'package:path/path.dart' as p; |
| 29 import 'package:plugin/manager.dart'; | 33 import 'package:plugin/manager.dart'; |
| 30 import 'package:plugin/plugin.dart'; | 34 import 'package:plugin/plugin.dart'; |
| 31 | 35 |
| 32 Source createSource(Uri sourceUri) { | 36 Source createSource(Uri sourceUri) { |
| 33 return PhysicalResourceProvider.INSTANCE | 37 return PhysicalResourceProvider.INSTANCE |
| 34 .getFile(sourceUri.toFilePath()) | 38 .getFile(sourceUri.toFilePath()) |
| 35 .createSource(sourceUri); | 39 .createSource(sourceUri); |
| 36 } | 40 } |
| 37 | 41 |
| 38 /// Print the given message and exit with the given [exitCode] | 42 /// Print the given message and exit with the given [exitCode] |
| 39 void printAndFail(String message, {int exitCode: 15}) { | 43 void printAndFail(String message, {int exitCode: 15}) { |
| 40 print(message); | 44 print(message); |
| 41 io.exit(exitCode); | 45 io.exit(exitCode); |
| 42 } | 46 } |
| 43 | 47 |
| 44 AnalysisOptions _buildAnalyzerOptions(DriverOptions options) { | 48 AnalysisOptions _buildAnalyzerOptions(LinterOptions options) { |
| 45 AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl(); | 49 AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl(); |
| 46 analysisOptions.strongMode = options.strongMode; | 50 analysisOptions.strongMode = options.strongMode; |
| 47 analysisOptions.hint = false; | 51 analysisOptions.hint = false; |
| 48 analysisOptions.lint = options.enableLints; | 52 analysisOptions.lint = options.enableLints; |
| 49 analysisOptions.generateSdkErrors = options.showSdkWarnings; | 53 analysisOptions.generateSdkErrors = options.showSdkWarnings; |
| 50 analysisOptions.enableAssertInitializer = options.enableAssertInitializer; | 54 analysisOptions.enableAssertInitializer = options.enableAssertInitializer; |
| 51 analysisOptions.enableTiming = options.enableTiming; | 55 analysisOptions.enableTiming = options.enableTiming; |
| 56 analysisOptions.lintRules = options.enabledLints?.toList(growable: false); |
| 52 return analysisOptions; | 57 return analysisOptions; |
| 53 } | 58 } |
| 54 | 59 |
| 55 class DriverOptions { | 60 class DriverOptions { |
| 56 /// The maximum number of sources for which AST structures should be kept | 61 /// The maximum number of sources for which AST structures should be kept |
| 57 /// in the cache. The default is 512. | 62 /// in the cache. The default is 512. |
| 58 int cacheSize = 512; | 63 int cacheSize = 512; |
| 59 | 64 |
| 60 /// The path to the dart SDK. | 65 /// The path to the dart SDK. |
| 61 String dartSdkPath; | 66 String dartSdkPath; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 77 String packageRootPath; | 82 String packageRootPath; |
| 78 | 83 |
| 79 /// Whether to show SDK warnings. | 84 /// Whether to show SDK warnings. |
| 80 bool showSdkWarnings = false; | 85 bool showSdkWarnings = false; |
| 81 | 86 |
| 82 /// Whether to use Dart's Strong Mode analyzer. | 87 /// Whether to use Dart's Strong Mode analyzer. |
| 83 bool strongMode = true; | 88 bool strongMode = true; |
| 84 | 89 |
| 85 /// The mock SDK (to speed up testing) or `null` to use the actual SDK. | 90 /// The mock SDK (to speed up testing) or `null` to use the actual SDK. |
| 86 DartSdk mockSdk; | 91 DartSdk mockSdk; |
| 87 | |
| 88 /// Whether to show lints for the transitive closure of imported and exported | |
| 89 /// libraries. | |
| 90 bool visitTransitiveClosure = false; | |
| 91 } | 92 } |
| 92 | 93 |
| 93 class LintDriver { | 94 class LintDriver { |
| 94 /// The sources which have been analyzed so far. This is used to avoid | 95 /// The sources which have been analyzed so far. This is used to avoid |
| 95 /// analyzing a source more than once, and to compute the total number of | 96 /// analyzing a source more than once, and to compute the total number of |
| 96 /// sources analyzed for statistics. | 97 /// sources analyzed for statistics. |
| 97 Set<Source> _sourcesAnalyzed = new HashSet<Source>(); | 98 Set<Source> _sourcesAnalyzed = new HashSet<Source>(); |
| 98 | 99 |
| 99 final LinterOptions options; | 100 final LinterOptions options; |
| 100 | 101 |
| 101 LintDriver(this.options) { | 102 LintDriver(this.options) { |
| 102 _processPlugins(); | 103 _processPlugins(); |
| 103 } | 104 } |
| 104 | 105 |
| 105 /// Return the number of sources that have been analyzed so far. | 106 /// Return the number of sources that have been analyzed so far. |
| 106 int get numSourcesAnalyzed => _sourcesAnalyzed.length; | 107 int get numSourcesAnalyzed => _sourcesAnalyzed.length; |
| 107 | 108 |
| 108 List<UriResolver> get resolvers { | 109 List<UriResolver> get resolvers { |
| 109 // TODO(brianwilkerson) Use the context builder to compute all of the resolv
ers. | 110 // TODO(brianwilkerson) Use the context builder to compute all of the resolv
ers. |
| 110 ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; | 111 ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; |
| 111 ContextBuilder builder = new ContextBuilder(resourceProvider, null, null); | 112 ContextBuilder builder = new ContextBuilder(resourceProvider, null, null); |
| 112 | 113 |
| 113 DartSdk sdk = options.mockSdk ?? | 114 DartSdk sdk = options.mockSdk ?? |
| 114 new FolderBasedDartSdk( | 115 new FolderBasedDartSdk(resourceProvider, |
| 115 resourceProvider, resourceProvider.getFolder(sdkDir)); | 116 resourceProvider.getFolder(sdkDir), options.strongMode); |
| 116 | 117 |
| 117 List<UriResolver> resolvers = [new DartUriResolver(sdk)]; | 118 List<UriResolver> resolvers = [new DartUriResolver(sdk)]; |
| 118 | 119 |
| 119 if (options.packageRootPath != null) { | 120 if (options.packageRootPath != null) { |
| 120 // TODO(brianwilkerson) After 0.30.0 is published, clean up the following. | 121 // TODO(brianwilkerson) After 0.30.0 is published, clean up the following. |
| 121 try { | 122 try { |
| 122 // Try to use the post 0.30.0 API. | 123 // Try to use the post 0.30.0 API. |
| 123 (builder as dynamic).builderOptions.defaultPackagesDirectoryPath = | 124 (builder as dynamic).builderOptions.defaultPackagesDirectoryPath = |
| 124 options.packageRootPath; | 125 options.packageRootPath; |
| 125 } catch (_) { | 126 } catch (_) { |
| 126 // If that fails, fall back to the pre 0.30.0 API. | 127 // If that fails, fall back to the pre 0.30.0 API. |
| 127 (builder as dynamic).defaultPackagesDirectoryPath = | 128 (builder as dynamic).defaultPackagesDirectoryPath = |
| 128 options.packageRootPath; | 129 options.packageRootPath; |
| 129 } | 130 } |
| 130 Map<String, List<Folder>> packageMap = | 131 Map<String, List<Folder>> packageMap = |
| 131 builder.convertPackagesToMap(builder.createPackageMap(null)); | 132 builder.convertPackagesToMap(builder.createPackageMap(null)); |
| 132 resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap)); | 133 resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap)); |
| 133 } | 134 } |
| 134 | 135 |
| 135 // File URI resolver must come last so that files inside "/lib" are | 136 // File URI resolver must come last so that files inside "/lib" are |
| 136 // are analyzed via "package:" URI's. | 137 // are analyzed via "package:" URI's. |
| 137 resolvers.add(new ResourceUriResolver(resourceProvider)); | 138 resolvers.add(new ResourceUriResolver(resourceProvider)); |
| 138 return resolvers; | 139 return resolvers; |
| 139 } | 140 } |
| 140 | 141 |
| 142 ResourceProvider get resourceProvider => options.resourceProvider; |
| 143 |
| 141 String get sdkDir { | 144 String get sdkDir { |
| 142 // In case no SDK has been specified, fall back to inferring it. | 145 // In case no SDK has been specified, fall back to inferring it. |
| 143 return options.dartSdkPath ?? getSdkPath(); | 146 return options.dartSdkPath ?? getSdkPath(); |
| 144 } | 147 } |
| 145 | 148 |
| 146 List<AnalysisErrorInfo> analyze(Iterable<io.File> files) { | 149 Future<List<AnalysisErrorInfo>> analyze(Iterable<io.File> files) async { |
| 147 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); | |
| 148 context.analysisOptions = _buildAnalyzerOptions(options); | |
| 149 registerLinters(context); | |
| 150 | |
| 151 Packages packages = _getPackageConfig(); | |
| 152 | |
| 153 context.sourceFactory = new SourceFactory(resolvers, packages); | |
| 154 AnalysisEngine.instance.logger = new StdLogger(); | 150 AnalysisEngine.instance.logger = new StdLogger(); |
| 155 | 151 |
| 152 SourceFactory sourceFactory = |
| 153 new SourceFactory(resolvers, _getPackageConfig()); |
| 154 |
| 155 PerformanceLog log = new PerformanceLog(null); |
| 156 AnalysisDriverScheduler scheduler = new AnalysisDriverScheduler(log); |
| 157 AnalysisDriver analysisDriver = new AnalysisDriver( |
| 158 scheduler, |
| 159 log, |
| 160 resourceProvider, |
| 161 new MemoryByteStore(), |
| 162 new FileContentOverlay(), |
| 163 null, |
| 164 sourceFactory, |
| 165 _buildAnalyzerOptions(options)); |
| 166 analysisDriver.results.listen((_) {}); |
| 167 analysisDriver.exceptions.listen((_) {}); |
| 168 scheduler.start(); |
| 169 |
| 156 List<Source> sources = []; | 170 List<Source> sources = []; |
| 157 ChangeSet changeSet = new ChangeSet(); | |
| 158 for (io.File file in files) { | 171 for (io.File file in files) { |
| 159 File sourceFile = PhysicalResourceProvider.INSTANCE | 172 File sourceFile = |
| 160 .getFile(p.normalize(file.absolute.path)); | 173 resourceProvider.getFile(p.normalize(file.absolute.path)); |
| 161 Source source = sourceFile.createSource(); | 174 Source source = sourceFile.createSource(); |
| 162 Uri uri = context.sourceFactory.restoreUri(source); | 175 Uri uri = sourceFactory.restoreUri(source); |
| 163 if (uri != null) { | 176 if (uri != null) { |
| 164 // Ensure that we analyze the file using its canonical URI (e.g. if | 177 // Ensure that we analyze the file using its canonical URI (e.g. if |
| 165 // it's in "/lib", analyze it using a "package:" URI). | 178 // it's in "/lib", analyze it using a "package:" URI). |
| 166 source = sourceFile.createSource(uri); | 179 source = sourceFile.createSource(uri); |
| 167 } | 180 } |
| 181 |
| 168 sources.add(source); | 182 sources.add(source); |
| 169 changeSet.addedSource(source); | 183 analysisDriver.addFile(source.fullName); |
| 170 } | 184 } |
| 171 context.applyChanges(changeSet); | |
| 172 | 185 |
| 173 // Temporary location | 186 DartProject project = await DartProject.create(analysisDriver, sources); |
| 174 var project = new DartProject(context, sources); | |
| 175 // This will get pushed into the generator (or somewhere comparable) when | |
| 176 // we have a proper plugin. | |
| 177 Registry.ruleRegistry.forEach((lint) { | 187 Registry.ruleRegistry.forEach((lint) { |
| 178 if (lint is ProjectVisitor) { | 188 if (lint is ProjectVisitor) { |
| 179 (lint as ProjectVisitor).visit(project); | 189 (lint as ProjectVisitor).visit(project); |
| 180 } | 190 } |
| 181 }); | 191 }); |
| 182 | 192 |
| 183 List<AnalysisErrorInfo> errors = []; | 193 List<AnalysisErrorInfo> errors = []; |
| 184 | |
| 185 for (Source source in sources) { | 194 for (Source source in sources) { |
| 186 context.computeErrors(source); | 195 ErrorsResult errorsResult = |
| 187 errors.add(context.getErrors(source)); | 196 await analysisDriver.getErrors(source.fullName); |
| 197 errors.add(new AnalysisErrorInfoImpl( |
| 198 errorsResult.errors, errorsResult.lineInfo)); |
| 188 _sourcesAnalyzed.add(source); | 199 _sourcesAnalyzed.add(source); |
| 189 } | 200 } |
| 190 | 201 |
| 191 if (options.visitTransitiveClosure) { | |
| 192 // In the process of computing errors for all the sources in [sources], | |
| 193 // the analyzer has visited the transitive closure of all libraries | |
| 194 // referenced by those sources. So now we simply need to visit all | |
| 195 // library sources known to the analysis context, and all parts they | |
| 196 // refer to. | |
| 197 for (Source librarySource in context.librarySources) { | |
| 198 for (Source source in _getAllUnitSources(context, librarySource)) { | |
| 199 if (!_sourcesAnalyzed.contains(source)) { | |
| 200 context.computeErrors(source); | |
| 201 errors.add(context.getErrors(source)); | |
| 202 _sourcesAnalyzed.add(source); | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 return errors; | 202 return errors; |
| 209 } | 203 } |
| 210 | 204 |
| 211 void registerLinters(AnalysisContext context) { | 205 void registerLinters(AnalysisContext context) { |
| 212 if (options.enableLints) { | 206 if (options.enableLints) { |
| 213 setLints(context, options.enabledLints?.toList(growable: false)); | 207 setLints(context, options.enabledLints?.toList(growable: false)); |
| 214 } | 208 } |
| 215 } | 209 } |
| 216 | 210 |
| 217 /// Yield the sources for all the compilation units constituting | |
| 218 /// [librarySource] (including the defining compilation unit). | |
| 219 Iterable<Source> _getAllUnitSources( | |
| 220 AnalysisContext context, Source librarySource) { | |
| 221 List<Source> result = <Source>[librarySource]; | |
| 222 result.addAll(context | |
| 223 .getLibraryElement(librarySource) | |
| 224 .parts | |
| 225 .map((CompilationUnitElement e) => e.source)); | |
| 226 return result; | |
| 227 } | |
| 228 | |
| 229 Packages _getPackageConfig() { | 211 Packages _getPackageConfig() { |
| 230 if (options.packageConfigPath != null) { | 212 if (options.packageConfigPath != null) { |
| 231 String packageConfigPath = options.packageConfigPath; | 213 String packageConfigPath = options.packageConfigPath; |
| 232 Uri fileUri = new Uri.file(packageConfigPath); | 214 Uri fileUri = new Uri.file(packageConfigPath); |
| 233 try { | 215 try { |
| 234 io.File configFile = new io.File.fromUri(fileUri).absolute; | 216 io.File configFile = new io.File.fromUri(fileUri).absolute; |
| 235 List<int> bytes = configFile.readAsBytesSync(); | 217 List<int> bytes = configFile.readAsBytesSync(); |
| 236 Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri); | 218 Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri); |
| 237 return new MapPackages(map); | 219 return new MapPackages(map); |
| 238 } catch (e) { | 220 } catch (e) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 252 } | 234 } |
| 253 | 235 |
| 254 /// Prints logging information comments to the [outSink] and error messages to | 236 /// Prints logging information comments to the [outSink] and error messages to |
| 255 /// [errorSink]. | 237 /// [errorSink]. |
| 256 class StdLogger extends Logger { | 238 class StdLogger extends Logger { |
| 257 @override | 239 @override |
| 258 void logError(String message, [exception]) => errorSink.writeln(message); | 240 void logError(String message, [exception]) => errorSink.writeln(message); |
| 259 @override | 241 @override |
| 260 void logInformation(String message, [exception]) => outSink.writeln(message); | 242 void logInformation(String message, [exception]) => outSink.writeln(message); |
| 261 } | 243 } |
| OLD | NEW |