| Index: pkg/analyzer/lib/src/analyzer_impl.dart
 | 
| ===================================================================
 | 
| --- pkg/analyzer/lib/src/analyzer_impl.dart	(revision 45350)
 | 
| +++ pkg/analyzer/lib/src/analyzer_impl.dart	(working copy)
 | 
| @@ -1,498 +0,0 @@
 | 
| -// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 | 
| -// for details. All rights reserved. Use of this source code is governed by a
 | 
| -// BSD-style license that can be found in the LICENSE file.
 | 
| -
 | 
| -library analyzer_impl;
 | 
| -
 | 
| -import 'dart:async';
 | 
| -import 'dart:collection';
 | 
| -import 'dart:io';
 | 
| -
 | 
| -import 'package:analyzer/file_system/file_system.dart' show Folder;
 | 
| -import 'package:analyzer/file_system/physical_file_system.dart';
 | 
| -import 'package:analyzer/source/package_map_provider.dart';
 | 
| -import 'package:analyzer/source/package_map_resolver.dart';
 | 
| -import 'package:analyzer/source/pub_package_map_provider.dart';
 | 
| -import 'package:analyzer/src/error_formatter.dart';
 | 
| -import 'package:analyzer/src/generated/java_core.dart' show JavaSystem;
 | 
| -import 'package:analyzer/src/generated/java_engine.dart';
 | 
| -import 'package:analyzer/src/generated/utilities_general.dart';
 | 
| -
 | 
| -import '../options.dart';
 | 
| -import 'generated/constant.dart';
 | 
| -import 'generated/element.dart';
 | 
| -import 'generated/engine.dart';
 | 
| -import 'generated/error.dart';
 | 
| -import 'generated/java_io.dart';
 | 
| -import 'generated/sdk_io.dart';
 | 
| -import 'generated/source_io.dart';
 | 
| -
 | 
| -DirectoryBasedDartSdk sdk;
 | 
| -
 | 
| -/**
 | 
| - * The maximum number of sources for which AST structures should be kept in the cache.
 | 
| - */
 | 
| -const int _MAX_CACHE_SIZE = 512;
 | 
| -
 | 
| -/// Analyzes single library [File].
 | 
