Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Side by Side Diff: pkg/analyzer_cli/lib/src/package_analyzer.dart

Issue 1720963003: Initial hermetic package analyzer. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/analyzer_cli/lib/src/options.dart ('k') | pkg/analyzer_cli/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer_cli.src.package_analyzer;
6
7 import 'dart:core' hide Resource;
8 import 'dart:io' as io;
9
10 import 'package:analyzer/dart/element/element.dart';
11 import 'package:analyzer/file_system/file_system.dart';
12 import 'package:analyzer/file_system/physical_file_system.dart';
13 import 'package:analyzer/source/package_map_resolver.dart';
14 import 'package:analyzer/src/context/cache.dart';
15 import 'package:analyzer/src/context/context.dart';
16 import 'package:analyzer/src/generated/engine.dart';
17 import 'package:analyzer/src/generated/error.dart';
18 import 'package:analyzer/src/generated/resolver.dart';
19 import 'package:analyzer/src/generated/sdk_io.dart';
20 import 'package:analyzer/src/generated/source.dart';
21 import 'package:analyzer/src/generated/source_io.dart';
22 import 'package:analyzer/src/summary/format.dart';
23 import 'package:analyzer/src/summary/idl.dart';
24 import 'package:analyzer/src/summary/resynthesize.dart';
25 import 'package:analyzer/src/summary/summarize_elements.dart';
26 import 'package:analyzer/src/summary/summary_sdk.dart';
27 import 'package:analyzer/src/task/dart.dart';
28 import 'package:analyzer/task/dart.dart';
29 import 'package:analyzer/task/model.dart';
30 import 'package:analyzer_cli/src/analyzer_impl.dart';
31 import 'package:analyzer_cli/src/driver.dart';
32 import 'package:analyzer_cli/src/error_formatter.dart';
33 import 'package:analyzer_cli/src/options.dart';
34 import 'package:path/path.dart' as pathos;
35
36 /**
37 * If [uri] has the `package` scheme in form of `package:pkg/file.dart`,
38 * return the `pkg` name. Otherwise return `null`.
39 */
40 String getPackageName(Uri uri) {
41 if (uri.scheme != 'package') {
42 return null;
43 }
44 String path = uri.path;
45 int index = path.indexOf('/');
46 if (index == -1) {
47 return null;
48 }
49 return path.substring(0, index);
50 }
51
52 /**
53 * A concrete resynthesizer that serves summaries from given file paths.
54 */
55 class FileBasedSummaryResynthesizer extends SummaryResynthesizer {
56 final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{};
57 final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{};
58
59 FileBasedSummaryResynthesizer(
60 SummaryResynthesizer parent,
61 AnalysisContext context,
62 TypeProvider typeProvider,
63 SourceFactory sourceFactory,
64 bool strongMode,
65 List<String> summaryPaths)
66 : super(parent, context, typeProvider, sourceFactory, strongMode) {
67 summaryPaths.forEach(_fillMaps);
68 }
69
70 @override
71 LinkedLibrary getLinkedSummary(String uri) {
72 return linkedMap[uri];
73 }
74
75 @override
76 UnlinkedUnit getUnlinkedSummary(String uri) {
77 return unlinkedMap[uri];
78 }
79
80 @override
81 bool hasLibrarySummary(String uri) {
82 return linkedMap.containsKey(uri);
83 }
84
85 void _fillMaps(String path) {
86 io.File file = new io.File(path);
87 List<int> buffer = file.readAsBytesSync();
88 SdkBundle bundle = new SdkBundle.fromBuffer(buffer);
89 for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
90 unlinkedMap[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
91 }
92 for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
93 linkedMap[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
94 }
95 }
96 }
97
98 /**
99 * The [ResourceProvider] that provides results from input package summaries.
100 */
101 class InputPackagesResultProvider extends ResultProvider {
102 final InternalAnalysisContext context;
103 final Map<String, String> packageSummaryInputs;
104
105 FileBasedSummaryResynthesizer resynthesizer;
106 SummaryResultProvider sdkProvider;
107
108 InputPackagesResultProvider(this.context, this.packageSummaryInputs) {
109 InternalAnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
110 sdkProvider = sdkContext.resultProvider;
111 // Set the type provider to prevent the context from computing it.
112 context.typeProvider = sdkContext.typeProvider;
113 // Create a chained resynthesizer.
114 resynthesizer = new FileBasedSummaryResynthesizer(
115 sdkProvider.resynthesizer,
116 context,
117 context.typeProvider,
118 context.sourceFactory,
119 false,
120 packageSummaryInputs.values.toList());
121 }
122
123 bool compute(CacheEntry entry, ResultDescriptor result) {
Paul Berry 2016/02/23 00:59:29 It looks like some of this code is duplicated from
scheglov 2016/02/23 01:15:28 Yes, probably some of it can be shared. I will add
124 if (sdkProvider.compute(entry, result)) {
125 return true;
126 }
127 AnalysisTarget target = entry.target;
128 // Only library results are supported for now.
129 if (target is Source) {
130 Uri uri = target.uri;
131 // We know how to server results to input packages.
132 String sourcePackageName = getPackageName(uri);
133 if (!packageSummaryInputs.containsKey(sourcePackageName)) {
134 return false;
135 }
136 // Provide known results.
137 String uriString = uri.toString();
138 if (result == LIBRARY_ELEMENT1 ||
139 result == LIBRARY_ELEMENT2 ||
140 result == LIBRARY_ELEMENT3 ||
141 result == LIBRARY_ELEMENT4 ||
142 result == LIBRARY_ELEMENT5 ||
143 result == LIBRARY_ELEMENT6 ||
144 result == LIBRARY_ELEMENT7 ||
145 result == LIBRARY_ELEMENT8 ||
146 result == LIBRARY_ELEMENT ||
147 false) {
148 LibraryElement libraryElement =
149 resynthesizer.getLibraryElement(uriString);
150 entry.setValue(result, libraryElement, TargetedResult.EMPTY_LIST);
151 return true;
152 } else if (result == READY_LIBRARY_ELEMENT2 ||
153 result == READY_LIBRARY_ELEMENT5 ||
154 result == READY_LIBRARY_ELEMENT6) {
155 entry.setValue(result, true, TargetedResult.EMPTY_LIST);
156 return true;
157 } else if (result == SOURCE_KIND) {
158 if (resynthesizer.linkedMap.containsKey(uriString)) {
159 entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
160 return true;
161 }
162 if (resynthesizer.unlinkedMap.containsKey(uriString)) {
163 entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
164 return true;
165 }
166 return false;
167 }
168 }
169 return false;
170 }
171 }
172
173 /**
174 * The [UriResolver] that knows about sources that are parts of packages which
175 * are served from their summaries.
176 */
177 class InSummaryPackageUriResolver extends UriResolver {
Brian Wilkerson 2016/02/23 00:27:01 I don't understand the need for either this class
scheglov 2016/02/23 01:15:28 Yes, we did not get to this part offline today.
178 final Map<String, String> packageSummaryInputs;
179
180 InSummaryPackageUriResolver(this.packageSummaryInputs);
181
182 @override
183 Source resolveAbsolute(Uri uri, [Uri actualUri]) {
184 actualUri ??= uri;
185 String packageName = getPackageName(actualUri);
186 if (packageSummaryInputs.containsKey(packageName)) {
187 return new InSummarySource(actualUri);
188 }
189 return null;
190 }
191 }
192
193 /**
194 * A placeholder of a source that is part of a package whose analysis results
195 * are served from its summary. This source uses its URI as [fullName] and has
196 * empty contents.
197 */
198 class InSummarySource extends Source {
199 final Uri uri;
200
201 InSummarySource(this.uri);
202
203 @override
204 TimestampedData<String> get contents => new TimestampedData<String>(0, '');
205
206 @override
207 String get encoding => uri.toString();
208
209 @override
210 String get fullName => encoding;
211
212 @override
213 bool get isInSystemLibrary => false;
214
215 @override
216 int get modificationStamp => 0;
217
218 @override
219 String get shortName => pathos.basename(fullName);
220
221 @override
222 UriKind get uriKind => UriKind.PACKAGE_URI;
223
224 @override
225 bool exists() => true;
226
227 @override
228 Uri resolveRelativeUri(Uri relativeUri) {
229 Uri baseUri = uri;
230 return baseUri.resolveUri(relativeUri);
231 }
232
233 @override
234 String toString() => uri.toString();
235 }
236
237 /**
238 * The hermetic whole package analyzer.
239 */
240 class PackageAnalyzer {
241 final CommandLineOptions options;
242
243 String packagePath;
244 String packageLibPath;
245
246 final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
247 InternalAnalysisContext context;
248 final List<Source> explicitSources = <Source>[];
249
250 final List<String> linkedLibraryUris = <String>[];
251 final List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[];
252 final List<String> unlinkedUnitUris = <String>[];
253 final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
254
255 PackageAnalyzer(this.options);
256
257 /**
258 * Perform package analysis according to the given [options].
259 */
260 ErrorSeverity analyze() {
261 packagePath = options.packageModePath;
262 packageLibPath = resourceProvider.pathContext.join(packagePath, 'lib');
263 if (packageLibPath == null) {
264 errorSink.writeln('--package-mode-path must be set to the root '
265 'folder of the package to analyze.');
266 io.exitCode = ErrorSeverity.ERROR.ordinal;
267 return ErrorSeverity.ERROR;
268 }
269
270 // Write the progress message.
271 if (!options.machineFormat) {
272 outSink.writeln("Analyzing sources ${options.sourceFiles}...");
273 }
274
275 // Prepare the analysis context.
276 _createContext();
277
278 // Add sources.
279 ChangeSet changeSet = new ChangeSet();
280 for (String path in options.sourceFiles) {
281 if (AnalysisEngine.isDartFileName(path)) {
282 path = resourceProvider.pathContext.absolute(path);
283 File file = resourceProvider.getFile(path);
284 if (!file.exists) {
285 errorSink.writeln('File not found: $path');
286 io.exitCode = ErrorSeverity.ERROR.ordinal;
287 return ErrorSeverity.ERROR;
288 }
289 Source source = _createSourceInContext(file);
290 explicitSources.add(source);
291 changeSet.addedSource(source);
292 }
293 }
294 context.applyChanges(changeSet);
295
296 // Perform full analysis.
297 while (true) {
298 AnalysisResult analysisResult = context.performAnalysisTask();
299 if (!analysisResult.hasMoreWork) {
300 break;
301 }
302 }
303
304 // Write summary for Dart libraries.
305 if (options.packageSummaryOutput != null) {
306 for (Source source in context.librarySources) {
307 if (pathos.isWithin(packageLibPath, source.fullName)) {
308 LibraryElement libraryElement = context.getLibraryElement(source);
309 if (libraryElement != null) {
310 _serializeSingleLibrary(libraryElement);
311 }
312 }
313 }
314 // Write the whole package bundle.
315 SdkBundleBuilder sdkBundle = new SdkBundleBuilder(
Brian Wilkerson 2016/02/23 00:27:01 Probably ought to rename SdkBundleBuilder at some
Paul Berry 2016/02/23 00:59:29 Agreed. I have some other changes I want to make
scheglov 2016/02/23 01:15:28 Yes, it was quite obvious that we need to rename i
316 linkedLibraryUris: linkedLibraryUris,
317 linkedLibraries: linkedLibraries,
318 unlinkedUnitUris: unlinkedUnitUris,
319 unlinkedUnits: unlinkedUnits);
320 io.File file = new io.File(options.packageSummaryOutput);
321 file.writeAsBytesSync(sdkBundle.toBuffer(), mode: io.FileMode.WRITE_ONLY);
322 }
323
324 // Process errors.
325 _printErrors();
326 return _computeMaxSeverity();
327 }
328
329 ErrorSeverity _computeMaxSeverity() {
330 ErrorSeverity maxSeverity = ErrorSeverity.NONE;
331 for (Source source in explicitSources) {
332 AnalysisErrorInfo errorInfo = context.getErrors(source);
333 for (AnalysisError error in errorInfo.errors) {
334 ProcessedSeverity processedSeverity =
335 AnalyzerImpl.processError(error, options, context);
336 if (processedSeverity != null) {
337 maxSeverity = maxSeverity.max(processedSeverity.severity);
338 }
339 }
340 }
341 return maxSeverity;
342 }
343
344 void _createContext() {
345 DirectoryBasedDartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
346 sdk.useSummary = true;
347
348 // Create the context.
349 context = AnalysisEngine.instance.createAnalysisContext();
350 context.typeProvider = sdk.context.typeProvider;
351 context.sourceFactory = new SourceFactory(<UriResolver>[
352 new DartUriResolver(sdk),
353 new InSummaryPackageUriResolver(options.packageSummaryInputs),
354 new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{
355 options.packageName: <Folder>[
356 resourceProvider.getFolder(packageLibPath)
357 ],
358 }),
359 new FileUriResolver()
360 ]);
361 context.resultProvider =
362 new InputPackagesResultProvider(context, options.packageSummaryInputs);
363
364 // Set context options.
365 Driver.setAnalysisContextOptions(
366 context, options, (AnalysisOptionsImpl contextOptions) {});
367 }
368
369 /**
370 * Create and return a source representing the given [file].
371 */
372 Source _createSourceInContext(File file) {
373 Source source = file.createSource();
374 if (context == null) {
375 return source;
376 }
377 Uri uri = context.sourceFactory.restoreUri(source);
378 return file.createSource(uri);
379 }
380
381 /**
382 * Print errors for all explicit sources.
383 */
384 void _printErrors() {
385 StringSink sink = options.machineFormat ? errorSink : outSink;
386 ErrorFormatter formatter = new ErrorFormatter(
387 sink,
388 options,
389 (AnalysisError error) =>
390 AnalyzerImpl.processError(error, options, context));
391 for (Source source in explicitSources) {
392 AnalysisErrorInfo errorInfo = context.getErrors(source);
393 formatter.formatErrors([errorInfo]);
394 }
395 }
396
397 /**
398 * Serialize the library with the given [element].
399 */
400 void _serializeSingleLibrary(LibraryElement element) {
401 String uri = element.source.uri.toString();
402 LibrarySerializationResult libraryResult =
403 serializeLibrary(element, context.typeProvider, options.strongMode);
404 linkedLibraryUris.add(uri);
405 linkedLibraries.add(libraryResult.linked);
406 unlinkedUnitUris.addAll(libraryResult.unitUris);
407 unlinkedUnits.addAll(libraryResult.unlinkedUnits);
408 }
409 }
OLDNEW
« no previous file with comments | « pkg/analyzer_cli/lib/src/options.dart ('k') | pkg/analyzer_cli/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698