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

Unified Diff: pkg/analyzer/lib/src/dart/analysis/analysis_impl.dart

Issue 2678193002: Not task based analysis. (Closed)
Patch Set: Created 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/dart/analysis/driver.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/dart/analysis/analysis_impl.dart
diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_impl.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_impl.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a8bfb9773cec059b758eb12da695495f9df5832f
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/analysis_impl.dart
@@ -0,0 +1,484 @@
+// Copyright (c) 2017, 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 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/error/pending_error.dart';
+import 'package:analyzer/src/generated/declaration_resolver.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:front_end/src/scanner/reader.dart';
+
+/**
+ * Analyzer of Dart files.
+ *
+ * Work in progress, not ready to be used.
+ */
+class AnalyzerImpl {
+ final AnalysisOptions analysisOptions;
+ final SourceFactory sourceFactory;
+ final FileSystemState fsState;
+ final SummaryDataStore store;
+
+ AnalysisContextImpl analysisContext;
+ TypeProvider typeProvider;
+ StoreBasedSummaryResynthesizer resynthesizer;
+ final Map<FileState, RecordingErrorListener> _errorListeners = {};
+ final Map<FileState, ErrorReporter> _errorReporters = {};
+ final List<UsedImportedElements> usedImportedElementsList = [];
+
+ AnalyzerImpl(
+ this.analysisOptions, this.sourceFactory, this.fsState, this.store);
+
+ /**
+ * Compute analysis results for all units of the [library].
+ */
+ Map<FileState, UnitAnalysisResult> analyze(FileState library) {
+ Map<FileState, CompilationUnit> units = {};
+
+ // Parse all files.
+ units[library] = _parse(library);
+ for (FileState part in library.partedFiles) {
+ units[part] = _parse(part);
+ }
+
+ // Resolve directives.
+ units.forEach((file, unit) {
+ _resolveUriBasedDirectives(file, unit);
+ });
+
+ _createAnalysisContext();
+
+ try {
+ resynthesizer = new StoreBasedSummaryResynthesizer(
+ analysisContext, sourceFactory, analysisOptions.strongMode, store);
+ typeProvider = resynthesizer.typeProvider;
+ analysisContext.typeProvider = typeProvider;
+
+ units.forEach((file, unit) {
+ _resolveFile(analysisContext, library, file, unit);
+ });
+
+ List<UsedLocalElements> usedLocalElementsList = [];
+ units.forEach((file, unit) {
+ GatherUsedLocalElementsVisitor visitor =
+ new GatherUsedLocalElementsVisitor(unit.element.library);
+ unit.accept(visitor);
+ usedLocalElementsList.add(visitor.usedElements);
+ });
+
+ units.forEach((file, unit) {
Paul Berry 2017/02/06 22:44:36 Can we merge this loop with the loop above? It se
+ LibraryElement libraryElement = unit.element.library;
+ var visitor = new GatherUsedImportedElementsVisitor(libraryElement);
+ unit.accept(visitor);
+ usedImportedElementsList.add(visitor.usedElements);
+ });
+
+ units.forEach((file, unit) {
+ _computeVerifyErrorsAndHints(
+ analysisContext, library, usedLocalElementsList, file, unit);
+ });
+ } finally {
+ analysisContext.dispose();
+ }
+
+ // Return full results.
+ Map<FileState, UnitAnalysisResult> results = {};
+ units.forEach((file, unit) {
+ List<AnalysisError> errors = _getErrorListener(file).errors;
+ results[file] = new UnitAnalysisResult(file, unit, errors);
+ });
+ return results;
+ }
+
+ void _computeVerifyErrorsAndHints(
+ AnalysisContext analysisContext,
+ FileState libraryFile,
+ List<UsedLocalElements> usedLocalElementsList,
+ FileState file,
+ CompilationUnit unit) {
+ RecordingErrorListener errorListener = _getErrorListener(file);
+ CompilationUnitElement unitElement = unit.element;
+ LibraryElement libraryElement = unitElement.library;
+
+ // Verify imports.
+ {
+ ImportsVerifier verifier = new ImportsVerifier();
+ verifier.addImports(unit);
+ usedImportedElementsList.forEach(verifier.removeUsedElements);
+ ErrorReporter errorReporter = _getErrorReporter(file);
+ verifier.generateDuplicateImportHints(errorReporter);
+ verifier.generateUnusedImportHints(errorReporter);
+ verifier.generateUnusedShownNameHints(errorReporter);
+ }
+
+ {
+ GatherUsedLocalElementsVisitor visitor =
+ new GatherUsedLocalElementsVisitor(libraryElement);
+ unit.accept(visitor);
+ }
+
+ // Unused local elements.
+ {
+ UsedLocalElements usedElements =
+ new UsedLocalElements.merge(usedLocalElementsList);
+ UnusedLocalElementsVerifier visitor =
+ new UnusedLocalElementsVerifier(errorListener, usedElements);
+ unitElement.accept(visitor);
+ }
+ }
+
+ void _createAnalysisContext() {
+ AnalysisContextImpl analysisContext =
+ AnalysisEngine.instance.createAnalysisContext();
+ analysisContext.analysisOptions = analysisOptions;
+ analysisContext.sourceFactory = sourceFactory.clone();
+ analysisContext.contentCache = new _ContentCacheWrapper(fsState);
+ this.analysisContext = analysisContext;
+ }
+
+ RecordingErrorListener _getErrorListener(FileState file) =>
+ _errorListeners.putIfAbsent(file, () => new RecordingErrorListener());
+
+ ErrorReporter _getErrorReporter(FileState file) {
+ return _errorReporters.putIfAbsent(file, () {
+ RecordingErrorListener listener = _getErrorListener(file);
+ return new ErrorReporter(listener, file.source);
+ });
+ }
+
+ /**
+ * Return a new parsed unresolved [CompilationUnit].
+ */
+ CompilationUnit _parse(FileState file) {
+ RecordingErrorListener errorListener = _getErrorListener(file);
+
+ CharSequenceReader reader = new CharSequenceReader(file.content);
+ Scanner scanner = new Scanner(file.source, reader, errorListener);
+ scanner.scanGenericMethodComments = analysisOptions.strongMode;
+ Token token = scanner.tokenize();
+ LineInfo lineInfo = new LineInfo(scanner.lineStarts);
+
+ Parser parser = new Parser(file.source, errorListener);
+ parser.parseGenericMethodComments = analysisOptions.strongMode;
+ CompilationUnit unit = parser.parseCompilationUnit(token);
+ unit.lineInfo = lineInfo;
+ return unit;
+ }
+
+ void _resolveFile(AnalysisContext analysisContext, FileState library,
+ FileState file, CompilationUnit unit) {
+ if (!file.exists) {
+ var unitElement = new CompilationUnitElementImpl(file.source.shortName);
+ var libraryElement = new LibraryElementImpl(analysisContext, null, -1, 0);
+ libraryElement.definingCompilationUnit = unitElement;
+ unit.element = unitElement;
+ return;
+ }
+
+ RecordingErrorListener errorListener = _getErrorListener(file);
+
+ String libraryUri = library.uri.toString();
+ String unitUri = file.uri.toString();
+ CompilationUnitElement unitElement = resynthesizer.getElement(
+ new ElementLocationImpl.con3(<String>[libraryUri, unitUri]));
+ LibraryElement libraryElement = unitElement.library;
+
+ // TODO(scheglov) Hack: set types for top-level variables
+ // Otherwise TypeResolverVisitor will set declared types, and because we
+ // don't run InferStaticVariableTypeTask, we will stuck with these declared
+ // types. And we don't need to run this task - resynthesized elements have
+ // inferred types.
+ for (var e in unitElement.topLevelVariables) {
+ if (!e.isSynthetic) {
+ e.type;
+ }
+ }
+
+ new DeclarationResolver().resolve(unit, unitElement);
+
+ if (file == library) {
+ // TODO(scheglov) fill these maps?
+ DirectiveResolver resolver = new DirectiveResolver({}, {}, {});
+ unit.accept(resolver);
+ }
+
+ unit.accept(new EnumMemberBuilder(typeProvider));
+
+ new TypeParameterBoundsResolver(
+ typeProvider, libraryElement, unitElement.source, errorListener)
+ .resolveTypeBounds(unit);
+
+ unit.accept(new TypeResolverVisitor(
+ libraryElement, unitElement.source, typeProvider, errorListener));
+
+ LibraryScope libraryScope = new LibraryScope(libraryElement);
+ unit.accept(new VariableResolverVisitor(
+ libraryElement, unitElement.source, typeProvider, errorListener,
+ nameScope: libraryScope));
+
+ unit.accept(new PartialResolverVisitor(libraryElement, unitElement.source,
+ typeProvider, AnalysisErrorListener.NULL_LISTENER));
+
+ // Nothing for RESOLVED_UNIT8?
+ // Nothing for RESOLVED_UNIT9?
+ // Nothing for RESOLVED_UNIT10?
+
+ unit.accept(new ResolverVisitor(
+ libraryElement, unitElement.source, typeProvider, errorListener));
+
+ // TODO(scheglov) RESOLVED_UNIT12: compute constants
+
+ //
+ // Use the ErrorVerifier to compute errors.
+ //
+ List<PendingError> pendingErrors;
+ {
+ RequiredConstantsComputer computer =
+ new RequiredConstantsComputer(file.source);
+ unit.accept(computer);
+ pendingErrors = computer.pendingErrors;
+ List<ConstantEvaluationTarget> requiredConstants =
+ computer.requiredConstants;
+ }
+
+ if (analysisOptions.strongMode) {
+ AnalysisOptionsImpl options = analysisOptions as AnalysisOptionsImpl;
+ CodeChecker checker = new CodeChecker(
+ typeProvider,
+ new StrongTypeSystemImpl(typeProvider,
+ implicitCasts: options.implicitCasts,
+ nonnullableTypes: options.nonnullableTypes),
+ errorListener,
+ options);
+ checker.visitCompilationUnit(unit);
+ }
+
+ var errorReporter = _getErrorReporter(file);
+
+ //
+ // Validate the directives.
+ //
+ _validateUriBasedDirectives(file, unit);
+
+ //
+ // Use the ConstantVerifier to compute errors.
+ //
+ ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter,
+ libraryElement, typeProvider, analysisContext.declaredVariables);
+ unit.accept(constantVerifier);
+
+ //
+ // Use the ErrorVerifier to compute errors.
+ //
+ ErrorVerifier errorVerifier = new ErrorVerifier(
+ errorReporter,
+ libraryElement,
+ typeProvider,
+ new InheritanceManager(libraryElement),
+ analysisOptions.enableSuperMixins);
+ unit.accept(errorVerifier);
+
+ //
+ // Convert the pending errors into actual errors.
+ //
+ for (PendingError pendingError in pendingErrors) {
+ errorListener.onError(pendingError.toAnalysisError());
+ }
+
+ //
+ // Find dead code.
+ //
+ unit.accept(new DeadCodeVerifier(errorReporter,
+ typeSystem: analysisContext.typeSystem));
+
+ // Dart2js analysis.
+ if (analysisOptions.dart2jsHint) {
+ unit.accept(new Dart2JSVerifier(errorReporter));
+ }
+
+ InheritanceManager inheritanceManager = new InheritanceManager(
+ libraryElement,
+ includeAbstractFromSuperclasses: true);
+
+ unit.accept(new BestPracticesVerifier(
+ errorReporter, typeProvider, libraryElement, inheritanceManager,
+ typeSystem: analysisContext.typeSystem));
+
+ unit.accept(new OverrideVerifier(errorReporter, inheritanceManager));
+
+ new ToDoFinder(errorReporter).findIn(unit);
+ }
+
+ /**
+ * Return the result of resolve the given [uriContent], reporting errors
+ * against the [uriLiteral].
+ */
+ Source _resolveUri(FileState file, bool isImport, StringLiteral uriLiteral,
+ String uriContent) {
+ UriValidationCode code =
+ UriBasedDirectiveImpl.validateUri(isImport, uriLiteral, uriContent);
+ if (code == null) {
+ try {
+ Uri.parse(uriContent);
+ } on FormatException {
+ return null;
+ }
+ return sourceFactory.resolveUri(file.source, uriContent);
+ } else if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) {
+ return null;
+ } else if (code == UriValidationCode.URI_WITH_INTERPOLATION) {
+ _getErrorReporter(file).reportErrorForNode(
+ CompileTimeErrorCode.URI_WITH_INTERPOLATION, uriLiteral);
+ return null;
+ } else if (code == UriValidationCode.INVALID_URI) {
+ _getErrorReporter(file).reportErrorForNode(
+ CompileTimeErrorCode.INVALID_URI, uriLiteral, [uriContent]);
+ return null;
+ }
+ return null;
+ }
+
+ void _resolveUriBasedDirectives(FileState file, CompilationUnit unit) {
+ for (Directive directive in unit.directives) {
+ if (directive is UriBasedDirective) {
+ StringLiteral uriLiteral = directive.uri;
+ String uriContent = uriLiteral.stringValue?.trim();
+ directive.uriContent = uriContent;
+ Source defaultSource = _resolveUri(
+ file, directive is ImportDirective, uriLiteral, uriContent);
+ directive.uriSource = defaultSource;
+ }
+ }
+ }
+
+ /**
+ * Check the given [directive] to see if the referenced source exists and
+ * report an error if it does not.
+ */
+ void _validateUriBasedDirective(
+ FileState file, UriBasedDirectiveImpl directive) {
+ Source source = directive.uriSource;
+ if (source != null) {
+ if (analysisContext.exists(source)) {
+ return;
+ }
+ } else {
+ // Don't report errors already reported by ParseDartTask.resolveDirective
+ if (directive.validate() != null) {
+ return;
+ }
+ }
+ StringLiteral uriLiteral = directive.uri;
+ CompileTimeErrorCode errorCode = CompileTimeErrorCode.URI_DOES_NOT_EXIST;
+ if (_isGenerated(source)) {
+ errorCode = CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED;
+ }
+ _getErrorReporter(file)
+ .reportErrorForNode(errorCode, uriLiteral, [directive.uriContent]);
+ }
+
+ /**
+ * Check each directive in the given [unit] to see if the referenced source
+ * exists and report an error if it does not.
+ */
+ void _validateUriBasedDirectives(FileState file, CompilationUnit unit) {
+ for (Directive directive in unit.directives) {
+ if (directive is UriBasedDirective) {
+ _validateUriBasedDirective(file, directive);
+ }
+ }
+ }
+
+ /**
+ * Return `true` if the given [source] refers to a file that is assumed to be
+ * generated.
+ */
+ static bool _isGenerated(Source source) {
+ if (source == null) {
+ return false;
+ }
+ // TODO(brianwilkerson) Generalize this mechanism.
+ const List<String> suffixes = const <String>[
+ '.g.dart',
+ '.pb.dart',
+ '.pbenum.dart',
+ '.pbserver.dart',
+ '.pbjson.dart',
+ '.template.dart'
+ ];
+ String fullName = source.fullName;
+ for (String suffix in suffixes) {
+ if (fullName.endsWith(suffix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * Analysis result for single file.
+ */
+class UnitAnalysisResult {
+ final FileState file;
+ final CompilationUnit unit;
+ final List<AnalysisError> errors;
+
+ UnitAnalysisResult(this.file, this.unit, this.errors);
+}
+
+/**
+ * [ContentCache] wrapper around [FileContentOverlay].
+ */
+class _ContentCacheWrapper implements ContentCache {
+ final FileSystemState fsState;
+
+ _ContentCacheWrapper(this.fsState);
+
+ @override
+ void accept(ContentCacheVisitor visitor) {
+ throw new UnimplementedError();
+ }
+
+ @override
+ String getContents(Source source) {
+ return _getFileForSource(source).content;
+ }
+
+ @override
+ bool getExists(Source source) {
+ return _getFileForSource(source).exists;
+ }
+
+ @override
+ int getModificationStamp(Source source) {
+ return _getFileForSource(source).exists ? 0 : -1;
+ }
+
+ @override
+ String setContents(Source source, String contents) {
+ throw new UnimplementedError();
+ }
+
+ FileState _getFileForSource(Source source) {
+ String path = source.fullName;
+ return fsState.getFileForPath(path);
+ }
+}
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/dart/analysis/driver.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698