| -class AnalyzerImpl {
 | 
| -  final String sourcePath;
 | 
| -
 | 
| -  final CommandLineOptions options;
 | 
| -  final int startTime;
 | 
| -
 | 
| -  /**
 | 
| -   * True if the analyzer is running in batch mode.
 | 
| -   */
 | 
| -  final bool isBatch;
 | 
| -
 | 
| -  ContentCache contentCache = new ContentCache();
 | 
| -
 | 
| -  SourceFactory sourceFactory;
 | 
| -  AnalysisContext context;
 | 
| -  Source librarySource;
 | 
| -  /// All [Source]s references by the analyzed library.
 | 
| -  final Set<Source> sources = new Set<Source>();
 | 
| -
 | 
| -  /// All [AnalysisErrorInfo]s in the analyzed library.
 | 
| -  final List<AnalysisErrorInfo> errorInfos = new List<AnalysisErrorInfo>();
 | 
| -
 | 
| -  /// [HashMap] between sources and analysis error infos.
 | 
| -  final HashMap<Source, AnalysisErrorInfo> sourceErrorsMap =
 | 
| -      new HashMap<Source, AnalysisErrorInfo>();
 | 
| -
 | 
| -  /**
 | 
| -   * If the file specified on the command line is part of a package, the name
 | 
| -   * of that package.  Otherwise `null`.  This allows us to analyze the file
 | 
| -   * specified on the command line as though it is reached via a "package:"
 | 
| -   * URI, but avoid suppressing its output in the event that the user has not
 | 
| -   * specified the "--package-warnings" option.
 | 
| -   */
 | 
| -  String _selfPackageName;
 | 
| -
 | 
| -  AnalyzerImpl(String sourcePath, this.options, this.startTime, this.isBatch)
 | 
| -      : sourcePath = _normalizeSourcePath(sourcePath) {
 | 
| -    if (sdk == null) {
 | 
| -      sdk = new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /// Returns the maximal [ErrorSeverity] of the recorded errors.
 | 
| -  ErrorSeverity get maxErrorSeverity {
 | 
| -    var status = ErrorSeverity.NONE;
 | 
| -    for (AnalysisErrorInfo errorInfo in errorInfos) {
 | 
| -      for (AnalysisError error in errorInfo.errors) {
 | 
| -        if (!_isDesiredError(error)) {
 | 
| -          continue;
 | 
| -        }
 | 
| -        var severity = computeSeverity(error, options.enableTypeChecks);
 | 
| -        status = status.max(severity);
 | 
| -      }
 | 
| -    }
 | 
| -    return status;
 | 
| -  }
 | 
| -
 | 
| -  void addCompilationUnitSource(CompilationUnitElement unit,
 | 
| -      Set<LibraryElement> libraries, Set<CompilationUnitElement> units) {
 | 
| -    if (unit == null || units.contains(unit)) {
 | 
| -      return;
 | 
| -    }
 | 
| -    units.add(unit);
 | 
| -    sources.add(unit.source);
 | 
| -  }
 | 
| -
 | 
| -  void addLibrarySources(LibraryElement library, Set<LibraryElement> libraries,
 | 
| -      Set<CompilationUnitElement> units) {
 | 
| -    if (library == null || !libraries.add(library)) {
 | 
| -      return;
 | 
| -    }
 | 
| -    // may be skip library
 | 
| -    {
 | 
| -      UriKind uriKind = library.source.uriKind;
 | 
| -      // Optionally skip package: libraries.
 | 
| -      if (!options.showPackageWarnings && _isOtherPackage(library.source.uri)) {
 | 
| -        return;
 | 
| -      }
 | 
| -      // Optionally skip SDK libraries.
 | 
| -      if (!options.showSdkWarnings && uriKind == UriKind.DART_URI) {
 | 
| -        return;
 | 
| -      }
 | 
| -    }
 | 
| -    // add compilation units
 | 
| -    addCompilationUnitSource(library.definingCompilationUnit, libraries, units);
 | 
| -    for (CompilationUnitElement child in library.parts) {
 | 
| -      addCompilationUnitSource(child, libraries, units);
 | 
| -    }
 | 
| -    // add referenced libraries
 | 
| -    for (LibraryElement child in library.importedLibraries) {
 | 
| -      addLibrarySources(child, libraries, units);
 | 
| -    }
 | 
| -    for (LibraryElement child in library.exportedLibraries) {
 | 
| -      addLibrarySources(child, libraries, units);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Treats the [sourcePath] as the top level library and analyzes it using a
 | 
| -   * asynchronous algorithm over the analysis engine.
 | 
| -   */
 | 
| -  void analyzeAsync() {
 | 
| -    setupForAnalysis();
 | 
| -    _analyzeAsync();
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Treats the [sourcePath] as the top level library and analyzes it using a
 | 
| -   * synchronous algorithm over the analysis engine. If [printMode] is `0`,
 | 
| -   * then no error or performance information is printed. If [printMode] is `1`,
 | 
| -   * then both will be printed. If [printMode] is `2`, then only performance
 | 
| -   * information will be printed, and it will be marked as being for a cold VM.
 | 
| -   */
 | 
| -  ErrorSeverity analyzeSync({int printMode: 1}) {
 | 
| -    setupForAnalysis();
 | 
| -    return _analyzeSync(printMode);
 | 
| -  }
 | 
| -
 | 
| -  Source computeLibrarySource() {
 | 
| -    JavaFile sourceFile = new JavaFile(sourcePath);
 | 
| -    Source source = sdk.fromFileUri(sourceFile.toURI());
 | 
| -    if (source != null) {
 | 
| -      return source;
 | 
| -    }
 | 
| -    source = new FileBasedSource.con2(sourceFile.toURI(), sourceFile);
 | 
| -    Uri uri = context.sourceFactory.restoreUri(source);
 | 
| -    if (uri == null) {
 | 
| -      return source;
 | 
| -    }
 | 
| -    return new FileBasedSource.con2(uri, sourceFile);
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Create and return the source factory to be used by the analysis context.
 | 
| -   */
 | 
| -  SourceFactory createSourceFactory() {
 | 
| -    List<UriResolver> resolvers = [
 | 
| -      new CustomUriResolver(options.customUrlMappings),
 | 
| -      new DartUriResolver(sdk)
 | 
| -    ];
 | 
| -    if (options.packageRootPath != null) {
 | 
| -      JavaFile packageDirectory = new JavaFile(options.packageRootPath);
 | 
| -      resolvers.add(new PackageUriResolver([packageDirectory]));
 | 
| -    } else {
 | 
| -      PubPackageMapProvider pubPackageMapProvider =
 | 
| -          new PubPackageMapProvider(PhysicalResourceProvider.INSTANCE, sdk);
 | 
| -      PackageMapInfo packageMapInfo = pubPackageMapProvider.computePackageMap(
 | 
| -          PhysicalResourceProvider.INSTANCE.getResource('.'));
 | 
| -      Map<String, List<Folder>> packageMap = packageMapInfo.packageMap;
 | 
| -      if (packageMap != null) {
 | 
| -        resolvers.add(new PackageMapUriResolver(
 | 
| -            PhysicalResourceProvider.INSTANCE, packageMap));
 | 
| -      }
 | 
| -    }
 | 
| -    resolvers.add(new FileUriResolver());
 | 
| -    return new SourceFactory(resolvers);
 | 
| -  }
 | 
| -
 | 
| -  void prepareAnalysisContext() {
 | 
| -    sourceFactory = createSourceFactory();
 | 
| -    context = AnalysisEngine.instance.createAnalysisContext();
 | 
| -    context.sourceFactory = sourceFactory;
 | 
| -    Map<String, String> definedVariables = options.definedVariables;
 | 
| -    if (!definedVariables.isEmpty) {
 | 
| -      DeclaredVariables declaredVariables = context.declaredVariables;
 | 
| -      definedVariables.forEach((String variableName, String value) {
 | 
| -        declaredVariables.define(variableName, value);
 | 
| -      });
 | 
| -    }
 | 
| -    // Uncomment the following to have errors reported on stdout and stderr
 | 
| -    AnalysisEngine.instance.logger = new StdLogger(options.log);
 | 
| -
 | 
| -    // set options for context
 | 
| -    AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
 | 
| -    contextOptions.cacheSize = _MAX_CACHE_SIZE;
 | 
| -    contextOptions.hint = !options.disableHints;
 | 
| -    contextOptions.enableNullAwareOperators = options.enableNullAwareOperators;
 | 
| -    contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
 | 
| -    contextOptions.analyzeFunctionBodiesPredicate =
 | 
| -        _analyzeFunctionBodiesPredicate;
 | 
| -    contextOptions.generateImplicitErrors = options.showPackageWarnings;
 | 
| -    contextOptions.generateSdkErrors = options.showSdkWarnings;
 | 
| -    context.analysisOptions = contextOptions;
 | 
| -
 | 
| -    librarySource = computeLibrarySource();
 | 
| -
 | 
| -    Uri libraryUri = librarySource.uri;
 | 
| -    if (libraryUri.scheme == 'package' && libraryUri.pathSegments.length > 0) {
 | 
| -      _selfPackageName = libraryUri.pathSegments[0];
 | 
| -    }
 | 
| -
 | 
| -    // Create and add a ChangeSet
 | 
| -    ChangeSet changeSet = new ChangeSet();
 | 
| -    changeSet.addedSource(librarySource);
 | 
| -    context.applyChanges(changeSet);
 | 
| -  }
 | 
| -
 | 
| -  /// Fills [errorInfos] using [sources].
 | 
| -  void prepareErrors() {
 | 
| -    for (Source source in sources) {
 | 
| -      context.computeErrors(source);
 | 
| -      var sourceErrors = context.getErrors(source);
 | 
| -      errorInfos.add(sourceErrors);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /// Fills [sources].
 | 
| -  void prepareSources(LibraryElement library) {
 | 
| -    var units = new Set<CompilationUnitElement>();
 | 
| -    var libraries = new Set<LibraryElement>();
 | 
| -    addLibrarySources(library, libraries, units);
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Setup local fields such as the analysis context for analysis.
 | 
| -   */
 | 
| -  void setupForAnalysis() {
 | 
| -    sources.clear();
 | 
| -    errorInfos.clear();
 | 
| -    if (sourcePath == null) {
 | 
| -      throw new ArgumentError("sourcePath cannot be null");
 | 
| -    }
 | 
| -    // prepare context
 | 
| -    prepareAnalysisContext();
 | 
| -  }
 | 
| -
 | 
| -  /// The async version of the analysis
 | 
| -  void _analyzeAsync() {
 | 
| -    new Future(context.performAnalysisTask).then((AnalysisResult result) {
 | 
| -      List<ChangeNotice> notices = result.changeNotices;
 | 
| -      if (result.hasMoreWork) {
 | 
| -        // There is more work, record the set of sources, and then call self
 | 
| -        // again to perform next task
 | 
| -        for (ChangeNotice notice in notices) {
 | 
| -          sources.add(notice.source);
 | 
| -          sourceErrorsMap[notice.source] = notice;
 | 
| -        }
 | 
| -        return _analyzeAsync();
 | 
| -      }
 | 
| -      //
 | 
| -      // There are not any more tasks, set error code and print performance
 | 
| -      // numbers.
 | 
| -      //
 | 
| -      // prepare errors
 | 
| -      sourceErrorsMap.forEach((k, v) {
 | 
| -        errorInfos.add(sourceErrorsMap[k]);
 | 
| -      });
 | 
| -
 | 
| -      // print errors and performance numbers
 | 
| -      _printErrorsAndPerf();
 | 
| -
 | 
| -      // compute max severity and set exitCode
 | 
| -      ErrorSeverity status = maxErrorSeverity;
 | 
| -      if (status == ErrorSeverity.WARNING && options.warningsAreFatal) {
 | 
| -        status = ErrorSeverity.ERROR;
 | 
| -      }
 | 
| -      exitCode = status.ordinal;
 | 
| -    }).catchError((ex, st) {
 | 
| -      AnalysisEngine.instance.logger.logError("$ex\n$st");
 | 
| -    });
 | 
| -  }
 | 
| -
 | 
| -  bool _analyzeFunctionBodiesPredicate(Source source) {
 | 
| -    // TODO(paulberry): This function will need to be updated when we add the
 | 
| -    // ability to suppress errors, warnings, and hints for files reached via
 | 
| -    // custom URI's using the "--url-mapping" flag.
 | 
| -    if (source.uri.scheme == 'dart') {
 | 
| -      if (isBatch) {
 | 
| -        // When running in batch mode, the SDK files are cached from one
 | 
| -        // analysis run to the next.  So we need to parse function bodies even
 | 
| -        // if the user hasn't asked for errors/warnings from the SDK, since
 | 
| -        // they might ask for errors/warnings from the SDK in the future.
 | 
| -        return true;
 | 
| -      }
 | 
| -      return options.showSdkWarnings;
 | 
| -    }
 | 
| -    if (_isOtherPackage(source.uri)) {
 | 
| -      return options.showPackageWarnings;
 | 
| -    }
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  /// The sync version of analysis.
 | 
| -  ErrorSeverity _analyzeSync(int printMode) {
 | 
| -    // don't try to analyze parts
 | 
| -    if (context.computeKindOf(librarySource) == SourceKind.PART) {
 | 
| -      print("Only libraries can be analyzed.");
 | 
| -      print("$sourcePath is a part and can not be analyzed.");
 | 
| -      return ErrorSeverity.ERROR;
 | 
| -    }
 | 
| -    // resolve library
 | 
| -    var libraryElement = context.computeLibraryElement(librarySource);
 | 
| -    // prepare source and errors
 | 
| -    prepareSources(libraryElement);
 | 
| -    prepareErrors();
 | 
| -
 | 
| -    // print errors and performance numbers
 | 
| -    if (printMode == 1) {
 | 
| -      _printErrorsAndPerf();
 | 
| -    } else if (printMode == 2) {
 | 
| -      _printColdPerf();
 | 
| -    }
 | 
| -
 | 
| -    // compute max severity and set exitCode
 | 
| -    ErrorSeverity status = maxErrorSeverity;
 | 
| -    if (status == ErrorSeverity.WARNING && options.warningsAreFatal) {
 | 
| -      status = ErrorSeverity.ERROR;
 | 
| -    }
 | 
| -    return status;
 | 
| -  }
 | 
| -
 | 
| -  bool _isDesiredError(AnalysisError error) {
 | 
| -    if (error.errorCode.type == ErrorType.TODO) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    if (computeSeverity(error, options.enableTypeChecks) ==
 | 
| -            ErrorSeverity.INFO &&
 | 
| -        options.disableHints) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Determine whether the given URI refers to a package other than the package
 | 
| -   * being analyzed.
 | 
| -   */
 | 
| -  bool _isOtherPackage(Uri uri) {
 | 
| -    if (uri.scheme != 'package') {
 | 
| -      return false;
 | 
| -    }
 | 
| -    if (_selfPackageName != null &&
 | 
| -        uri.pathSegments.length > 0 &&
 | 
| -        uri.pathSegments[0] == _selfPackageName) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  _printColdPerf() {
 | 
| -    // print cold VM performance numbers
 | 
| -    int totalTime = JavaSystem.currentTimeMillis() - startTime;
 | 
| -    int otherTime = totalTime;
 | 
| -    for (PerformanceTag tag in PerformanceTag.all) {
 | 
| -      if (tag != PerformanceTag.UNKNOWN) {
 | 
| -        int tagTime = tag.elapsedMs;
 | 
| -        stdout.writeln('${tag.label}-cold:$tagTime');
 | 
| -        otherTime -= tagTime;
 | 
| -      }
 | 
| -    }
 | 
| -    stdout.writeln('other-cold:$otherTime');
 | 
| -    stdout.writeln("total-cold:$totalTime");
 | 
| -  }
 | 
| -
 | 
| -  _printErrorsAndPerf() {
 | 
| -    // The following is a hack. We currently print out to stderr to ensure that
 | 
| -    // when in batch mode we print to stderr, this is because the prints from
 | 
| -    // batch are made to stderr. The reason that options.shouldBatch isn't used
 | 
| -    // is because when the argument flags are constructed in BatchRunner and
 | 
| -    // passed in from batch mode which removes the batch flag to prevent the
 | 
| -    // "cannot have the batch flag and source file" error message.
 | 
| -    IOSink sink = options.machineFormat ? stderr : stdout;
 | 
| -
 | 
| -    // print errors
 | 
| -    ErrorFormatter formatter =
 | 
| -        new ErrorFormatter(sink, options, _isDesiredError);
 | 
| -    formatter.formatErrors(errorInfos);
 | 
| -
 | 
| -    // print performance numbers
 | 
| -    if (options.perf || options.warmPerf) {
 | 
| -      int totalTime = JavaSystem.currentTimeMillis() - startTime;
 | 
| -      int otherTime = totalTime;
 | 
| -      for (PerformanceTag tag in PerformanceTag.all) {
 | 
| -        if (tag != PerformanceTag.UNKNOWN) {
 | 
| -          int tagTime = tag.elapsedMs;
 | 
| -          stdout.writeln('${tag.label}:$tagTime');
 | 
| -          otherTime -= tagTime;
 | 
| -        }
 | 
| -      }
 | 
| -      stdout.writeln('other:$otherTime');
 | 
| -      stdout.writeln("total:$totalTime");
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Compute the severity of the error; however, if
 | 
| -   * [enableTypeChecks] is false, then de-escalate checked-mode compile time
 | 
| -   * errors to a severity of [ErrorSeverity.INFO].
 | 
| -   */
 | 
| -  static ErrorSeverity computeSeverity(
 | 
| -      AnalysisError error, bool enableTypeChecks) {
 | 
| -    if (!enableTypeChecks &&
 | 
| -        error.errorCode.type == ErrorType.CHECKED_MODE_COMPILE_TIME_ERROR) {
 | 
| -      return ErrorSeverity.INFO;
 | 
| -    }
 | 
| -    return error.errorCode.errorSeverity;
 | 
| -  }
 | 
| -
 | 
| -  static JavaFile getPackageDirectoryFor(JavaFile sourceFile) {
 | 
| -    // we are going to ask parent file, so get absolute path
 | 
| -    sourceFile = sourceFile.getAbsoluteFile();
 | 
| -    // look in the containing directories
 | 
| -    JavaFile dir = sourceFile.getParentFile();
 | 
| -    while (dir != null) {
 | 
| -      JavaFile packagesDir = new JavaFile.relative(dir, "packages");
 | 
| -      if (packagesDir.exists()) {
 | 
| -        return packagesDir;
 | 
| -      }
 | 
| -      dir = dir.getParentFile();
 | 
| -    }
 | 
| -    // not found
 | 
| -    return null;
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Convert [sourcePath] into an absolute path.
 | 
| -   */
 | 
| -  static String _normalizeSourcePath(String sourcePath) {
 | 
| -    return new File(sourcePath).absolute.path;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * This [Logger] prints out information comments to [stdout] and error messages
 | 
| - * to [stderr].
 | 
| - */
 | 
| -class StdLogger extends Logger {
 | 
| -  final bool log;
 | 
| -
 | 
| -  StdLogger(this.log);
 | 
| -
 | 
| -  @override
 | 
| -  void logError(String message, [CaughtException exception]) {
 | 
| -    stderr.writeln(message);
 | 
| -    if (exception != null) {
 | 
| -      stderr.writeln(exception);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  @override
 | 
| -  void logError2(String message, Object exception) {
 | 
| -    stderr.writeln(message);
 | 
| -  }
 | 
| -
 | 
| -  @override
 | 
| -  void logInformation(String message, [CaughtException exception]) {
 | 
| -    if (log) {
 | 
| -      stdout.writeln(message);
 | 
| -      if (exception != null) {
 | 
| -        stderr.writeln(exception);
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  @override
 | 
| -  void logInformation2(String message, Object exception) {
 | 
| -    if (log) {
 | 
| -      stdout.writeln(message);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| 
 |