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

Side by Side Diff: pkg/analyzer/lib/src/analyzer_impl.dart

Issue 1102613002: Analyzer CLI removal. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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_impl;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:io';
10
11 import 'package:analyzer/file_system/file_system.dart' show Folder;
12 import 'package:analyzer/file_system/physical_file_system.dart';
13 import 'package:analyzer/source/package_map_provider.dart';
14 import 'package:analyzer/source/package_map_resolver.dart';
15 import 'package:analyzer/source/pub_package_map_provider.dart';
16 import 'package:analyzer/src/error_formatter.dart';
17 import 'package:analyzer/src/generated/java_core.dart' show JavaSystem;
18 import 'package:analyzer/src/generated/java_engine.dart';
19 import 'package:analyzer/src/generated/utilities_general.dart';
20
21 import '../options.dart';
22 import 'generated/constant.dart';
23 import 'generated/element.dart';
24 import 'generated/engine.dart';
25 import 'generated/error.dart';
26 import 'generated/java_io.dart';
27 import 'generated/sdk_io.dart';
28 import 'generated/source_io.dart';
29
30 DirectoryBasedDartSdk sdk;
31
32 /**
33 * The maximum number of sources for which AST structures should be kept in the cache.
34 */
35 const int _MAX_CACHE_SIZE = 512;
36
37 /// Analyzes single library [File].
38 class AnalyzerImpl {
39 final String sourcePath;
40
41 final CommandLineOptions options;
42 final int startTime;
43
44 /**
45 * True if the analyzer is running in batch mode.
46 */
47 final bool isBatch;
48
49 ContentCache contentCache = new ContentCache();
50
51 SourceFactory sourceFactory;
52 AnalysisContext context;
53 Source librarySource;
54 /// All [Source]s references by the analyzed library.
55 final Set<Source> sources = new Set<Source>();
56
57 /// All [AnalysisErrorInfo]s in the analyzed library.
58 final List<AnalysisErrorInfo> errorInfos = new List<AnalysisErrorInfo>();
59
60 /// [HashMap] between sources and analysis error infos.
61 final HashMap<Source, AnalysisErrorInfo> sourceErrorsMap =
62 new HashMap<Source, AnalysisErrorInfo>();
63
64 /**
65 * If the file specified on the command line is part of a package, the name
66 * of that package. Otherwise `null`. This allows us to analyze the file
67 * specified on the command line as though it is reached via a "package:"
68 * URI, but avoid suppressing its output in the event that the user has not
69 * specified the "--package-warnings" option.
70 */
71 String _selfPackageName;
72
73 AnalyzerImpl(String sourcePath, this.options, this.startTime, this.isBatch)
74 : sourcePath = _normalizeSourcePath(sourcePath) {
75 if (sdk == null) {
76 sdk = new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
77 }
78 }
79
80 /// Returns the maximal [ErrorSeverity] of the recorded errors.
81 ErrorSeverity get maxErrorSeverity {
82 var status = ErrorSeverity.NONE;
83 for (AnalysisErrorInfo errorInfo in errorInfos) {
84 for (AnalysisError error in errorInfo.errors) {
85 if (!_isDesiredError(error)) {
86 continue;
87 }
88 var severity = computeSeverity(error, options.enableTypeChecks);
89 status = status.max(severity);
90 }
91 }
92 return status;
93 }
94
95 void addCompilationUnitSource(CompilationUnitElement unit,
96 Set<LibraryElement> libraries, Set<CompilationUnitElement> units) {
97 if (unit == null || units.contains(unit)) {
98 return;
99 }
100 units.add(unit);
101 sources.add(unit.source);
102 }
103
104 void addLibrarySources(LibraryElement library, Set<LibraryElement> libraries,
105 Set<CompilationUnitElement> units) {
106 if (library == null || !libraries.add(library)) {
107 return;
108 }
109 // may be skip library
110 {
111 UriKind uriKind = library.source.uriKind;
112 // Optionally skip package: libraries.
113 if (!options.showPackageWarnings && _isOtherPackage(library.source.uri)) {
114 return;
115 }
116 // Optionally skip SDK libraries.
117 if (!options.showSdkWarnings && uriKind == UriKind.DART_URI) {
118 return;
119 }
120 }
121 // add compilation units
122 addCompilationUnitSource(library.definingCompilationUnit, libraries, units);
123 for (CompilationUnitElement child in library.parts) {
124 addCompilationUnitSource(child, libraries, units);
125 }
126 // add referenced libraries
127 for (LibraryElement child in library.importedLibraries) {
128 addLibrarySources(child, libraries, units);
129 }
130 for (LibraryElement child in library.exportedLibraries) {
131 addLibrarySources(child, libraries, units);
132 }
133 }
134
135 /**
136 * Treats the [sourcePath] as the top level library and analyzes it using a
137 * asynchronous algorithm over the analysis engine.
138 */
139 void analyzeAsync() {
140 setupForAnalysis();
141 _analyzeAsync();
142 }
143
144 /**
145 * Treats the [sourcePath] as the top level library and analyzes it using a
146 * synchronous algorithm over the analysis engine. If [printMode] is `0`,
147 * then no error or performance information is printed. If [printMode] is `1`,
148 * then both will be printed. If [printMode] is `2`, then only performance
149 * information will be printed, and it will be marked as being for a cold VM.
150 */
151 ErrorSeverity analyzeSync({int printMode: 1}) {
152 setupForAnalysis();
153 return _analyzeSync(printMode);
154 }
155
156 Source computeLibrarySource() {
157 JavaFile sourceFile = new JavaFile(sourcePath);
158 Source source = sdk.fromFileUri(sourceFile.toURI());
159 if (source != null) {
160 return source;
161 }
162 source = new FileBasedSource.con2(sourceFile.toURI(), sourceFile);
163 Uri uri = context.sourceFactory.restoreUri(source);
164 if (uri == null) {
165 return source;
166 }
167 return new FileBasedSource.con2(uri, sourceFile);
168 }
169
170 /**
171 * Create and return the source factory to be used by the analysis context.
172 */
173 SourceFactory createSourceFactory() {
174 List<UriResolver> resolvers = [
175 new CustomUriResolver(options.customUrlMappings),
176 new DartUriResolver(sdk)
177 ];
178 if (options.packageRootPath != null) {
179 JavaFile packageDirectory = new JavaFile(options.packageRootPath);
180 resolvers.add(new PackageUriResolver([packageDirectory]));
181 } else {
182 PubPackageMapProvider pubPackageMapProvider =
183 new PubPackageMapProvider(PhysicalResourceProvider.INSTANCE, sdk);
184 PackageMapInfo packageMapInfo = pubPackageMapProvider.computePackageMap(
185 PhysicalResourceProvider.INSTANCE.getResource('.'));
186 Map<String, List<Folder>> packageMap = packageMapInfo.packageMap;
187 if (packageMap != null) {
188 resolvers.add(new PackageMapUriResolver(
189 PhysicalResourceProvider.INSTANCE, packageMap));
190 }
191 }
192 resolvers.add(new FileUriResolver());
193 return new SourceFactory(resolvers);
194 }
195
196 void prepareAnalysisContext() {
197 sourceFactory = createSourceFactory();
198 context = AnalysisEngine.instance.createAnalysisContext();
199 context.sourceFactory = sourceFactory;
200 Map<String, String> definedVariables = options.definedVariables;
201 if (!definedVariables.isEmpty) {
202 DeclaredVariables declaredVariables = context.declaredVariables;
203 definedVariables.forEach((String variableName, String value) {
204 declaredVariables.define(variableName, value);
205 });
206 }
207 // Uncomment the following to have errors reported on stdout and stderr
208 AnalysisEngine.instance.logger = new StdLogger(options.log);
209
210 // set options for context
211 AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
212 contextOptions.cacheSize = _MAX_CACHE_SIZE;
213 contextOptions.hint = !options.disableHints;
214 contextOptions.enableNullAwareOperators = options.enableNullAwareOperators;
215 contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
216 contextOptions.analyzeFunctionBodiesPredicate =
217 _analyzeFunctionBodiesPredicate;
218 contextOptions.generateImplicitErrors = options.showPackageWarnings;
219 contextOptions.generateSdkErrors = options.showSdkWarnings;
220 context.analysisOptions = contextOptions;
221
222 librarySource = computeLibrarySource();
223
224 Uri libraryUri = librarySource.uri;
225 if (libraryUri.scheme == 'package' && libraryUri.pathSegments.length > 0) {
226 _selfPackageName = libraryUri.pathSegments[0];
227 }
228
229 // Create and add a ChangeSet
230 ChangeSet changeSet = new ChangeSet();
231 changeSet.addedSource(librarySource);
232 context.applyChanges(changeSet);
233 }
234
235 /// Fills [errorInfos] using [sources].
236 void prepareErrors() {
237 for (Source source in sources) {
238 context.computeErrors(source);
239 var sourceErrors = context.getErrors(source);
240 errorInfos.add(sourceErrors);
241 }
242 }
243
244 /// Fills [sources].
245 void prepareSources(LibraryElement library) {
246 var units = new Set<CompilationUnitElement>();
247 var libraries = new Set<LibraryElement>();
248 addLibrarySources(library, libraries, units);
249 }
250
251 /**
252 * Setup local fields such as the analysis context for analysis.
253 */
254 void setupForAnalysis() {
255 sources.clear();
256 errorInfos.clear();
257 if (sourcePath == null) {
258 throw new ArgumentError("sourcePath cannot be null");
259 }
260 // prepare context
261 prepareAnalysisContext();
262 }
263
264 /// The async version of the analysis
265 void _analyzeAsync() {
266 new Future(context.performAnalysisTask).then((AnalysisResult result) {
267 List<ChangeNotice> notices = result.changeNotices;
268 if (result.hasMoreWork) {
269 // There is more work, record the set of sources, and then call self
270 // again to perform next task
271 for (ChangeNotice notice in notices) {
272 sources.add(notice.source);
273 sourceErrorsMap[notice.source] = notice;
274 }
275 return _analyzeAsync();
276 }
277 //
278 // There are not any more tasks, set error code and print performance
279 // numbers.
280 //
281 // prepare errors
282 sourceErrorsMap.forEach((k, v) {
283 errorInfos.add(sourceErrorsMap[k]);
284 });
285
286 // print errors and performance numbers
287 _printErrorsAndPerf();
288
289 // compute max severity and set exitCode
290 ErrorSeverity status = maxErrorSeverity;
291 if (status == ErrorSeverity.WARNING && options.warningsAreFatal) {
292 status = ErrorSeverity.ERROR;
293 }
294 exitCode = status.ordinal;
295 }).catchError((ex, st) {
296 AnalysisEngine.instance.logger.logError("$ex\n$st");
297 });
298 }
299
300 bool _analyzeFunctionBodiesPredicate(Source source) {
301 // TODO(paulberry): This function will need to be updated when we add the
302 // ability to suppress errors, warnings, and hints for files reached via
303 // custom URI's using the "--url-mapping" flag.
304 if (source.uri.scheme == 'dart') {
305 if (isBatch) {
306 // When running in batch mode, the SDK files are cached from one
307 // analysis run to the next. So we need to parse function bodies even
308 // if the user hasn't asked for errors/warnings from the SDK, since
309 // they might ask for errors/warnings from the SDK in the future.
310 return true;
311 }
312 return options.showSdkWarnings;
313 }
314 if (_isOtherPackage(source.uri)) {
315 return options.showPackageWarnings;
316 }
317 return true;
318 }
319
320 /// The sync version of analysis.
321 ErrorSeverity _analyzeSync(int printMode) {
322 // don't try to analyze parts
323 if (context.computeKindOf(librarySource) == SourceKind.PART) {
324 print("Only libraries can be analyzed.");
325 print("$sourcePath is a part and can not be analyzed.");
326 return ErrorSeverity.ERROR;
327 }
328 // resolve library
329 var libraryElement = context.computeLibraryElement(librarySource);
330 // prepare source and errors
331 prepareSources(libraryElement);
332 prepareErrors();
333
334 // print errors and performance numbers
335 if (printMode == 1) {
336 _printErrorsAndPerf();
337 } else if (printMode == 2) {
338 _printColdPerf();
339 }
340
341 // compute max severity and set exitCode
342 ErrorSeverity status = maxErrorSeverity;
343 if (status == ErrorSeverity.WARNING && options.warningsAreFatal) {
344 status = ErrorSeverity.ERROR;
345 }
346 return status;
347 }
348
349 bool _isDesiredError(AnalysisError error) {
350 if (error.errorCode.type == ErrorType.TODO) {
351 return false;
352 }
353 if (computeSeverity(error, options.enableTypeChecks) ==
354 ErrorSeverity.INFO &&
355 options.disableHints) {
356 return false;
357 }
358 return true;
359 }
360
361 /**
362 * Determine whether the given URI refers to a package other than the package
363 * being analyzed.
364 */
365 bool _isOtherPackage(Uri uri) {
366 if (uri.scheme != 'package') {
367 return false;
368 }
369 if (_selfPackageName != null &&
370 uri.pathSegments.length > 0 &&
371 uri.pathSegments[0] == _selfPackageName) {
372 return false;
373 }
374 return true;
375 }
376
377 _printColdPerf() {
378 // print cold VM performance numbers
379 int totalTime = JavaSystem.currentTimeMillis() - startTime;
380 int otherTime = totalTime;
381 for (PerformanceTag tag in PerformanceTag.all) {
382 if (tag != PerformanceTag.UNKNOWN) {
383 int tagTime = tag.elapsedMs;
384 stdout.writeln('${tag.label}-cold:$tagTime');
385 otherTime -= tagTime;
386 }
387 }
388 stdout.writeln('other-cold:$otherTime');
389 stdout.writeln("total-cold:$totalTime");
390 }
391
392 _printErrorsAndPerf() {
393 // The following is a hack. We currently print out to stderr to ensure that
394 // when in batch mode we print to stderr, this is because the prints from
395 // batch are made to stderr. The reason that options.shouldBatch isn't used
396 // is because when the argument flags are constructed in BatchRunner and
397 // passed in from batch mode which removes the batch flag to prevent the
398 // "cannot have the batch flag and source file" error message.
399 IOSink sink = options.machineFormat ? stderr : stdout;
400
401 // print errors
402 ErrorFormatter formatter =
403 new ErrorFormatter(sink, options, _isDesiredError);
404 formatter.formatErrors(errorInfos);
405
406 // print performance numbers
407 if (options.perf || options.warmPerf) {
408 int totalTime = JavaSystem.currentTimeMillis() - startTime;
409 int otherTime = totalTime;
410 for (PerformanceTag tag in PerformanceTag.all) {
411 if (tag != PerformanceTag.UNKNOWN) {
412 int tagTime = tag.elapsedMs;
413 stdout.writeln('${tag.label}:$tagTime');
414 otherTime -= tagTime;
415 }
416 }
417 stdout.writeln('other:$otherTime');
418 stdout.writeln("total:$totalTime");
419 }
420 }
421
422 /**
423 * Compute the severity of the error; however, if
424 * [enableTypeChecks] is false, then de-escalate checked-mode compile time
425 * errors to a severity of [ErrorSeverity.INFO].
426 */
427 static ErrorSeverity computeSeverity(
428 AnalysisError error, bool enableTypeChecks) {
429 if (!enableTypeChecks &&
430 error.errorCode.type == ErrorType.CHECKED_MODE_COMPILE_TIME_ERROR) {
431 return ErrorSeverity.INFO;
432 }
433 return error.errorCode.errorSeverity;
434 }
435
436 static JavaFile getPackageDirectoryFor(JavaFile sourceFile) {
437 // we are going to ask parent file, so get absolute path
438 sourceFile = sourceFile.getAbsoluteFile();
439 // look in the containing directories
440 JavaFile dir = sourceFile.getParentFile();
441 while (dir != null) {
442 JavaFile packagesDir = new JavaFile.relative(dir, "packages");
443 if (packagesDir.exists()) {
444 return packagesDir;
445 }
446 dir = dir.getParentFile();
447 }
448 // not found
449 return null;
450 }
451
452 /**
453 * Convert [sourcePath] into an absolute path.
454 */
455 static String _normalizeSourcePath(String sourcePath) {
456 return new File(sourcePath).absolute.path;
457 }
458 }
459
460 /**
461 * This [Logger] prints out information comments to [stdout] and error messages
462 * to [stderr].
463 */
464 class StdLogger extends Logger {
465 final bool log;
466
467 StdLogger(this.log);
468
469 @override
470 void logError(String message, [CaughtException exception]) {
471 stderr.writeln(message);
472 if (exception != null) {
473 stderr.writeln(exception);
474 }
475 }
476
477 @override
478 void logError2(String message, Object exception) {
479 stderr.writeln(message);
480 }
481
482 @override
483 void logInformation(String message, [CaughtException exception]) {
484 if (log) {
485 stdout.writeln(message);
486 if (exception != null) {
487 stderr.writeln(exception);
488 }
489 }
490 }
491
492 @override
493 void logInformation2(String message, Object exception) {
494 if (log) {
495 stdout.writeln(message);
496 }
497 }
498 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698