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 |