blob: ec27a693d5b03e55da62bc9c4f080379d8269b83 [file] [log] [blame]
// Copyright (c) 2014, 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.
import 'dart:collection';
import 'dart:typed_data';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:front_end/src/fasta/scanner/token.dart';
import 'package:path/path.dart' as pathos;
import 'package:pub_semver/pub_semver.dart';
export 'package:analyzer/error/listener.dart' show RecordingErrorListener;
export 'package:analyzer/src/generated/timestamped_data.dart'
show TimestampedData;
/// Used by [AnalysisOptions] to allow function bodies to be analyzed in some
/// sources but not others.
typedef bool AnalyzeFunctionBodiesPredicate(Source source);
/// A context in which a single analysis can be performed and incrementally
/// maintained. The context includes such information as the version of the SDK
/// being analyzed against as well as the package-root used to resolve 'package:'
/// URI's. (Both of which are known indirectly through the [SourceFactory].)
///
/// An analysis context also represents the state of the analysis, which includes
/// knowing which sources have been included in the analysis (either directly or
/// indirectly) and the results of the analysis. Sources must be added and
/// removed from the context using the method [applyChanges], which is also used
/// to notify the context when sources have been modified and, consequently,
/// previously known results might have been invalidated.
///
/// There are two ways to access the results of the analysis. The most common is
/// to use one of the 'get' methods to access the results. The 'get' methods have
/// the advantage that they will always return quickly, but have the disadvantage
/// that if the results are not currently available they will return either
/// nothing or in some cases an incomplete result. The second way to access
/// results is by using one of the 'compute' methods. The 'compute' methods will
/// always attempt to compute the requested results but might block the caller
/// for a significant period of time.
///
/// When results have been invalidated, have never been computed (as is the case
/// for newly added sources), or have been removed from the cache, they are
/// <b>not</b> automatically recreated. They will only be recreated if one of the
/// 'compute' methods is invoked.
///
/// However, this is not always acceptable. Some clients need to keep the
/// analysis results up-to-date. For such clients there is a mechanism that
/// allows them to incrementally perform needed analysis and get notified of the
/// consequent changes to the analysis results. This mechanism is realized by the
/// method [performAnalysisTask].
///
/// Analysis engine allows for having more than one context. This can be used,
/// for example, to perform one analysis based on the state of files on disk and
/// a separate analysis based on the state of those files in open editors. It can
/// also be used to perform an analysis based on a proposed future state, such as
/// the state after a refactoring.
abstract class AnalysisContext {
/// Return the set of analysis options controlling the behavior of this
/// context. Clients should not modify the returned set of options.
AnalysisOptions get analysisOptions;
/// Set the set of analysis options controlling the behavior of this context to
/// the given [options]. Clients can safely assume that all necessary analysis
/// results have been invalidated.
void set analysisOptions(AnalysisOptions options);
/// Return the set of declared variables used when computing constant values.
DeclaredVariables get declaredVariables;
/// Return the source factory used to create the sources that can be analyzed
/// in this context.
SourceFactory get sourceFactory;
/// Set the source factory used to create the sources that can be analyzed in
/// this context to the given source [factory]. Clients can safely assume that
/// all analysis results have been invalidated.
void set sourceFactory(SourceFactory factory);
/// Return a type provider for this context or throw [AnalysisException] if
/// either `dart:core` or `dart:async` cannot be resolved.
TypeProvider get typeProvider;
/// Return a type system for this context.
TypeSystem get typeSystem;
/// Apply the changes specified by the given [changeSet] to this context. Any
/// analysis results that have been invalidated by these changes will be
/// removed.
/// TODO(scheglov) This method is referenced by the internal indexer tool.
void applyChanges(ChangeSet changeSet);
}
/// The entry point for the functionality provided by the analysis engine. There
/// is a single instance of this class.
class AnalysisEngine {
/// The suffix used for Dart source files.
static const String SUFFIX_DART = "dart";
/// The short suffix used for HTML files.
static const String SUFFIX_HTM = "htm";
/// The long suffix used for HTML files.
static const String SUFFIX_HTML = "html";
/// The deprecated file name used for analysis options files.
static const String ANALYSIS_OPTIONS_FILE = '.analysis_options';
/// The file name used for analysis options files.
static const String ANALYSIS_OPTIONS_YAML_FILE = 'analysis_options.yaml';
/// The file name used for pubspec files.
static const String PUBSPEC_YAML_FILE = 'pubspec.yaml';
/// The file name used for Android manifest files.
static const String ANDROID_MANIFEST_FILE = 'AndroidManifest.xml';
/// The unique instance of this class.
static final AnalysisEngine instance = new AnalysisEngine._();
/// The logger that should receive information about errors within the analysis
/// engine.
Logger _logger = Logger.NULL;
/// The instrumentation service that is to be used by this analysis engine.
InstrumentationService _instrumentationService =
InstrumentationService.NULL_SERVICE;
/// The partition manager being used to manage the shared partitions.
final PartitionManager partitionManager = new PartitionManager();
AnalysisEngine._();
/// Return the instrumentation service that is to be used by this analysis
/// engine.
InstrumentationService get instrumentationService => _instrumentationService;
/// Set the instrumentation service that is to be used by this analysis engine
/// to the given [service].
void set instrumentationService(InstrumentationService service) {
if (service == null) {
_instrumentationService = InstrumentationService.NULL_SERVICE;
} else {
_instrumentationService = service;
}
}
/// Return the logger that should receive information about errors within the
/// analysis engine.
Logger get logger => _logger;
/// Set the logger that should receive information about errors within the
/// analysis engine to the given [logger].
void set logger(Logger logger) {
this._logger = logger ?? Logger.NULL;
}
/// Clear any caches holding on to analysis results so that a full re-analysis
/// will be performed the next time an analysis context is created.
void clearCaches() {
partitionManager.clearCache();
// See https://github.com/dart-lang/sdk/issues/30314.
StringToken.canonicalizer.clear();
}
/// Create and return a new context in which analysis can be performed.
AnalysisContext createAnalysisContext() {
return new AnalysisContextImpl();
}
/// A utility method that clients can use to process all of the required
/// plugins. This method can only be used by clients that do not need to
/// process any other plugins.
@deprecated
void processRequiredPlugins() {}
/// Return `true` if the given [fileName] is an analysis options file.
static bool isAnalysisOptionsFileName(String fileName,
[pathos.Context context]) {
if (fileName == null) {
return false;
}
String basename = (context ?? pathos.posix).basename(fileName);
return basename == ANALYSIS_OPTIONS_FILE ||
basename == ANALYSIS_OPTIONS_YAML_FILE;
}
/// Return `true` if the given [fileName] is assumed to contain Dart source
/// code.
static bool isDartFileName(String fileName) {
if (fileName == null) {
return false;
}
String extension = FileNameUtilities.getExtension(fileName).toLowerCase();
return extension == SUFFIX_DART;
}
/// Return `true` if the given [fileName] is AndroidManifest.xml
static bool isManifestFileName(String fileName) {
if (fileName == null) {
return false;
}
return fileName.endsWith(AnalysisEngine.ANDROID_MANIFEST_FILE);
}
}
/// The analysis errors and line information for the errors.
abstract class AnalysisErrorInfo {
/// Return the errors that as a result of the analysis, or `null` if there were
/// no errors.
List<AnalysisError> get errors;
/// Return the line information associated with the errors, or `null` if there
/// were no errors.
LineInfo get lineInfo;
}
/// The analysis errors and line info associated with a source.
class AnalysisErrorInfoImpl implements AnalysisErrorInfo {
/// The analysis errors associated with a source, or `null` if there are no
/// errors.
@override
final List<AnalysisError> errors;
/// The line information associated with the errors, or `null` if there are no
/// errors.
final LineInfo lineInfo;
/// Initialize an newly created error info with the given [errors] and
/// [lineInfo].
AnalysisErrorInfoImpl(this.errors, this.lineInfo);
}
/// A set of analysis options used to control the behavior of an analysis
/// context.
abstract class AnalysisOptions {
/// The length of the list returned by [signature].
static const int signatureLength = 4;
/// Function that returns `true` if analysis is to parse and analyze function
/// bodies for a given source.
AnalyzeFunctionBodiesPredicate get analyzeFunctionBodiesPredicate;
/// Return the maximum number of sources for which AST structures should be
/// kept in the cache.
///
/// DEPRECATED: This setting no longer has any effect.
@deprecated
int get cacheSize;
/// A flag indicating whether to run checks on AndroidManifest.xml file to
/// see if it is complaint with Chrome OS.
bool get chromeOsManifestChecks;
/// The set of features that are globally enabled for this context.
FeatureSet get contextFeatures;
/// Return `true` if analysis is to generate dart2js related hint results.
bool get dart2jsHint;
/// Return `true` if cache flushing should be disabled. Setting this option to
/// `true` can improve analysis speed at the expense of memory usage. It may
/// also be useful for working around bugs.
///
/// This option should not be used when the analyzer is part of a long running
/// process (such as the analysis server) because it has the potential to
/// prevent memory from being reclaimed.
bool get disableCacheFlushing;
/// Return `true` if the parser is to parse asserts in the initializer list of
/// a constructor.
@deprecated
bool get enableAssertInitializer;
/// Return `true` to enable custom assert messages (DEP 37).
@deprecated
bool get enableAssertMessage;
/// Return `true` to if analysis is to enable async support.
@deprecated
bool get enableAsync;
/// Return `true` to enable interface libraries (DEP 40).
@deprecated
bool get enableConditionalDirectives;
/// Return a list containing the names of the experiments that are enabled in
/// the context associated with these options.
///
/// The process around these experiments is described in this
/// [doc](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md).
List<String> get enabledExperiments;
/// Return a list of the names of the packages for which, if they define a
/// plugin, the plugin should be enabled.
List<String> get enabledPluginNames;
/// Return `true` to enable generic methods (DEP 22).
@deprecated
bool get enableGenericMethods => null;
/// Return `true` if access to field formal parameters should be allowed in a
/// constructor's initializer list.
@deprecated
bool get enableInitializingFormalAccess;
/// Return `true` to enable the lazy compound assignment operators '&&=' and
/// '||='.
bool get enableLazyAssignmentOperators;
/// Return `true` if mixins are allowed to inherit from types other than
/// Object, and are allowed to reference `super`.
@deprecated
bool get enableSuperMixins;
/// Return `true` if timing data should be gathered during execution.
bool get enableTiming;
/// Return `true` to enable the use of URIs in part-of directives.
@deprecated
bool get enableUriInPartOf;
/// Return a list of error processors that are to be used when reporting
/// errors in some analysis context.
List<ErrorProcessor> get errorProcessors;
/// Return a list of exclude patterns used to exclude some sources from
/// analysis.
List<String> get excludePatterns;
/// Return `true` if errors, warnings and hints should be generated for sources
/// that are implicitly being analyzed. The default value is `true`.
bool get generateImplicitErrors;
/// Return `true` if errors, warnings and hints should be generated for sources
/// in the SDK. The default value is `false`.
bool get generateSdkErrors;
/// Return `true` if analysis is to generate hint results (e.g. type inference
/// based information and pub best practices).
bool get hint;
/// Return `true` if analysis is to generate lint warnings.
bool get lint;
/// Return a list of the lint rules that are to be run in an analysis context
/// if [lint] returns `true`.
List<Linter> get lintRules;
/// A mapping from Dart SDK library name (e.g. "dart:core") to a list of paths
/// to patch files that should be applied to the library.
Map<String, List<String>> get patchPaths;
/// Return `true` if analysis is to parse comments.
bool get preserveComments;
/// Return `true` if analyzer should enable the use of Dart 2.0 features.
///
/// This getter is deprecated, and is hard-coded to always return true.
@Deprecated(
'This getter is deprecated and is hard-coded to always return true.')
bool get previewDart2;
/// The version range for the SDK specified in `pubspec.yaml`, or `null` if
/// there is no `pubspec.yaml` or if it does not contain an SDK range.
VersionConstraint get sdkVersionConstraint;
/// Return the opaque signature of the options.
///
/// The length of the list is guaranteed to equal [signatureLength].
Uint32List get signature;
/// Return `true` if strong mode analysis should be used.
///
/// This getter is deprecated, and is hard-coded to always return true.
@Deprecated(
'This getter is deprecated and is hard-coded to always return true.')
bool get strongMode;
/// Return `true` if dependencies between computed results should be tracked
/// by analysis cache. This option should only be set to `false` if analysis
/// is performed in such a way that none of the inputs is ever changed
/// during the life time of the context.
bool get trackCacheDependencies;
/// Return `true` if analyzer should use the Dart 2.0 Front End parser.
bool get useFastaParser;
/// Return `true` the lint with the given [name] is enabled.
bool isLintEnabled(String name);
/// Reset the state of this set of analysis options to its original state.
void resetToDefaults();
/// Set the values of the cross-context options to match those in the given set
/// of [options].
@deprecated
void setCrossContextOptionsFrom(AnalysisOptions options);
/// Determine whether two signatures returned by [signature] are equal.
static bool signaturesEqual(Uint32List a, Uint32List b) {
assert(a.length == signatureLength);
assert(b.length == signatureLength);
if (a.length != b.length) {
return false;
}
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
}
/// A set of analysis options used to control the behavior of an analysis
/// context.
class AnalysisOptionsImpl implements AnalysisOptions {
/// DEPRECATED: The maximum number of sources for which data should be kept in
/// the cache.
///
/// This constant no longer has any effect.
@deprecated
static const int DEFAULT_CACHE_SIZE = 64;
/// The length of the list returned by [unlinkedSignature].
static const int unlinkedSignatureLength = 4;
/// A predicate indicating whether analysis is to parse and analyze function
/// bodies.
AnalyzeFunctionBodiesPredicate _analyzeFunctionBodiesPredicate =
_analyzeAllFunctionBodies;
/// The cached [unlinkedSignature].
Uint32List _unlinkedSignature;
/// The cached [signature].
Uint32List _signature;
@override
VersionConstraint sdkVersionConstraint;
@override
@deprecated
int cacheSize = 64;
@override
bool dart2jsHint = false;
List<String> _enabledExperiments = const <String>[];
ExperimentStatus _contextFeatures = ExperimentStatus();
@override
List<String> enabledPluginNames = const <String>[];
@override
bool enableLazyAssignmentOperators = false;
@override
bool enableTiming = false;
/// A list of error processors that are to be used when reporting errors in
/// some analysis context.
List<ErrorProcessor> _errorProcessors;
/// A list of exclude patterns used to exclude some sources from analysis.
List<String> _excludePatterns;
@override
bool generateImplicitErrors = true;
@override
bool generateSdkErrors = false;
@override
bool hint = true;
@override
bool lint = false;
/// The lint rules that are to be run in an analysis context if [lint] returns
/// `true`.
List<Linter> _lintRules;
Map<String, List<String>> patchPaths = {};
@override
bool preserveComments = true;
/// A flag indicating whether strong-mode inference hints should be
/// used. This flag is not exposed in the interface, and should be
/// replaced by something more general.
// TODO(leafp): replace this with something more general
bool strongModeHints = false;
@override
bool trackCacheDependencies = true;
@override
bool useFastaParser = true;
@override
bool disableCacheFlushing = false;
/// A flag indicating whether implicit casts are allowed in [strongMode]
/// (they are always allowed in Dart 1.0 mode).
///
/// This option is experimental and subject to change.
bool implicitCasts = true;
/// A flag indicating whether implicit dynamic type is allowed, on by default.
///
/// This flag can be used without necessarily enabling [strongMode], but it is
/// designed with strong mode's type inference in mind. Without type inference,
/// it will raise many errors. Also it does not provide type safety without
/// strong mode.
///
/// This option is experimental and subject to change.
bool implicitDynamic = true;
/// A flag indicating whether inference failures are allowed, off by default.
///
/// This option is experimental and subject to change.
bool strictInference = false;
/// Whether raw types (types without explicit type arguments, such as `List`)
/// should be reported as potential problems.
///
/// Raw types are a common source of `dynamic` being introduced implicitly.
/// This often leads to cast failures later on in the program.
bool strictRawTypes = false;
@override
bool chromeOsManifestChecks = false;
/// Initialize a newly created set of analysis options to have their default
/// values.
AnalysisOptionsImpl();
/// Initialize a newly created set of analysis options to have the same values
/// as those in the given set of analysis [options].
AnalysisOptionsImpl.from(AnalysisOptions options) {
analyzeFunctionBodiesPredicate = options.analyzeFunctionBodiesPredicate;
dart2jsHint = options.dart2jsHint;
enabledExperiments = options.enabledExperiments;
enabledPluginNames = options.enabledPluginNames;
enableLazyAssignmentOperators = options.enableLazyAssignmentOperators;
enableTiming = options.enableTiming;
errorProcessors = options.errorProcessors;
excludePatterns = options.excludePatterns;
generateImplicitErrors = options.generateImplicitErrors;
generateSdkErrors = options.generateSdkErrors;
hint = options.hint;
lint = options.lint;
lintRules = options.lintRules;
preserveComments = options.preserveComments;
useFastaParser = options.useFastaParser;
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
implicitCasts = options.implicitCasts;
implicitDynamic = options.implicitDynamic;
strictInference = options.strictInference;
strictRawTypes = options.strictRawTypes;
}
trackCacheDependencies = options.trackCacheDependencies;
disableCacheFlushing = options.disableCacheFlushing;
patchPaths = options.patchPaths;
sdkVersionConstraint = options.sdkVersionConstraint;
}
bool get analyzeFunctionBodies {
if (identical(analyzeFunctionBodiesPredicate, _analyzeAllFunctionBodies)) {
return true;
} else if (identical(
analyzeFunctionBodiesPredicate, _analyzeNoFunctionBodies)) {
return false;
} else {
throw new StateError('analyzeFunctionBodiesPredicate in use');
}
}
set analyzeFunctionBodies(bool value) {
if (value) {
analyzeFunctionBodiesPredicate = _analyzeAllFunctionBodies;
} else {
analyzeFunctionBodiesPredicate = _analyzeNoFunctionBodies;
}
}
@override
AnalyzeFunctionBodiesPredicate get analyzeFunctionBodiesPredicate =>
_analyzeFunctionBodiesPredicate;
set analyzeFunctionBodiesPredicate(AnalyzeFunctionBodiesPredicate value) {
if (value == null) {
throw new ArgumentError.notNull('analyzeFunctionBodiesPredicate');
}
_analyzeFunctionBodiesPredicate = value;
}
@override
FeatureSet get contextFeatures => _contextFeatures;
set contextFeatures(FeatureSet featureSet) {
_contextFeatures = featureSet;
_enabledExperiments = _contextFeatures.toStringList();
}
@deprecated
@override
bool get enableAssertInitializer => true;
@deprecated
void set enableAssertInitializer(bool enable) {}
@override
@deprecated
bool get enableAssertMessage => true;
@deprecated
void set enableAssertMessage(bool enable) {}
@deprecated
@override
bool get enableAsync => true;
@deprecated
void set enableAsync(bool enable) {}
/// A flag indicating whether interface libraries are to be supported (DEP 40).
bool get enableConditionalDirectives => true;
@deprecated
void set enableConditionalDirectives(_) {}
@override
List<String> get enabledExperiments => _enabledExperiments;
set enabledExperiments(List<String> enabledExperiments) {
_enabledExperiments = enabledExperiments;
_contextFeatures = ExperimentStatus.fromStrings(enabledExperiments);
}
@override
@deprecated
bool get enableGenericMethods => true;
@deprecated
void set enableGenericMethods(bool enable) {}
@deprecated
@override
bool get enableInitializingFormalAccess => true;
@deprecated
void set enableInitializingFormalAccess(bool enable) {}
@override
@deprecated
bool get enableSuperMixins => false;
@deprecated
void set enableSuperMixins(bool enable) {
// Ignored.
}
@deprecated
@override
bool get enableUriInPartOf => true;
@deprecated
void set enableUriInPartOf(bool enable) {}
@override
List<ErrorProcessor> get errorProcessors =>
_errorProcessors ??= const <ErrorProcessor>[];
/// Set the list of error [processors] that are to be used when reporting
/// errors in some analysis context.
void set errorProcessors(List<ErrorProcessor> processors) {
_errorProcessors = processors;
}
@override
List<String> get excludePatterns => _excludePatterns ??= const <String>[];
/// Set the exclude patterns used to exclude some sources from analysis to
/// those in the given list of [patterns].
void set excludePatterns(List<String> patterns) {
_excludePatterns = patterns;
}
/// The set of enabled experiments.
ExperimentStatus get experimentStatus => _contextFeatures;
/// Return `true` to enable mixin declarations.
/// https://github.com/dart-lang/language/issues/12
@deprecated
bool get isMixinSupportEnabled => true;
@deprecated
set isMixinSupportEnabled(bool value) {}
@override
List<Linter> get lintRules => _lintRules ??= const <Linter>[];
/// Set the lint rules that are to be run in an analysis context if [lint]
/// returns `true`.
void set lintRules(List<Linter> rules) {
_lintRules = rules;
}
@deprecated
@override
bool get previewDart2 => true;
@deprecated
set previewDart2(bool value) {}
@override
Uint32List get signature {
if (_signature == null) {
ApiSignature buffer = new ApiSignature();
// Append environment.
if (sdkVersionConstraint != null) {
buffer.addString(sdkVersionConstraint.toString());
}
// Append boolean flags.
buffer.addBool(enableLazyAssignmentOperators);
buffer.addBool(implicitCasts);
buffer.addBool(implicitDynamic);
buffer.addBool(strictInference);
buffer.addBool(strictRawTypes);
buffer.addBool(strongModeHints);
buffer.addBool(useFastaParser);
// Append enabled experiments.
buffer.addInt(enabledExperiments.length);
for (String experimentName in enabledExperiments) {
buffer.addString(experimentName);
}
// Append error processors.
buffer.addInt(errorProcessors.length);
for (ErrorProcessor processor in errorProcessors) {
buffer.addString(processor.description);
}
// Append lints.
buffer.addString(linterVersion ?? '');
buffer.addInt(lintRules.length);
for (Linter lintRule in lintRules) {
buffer.addString(lintRule.lintCode.uniqueName);
}
// Append plugin names.
buffer.addInt(enabledPluginNames.length);
for (String enabledPluginName in enabledPluginNames) {
buffer.addString(enabledPluginName);
}
// Hash and convert to Uint32List.
List<int> bytes = buffer.toByteList();
_signature = new Uint8List.fromList(bytes).buffer.asUint32List();
}
return _signature;
}
@override
bool get strongMode => true;
@Deprecated(
"The strongMode field is deprecated, and shouldn't be assigned to")
set strongMode(bool value) {}
/// Return the opaque signature of the options that affect unlinked data.
///
/// The length of the list is guaranteed to equal [unlinkedSignatureLength].
Uint32List get unlinkedSignature {
if (_unlinkedSignature == null) {
ApiSignature buffer = new ApiSignature();
// Append boolean flags.
buffer.addBool(enableLazyAssignmentOperators);
buffer.addBool(useFastaParser);
// Append enabled experiments.
buffer.addInt(enabledExperiments.length);
for (String experimentName in enabledExperiments) {
buffer.addString(experimentName);
}
// Hash and convert to Uint32List.
List<int> bytes = buffer.toByteList();
_unlinkedSignature = new Uint8List.fromList(bytes).buffer.asUint32List();
}
return _unlinkedSignature;
}
@override
bool isLintEnabled(String name) {
return lintRules.any((rule) => rule.name == name);
}
@override
void resetToDefaults() {
dart2jsHint = false;
disableCacheFlushing = false;
enabledExperiments = const <String>[];
enabledPluginNames = const <String>[];
enableLazyAssignmentOperators = false;
enableTiming = false;
_errorProcessors = null;
_excludePatterns = null;
generateImplicitErrors = true;
generateSdkErrors = false;
hint = true;
implicitCasts = true;
implicitDynamic = true;
strictInference = false;
strictRawTypes = false;
lint = false;
_lintRules = null;
patchPaths = {};
preserveComments = true;
strongModeHints = false;
trackCacheDependencies = true;
useFastaParser = true;
}
@deprecated
@override
void setCrossContextOptionsFrom(AnalysisOptions options) {
enableLazyAssignmentOperators = options.enableLazyAssignmentOperators;
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
}
}
/// Return whether the given lists of lints are equal.
static bool compareLints(List<Linter> a, List<Linter> b) {
if (a.length != b.length) {
return false;
}
for (int i = 0; i < a.length; i++) {
if (a[i].lintCode != b[i].lintCode) {
return false;
}
}
return true;
}
/// Predicate used for [analyzeFunctionBodiesPredicate] when
/// [analyzeFunctionBodies] is set to `true`.
static bool _analyzeAllFunctionBodies(Source _) => true;
/// Predicate used for [analyzeFunctionBodiesPredicate] when
/// [analyzeFunctionBodies] is set to `false`.
static bool _analyzeNoFunctionBodies(Source _) => false;
}
/// An indication of which sources have been added, changed, removed, or deleted.
/// In the case of a changed source, there are multiple ways of indicating the
/// nature of the change.
///
/// No source should be added to the change set more than once, either with the
/// same or a different kind of change. It does not make sense, for example, for
/// a source to be both added and removed, and it is redundant for a source to be
/// marked as changed in its entirety and changed in some specific range.
class ChangeSet {
/// A list containing the sources that have been added.
final List<Source> addedSources = new List<Source>();
/// A list containing the sources that have been changed.
final List<Source> changedSources = new List<Source>();
/// A table mapping the sources whose content has been changed to the current
/// content of those sources.
Map<Source, String> _changedContent = new HashMap<Source, String>();
/// A table mapping the sources whose content has been changed within a single
/// range to the current content of those sources and information about the
/// affected range.
final HashMap<Source, ChangeSet_ContentChange> changedRanges =
new HashMap<Source, ChangeSet_ContentChange>();
/// A list containing the sources that have been removed.
final List<Source> removedSources = new List<Source>();
/// A list containing the source containers specifying additional sources that
/// have been removed.
final List<SourceContainer> removedContainers = new List<SourceContainer>();
/// Return a table mapping the sources whose content has been changed to the
/// current content of those sources.
Map<Source, String> get changedContents => _changedContent;
/// Return `true` if this change set does not contain any changes.
bool get isEmpty =>
addedSources.isEmpty &&
changedSources.isEmpty &&
_changedContent.isEmpty &&
changedRanges.isEmpty &&
removedSources.isEmpty &&
removedContainers.isEmpty;
/// Record that the specified [source] has been added and that its content is
/// the default contents of the source.
void addedSource(Source source) {
addedSources.add(source);
}
/// Record that the specified [source] has been changed and that its content is
/// the given [contents].
void changedContent(Source source, String contents) {
_changedContent[source] = contents;
}
/// Record that the specified [source] has been changed and that its content is
/// the given [contents]. The [offset] is the offset into the current contents.
/// The [oldLength] is the number of characters in the original contents that
/// were replaced. The [newLength] is the number of characters in the
/// replacement text.
void changedRange(Source source, String contents, int offset, int oldLength,
int newLength) {
changedRanges[source] =
new ChangeSet_ContentChange(contents, offset, oldLength, newLength);
}
/// Record that the specified [source] has been changed. If the content of the
/// source was previously overridden, this has no effect (the content remains
/// overridden). To cancel (or change) the override, use [changedContent]
/// instead.
void changedSource(Source source) {
changedSources.add(source);
}
/// Record that the specified source [container] has been removed.
void removedContainer(SourceContainer container) {
if (container != null) {
removedContainers.add(container);
}
}
/// Record that the specified [source] has been removed.
void removedSource(Source source) {
if (source != null) {
removedSources.add(source);
}
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
bool needsSeparator =
_appendSources(buffer, addedSources, false, "addedSources");
needsSeparator = _appendSources(
buffer, changedSources, needsSeparator, "changedSources");
needsSeparator = _appendSources2(
buffer, _changedContent, needsSeparator, "changedContent");
needsSeparator =
_appendSources2(buffer, changedRanges, needsSeparator, "changedRanges");
needsSeparator = _appendSources(
buffer, removedSources, needsSeparator, "removedSources");
int count = removedContainers.length;
if (count > 0) {
if (removedSources.isEmpty) {
if (needsSeparator) {
buffer.write("; ");
}
buffer.write("removed: from ");
buffer.write(count);
buffer.write(" containers");
} else {
buffer.write(", and more from ");
buffer.write(count);
buffer.write(" containers");
}
}
return buffer.toString();
}
/// Append the given [sources] to the given [buffer], prefixed with the given
/// [label] and a separator if [needsSeparator] is `true`. Return `true` if
/// future lists of sources will need a separator.
bool _appendSources(StringBuffer buffer, List<Source> sources,
bool needsSeparator, String label) {
if (sources.isEmpty) {
return needsSeparator;
}
if (needsSeparator) {
buffer.write("; ");
}
buffer.write(label);
String prefix = " ";
for (Source source in sources) {
buffer.write(prefix);
buffer.write(source.fullName);
prefix = ", ";
}
return true;
}
/// Append the given [sources] to the given [builder], prefixed with the given
/// [label] and a separator if [needsSeparator] is `true`. Return `true` if
/// future lists of sources will need a separator.
bool _appendSources2(StringBuffer buffer, Map<Source, dynamic> sources,
bool needsSeparator, String label) {
if (sources.isEmpty) {
return needsSeparator;
}
if (needsSeparator) {
buffer.write("; ");
}
buffer.write(label);
String prefix = " ";
for (Source source in sources.keys.toSet()) {
buffer.write(prefix);
buffer.write(source.fullName);
prefix = ", ";
}
return true;
}
}
/// A change to the content of a source.
class ChangeSet_ContentChange {
/// The new contents of the source.
final String contents;
/// The offset into the current contents.
final int offset;
/// The number of characters in the original contents that were replaced
final int oldLength;
/// The number of characters in the replacement text.
final int newLength;
/// Initialize a newly created change object to represent a change to the
/// content of a source. The [contents] is the new contents of the source. The
/// [offset] is the offset into the current contents. The [oldLength] is the
/// number of characters in the original contents that were replaced. The
/// [newLength] is the number of characters in the replacement text.
ChangeSet_ContentChange(
this.contents, this.offset, this.oldLength, this.newLength);
}
/// Additional behavior for an analysis context that is required by internal
/// users of the context.
abstract class InternalAnalysisContext implements AnalysisContext {
/// Sets the [TypeProvider] for this context.
void set typeProvider(TypeProvider typeProvider);
}
/// An object that can be used to receive information about errors within the
/// analysis engine. Implementations usually write this information to a file,
/// but can also record the information for later use (such as during testing) or
/// even ignore the information.
abstract class Logger {
/// A logger that ignores all logging.
static final Logger NULL = new NullLogger();
/// Log the given message as an error. The [message] is expected to be an
/// explanation of why the error occurred or what it means. The [exception] is
/// expected to be the reason for the error. At least one argument must be
/// provided.
void logError(String message, [CaughtException exception]);
/// Log the given informational message. The [message] is expected to be an
/// explanation of why the error occurred or what it means. The [exception] is
/// expected to be the reason for the error.
void logInformation(String message, [CaughtException exception]);
}
/// An implementation of [Logger] that does nothing.
class NullLogger implements Logger {
@override
void logError(String message, [CaughtException exception]) {}
@override
void logInformation(String message, [CaughtException exception]) {}
}
/// Container with global [AnalysisContext] performance statistics.
class PerformanceStatistics {
/// The [PerformanceTag] for `package:analyzer`.
static PerformanceTag analyzer = new PerformanceTag('analyzer');
/// The [PerformanceTag] for time spent in reading files.
static PerformanceTag io = analyzer.createChild('io');
/// The [PerformanceTag] for general phases of analysis.
static PerformanceTag analysis = analyzer.createChild('analysis');
/// The [PerformanceTag] for time spent in scanning.
static PerformanceTag scan = analyzer.createChild('scan');
/// The [PerformanceTag] for time spent in parsing.
static PerformanceTag parse = analyzer.createChild('parse');
/// The [PerformanceTag] for time spent in resolving.
static PerformanceTag resolve = new PerformanceTag('resolve');
/// The [PerformanceTag] for time spent in error verifier.
static PerformanceTag errors = analysis.createChild('errors');
/// The [PerformanceTag] for time spent in hints generator.
static PerformanceTag hints = analysis.createChild('hints');
/// The [PerformanceTag] for time spent in linting.
static PerformanceTag lints = analysis.createChild('lints');
/// The [PerformanceTag] for time spent computing cycles.
static PerformanceTag cycles = new PerformanceTag('cycles');
/// The [PerformanceTag] for time spent in summaries support.
static PerformanceTag summary = analyzer.createChild('summary');
}