Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/resolver.dart |
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart |
| index 0576ed003700018153bfa5afe32eace3d6dd7b8b..079b177b86450a877c1d1eb552614163ec2afbd5 100644 |
| --- a/pkg/analyzer/lib/src/generated/resolver.dart |
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart |
| @@ -61,11 +61,19 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
| final ErrorReporter _errorReporter; |
| /** |
| + * The type Future<Null>, which is needed for determining whether it is safe |
| + * to have a bare "return;" in an async method. |
| + */ |
| + final InterfaceType _futureNullType; |
| + |
| + /** |
| * Create a new instance of the [BestPracticesVerifier]. |
| * |
| * @param errorReporter the error reporter |
| */ |
| - BestPracticesVerifier(this._errorReporter); |
| + BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider) |
| + : _futureNullType = typeProvider.futureType.substitute4( |
|
Brian Wilkerson
2015/02/02 19:41:48
Should we make Future<Null> directly accessible th
Paul Berry
2015/02/02 20:55:38
That's a good idea. I need to do more work in thi
|
| + <DartType>[typeProvider.nullType]); |
| @override |
| Object visitArgumentList(ArgumentList node) { |
| @@ -558,6 +566,9 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
| * statement on all branches. At the end of blocks with no return, Dart implicitly returns |
| * `null`, avoiding these implicit returns is considered a best practice. |
| * |
| + * Note: for async functions/methods, this hint only applies when the |
| + * function has a return type that Future<Null> is not assignable to. |
| + * |
| * @param node the binary expression to check |
| * @param body the function body |
| * @return `true` if and only if a hint code is generated on the passed node |
| @@ -577,6 +588,11 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
| if (returnTypeType == null || returnTypeType.isVoid) { |
| return false; |
| } |
| + // For async, give no hint if Future<Null> is assignable to the return |
| + // type. |
| + if (body.isAsynchronous && _futureNullType.isAssignableTo(returnTypeType)) { |
| + return false; |
| + } |
| // Check the block for a return statement, if not, create the hint |
| BlockFunctionBody blockFunctionBody = body as BlockFunctionBody; |
| if (!blockFunctionBody.accept(new ExitDetector())) { |
| @@ -4393,7 +4409,7 @@ class FunctionTypeScope extends EnclosedScope { |
| class HintGenerator { |
| final List<CompilationUnit> _compilationUnits; |
| - final AnalysisContext _context; |
| + final InternalAnalysisContext _context; |
| final AnalysisErrorListener _errorListener; |
| @@ -4458,7 +4474,8 @@ class HintGenerator { |
| unit.accept(new Dart2JSVerifier(errorReporter)); |
| } |
| // Dart best practices |
| - unit.accept(new BestPracticesVerifier(errorReporter)); |
| + unit.accept( |
| + new BestPracticesVerifier(errorReporter, _context.typeProvider)); |
| unit.accept(new OverrideVerifier(_manager, errorReporter)); |
| // Find to-do comments |
| new ToDoFinder(errorReporter).findIn(unit); |
| @@ -7690,11 +7707,21 @@ class LibraryResolver { |
| Source _coreLibrarySource; |
| /** |
| + * A Source object representing the async library (dart:async). |
| + */ |
| + Source _asyncLibrarySource; |
| + |
| + /** |
| * The object representing the core library. |
| */ |
| Library _coreLibrary; |
| /** |
| + * The object representing the async library. |
| + */ |
| + Library _asyncLibrary; |
| + |
| + /** |
| * The object used to access the types from the core library. |
| */ |
| TypeProvider _typeProvider; |
| @@ -7718,6 +7745,8 @@ class LibraryResolver { |
| this._errorListener = new RecordingErrorListener(); |
| _coreLibrarySource = |
| analysisContext.sourceFactory.forUri(DartSdk.DART_CORE); |
| + _asyncLibrarySource = |
| + analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC); |
| } |
| /** |
| @@ -7769,7 +7798,7 @@ class LibraryResolver { |
| Library targetLibrary = _createLibraryWithUnit(librarySource, unit); |
| _coreLibrary = _libraryMap[_coreLibrarySource]; |
| if (_coreLibrary == null) { |
| - // This will be true unless the library being analyzed is the core |
| + // This will only happen if the library being analyzed is the core |
| // library. |
| _coreLibrary = createLibrary(_coreLibrarySource); |
| if (_coreLibrary == null) { |
| @@ -7778,6 +7807,17 @@ class LibraryResolver { |
| _coreLibrarySource); |
| } |
| } |
| + _asyncLibrary = _libraryMap[_asyncLibrarySource]; |
| + if (_asyncLibrary == null) { |
| + // This will only happen if the library being analyzed is the async |
| + // library. |
| + _asyncLibrary = createLibrary(_asyncLibrarySource); |
| + if (_asyncLibrary == null) { |
| + LibraryResolver2.missingAsyncLibrary( |
| + analysisContext, |
| + _asyncLibrarySource); |
| + } |
| + } |
| // |
| // Compute the set of libraries that need to be resolved together. |
| // |
| @@ -7804,8 +7844,12 @@ class LibraryResolver { |
| if (coreElement == null) { |
| throw new AnalysisException("Could not resolve dart:core"); |
| } |
| + LibraryElement asyncElement = _asyncLibrary.libraryElement; |
| + if (asyncElement == null) { |
| + throw new AnalysisException("Could not resolve dart:async"); |
| + } |
| _buildDirectiveModels(); |
| - _typeProvider = new TypeProviderImpl(coreElement); |
| + _typeProvider = new TypeProviderImpl(coreElement, asyncElement); |
| _buildTypeAliases(); |
| _buildTypeHierarchies(); |
| // |
| @@ -7849,7 +7893,7 @@ class LibraryResolver { |
| Library targetLibrary = createLibrary(librarySource); |
| _coreLibrary = _libraryMap[_coreLibrarySource]; |
| if (_coreLibrary == null) { |
| - // This will be true unless the library being analyzed is the core |
| + // This should only happen if the library being analyzed is the core |
| // library. |
| _coreLibrary = _createLibraryOrNull(_coreLibrarySource); |
| if (_coreLibrary == null) { |
| @@ -7858,6 +7902,17 @@ class LibraryResolver { |
| _coreLibrarySource); |
| } |
| } |
| + _asyncLibrary = _libraryMap[_asyncLibrarySource]; |
| + if (_asyncLibrary == null) { |
| + // This should only happen if the library being analyzed is the async |
| + // library. |
| + _asyncLibrary = _createLibraryOrNull(_asyncLibrarySource); |
| + if (_asyncLibrary == null) { |
| + LibraryResolver2.missingAsyncLibrary( |
| + analysisContext, |
| + _asyncLibrarySource); |
| + } |
| + } |
| // |
| // Compute the set of libraries that need to be resolved together. |
| // |
| @@ -7886,8 +7941,12 @@ class LibraryResolver { |
| if (coreElement == null) { |
| throw new AnalysisException("Could not resolve dart:core"); |
| } |
| + LibraryElement asyncElement = _asyncLibrary.libraryElement; |
| + if (asyncElement == null) { |
| + throw new AnalysisException("Coulb not resolve dart:async"); |
| + } |
| _buildDirectiveModels(); |
| - _typeProvider = new TypeProviderImpl(coreElement); |
| + _typeProvider = new TypeProviderImpl(coreElement, asyncElement); |
| _buildEnumMembers(); |
| _buildTypeAliases(); |
| _buildTypeHierarchies(); |
| @@ -7966,13 +8025,21 @@ class LibraryResolver { |
| void _addToDependencyMap(Library library, HashMap<Library, |
| List<Library>> dependencyMap, Set<Library> visitedLibraries) { |
| if (visitedLibraries.add(library)) { |
| + bool asyncFound = false; |
| for (Library referencedLibrary in library.importsAndExports) { |
| _addDependencyToMap(dependencyMap, library, referencedLibrary); |
| _addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries); |
| + if (identical(referencedLibrary, _asyncLibrary)) { |
| + asyncFound = true; |
| + } |
| } |
| if (!library.explicitlyImportsCore && !identical(library, _coreLibrary)) { |
| _addDependencyToMap(dependencyMap, library, _coreLibrary); |
| } |
| + if (!asyncFound && !identical(library, _asyncLibrary)) { |
| + _addDependencyToMap(dependencyMap, library, _asyncLibrary); |
| + _addToDependencyMap(_asyncLibrary, dependencyMap, visitedLibraries); |
| + } |
| } |
| } |
| @@ -8339,10 +8406,14 @@ class LibraryResolver { |
| List<Source> importedSources, List<Source> exportedSources) { |
| List<Library> importedLibraries = new List<Library>(); |
| bool explicitlyImportsCore = false; |
| + bool importsAsync = false; |
| for (Source importedSource in importedSources) { |
| if (importedSource == _coreLibrarySource) { |
| explicitlyImportsCore = true; |
| } |
| + if (importedSource == _asyncLibrarySource) { |
| + importsAsync = true; |
| + } |
| Library importedLibrary = _libraryMap[importedSource]; |
| if (importedLibrary == null) { |
| importedLibrary = _createLibraryOrNull(importedSource); |
| @@ -8379,6 +8450,15 @@ class LibraryResolver { |
| } |
| } |
| } |
| + if (!importsAsync && _asyncLibrarySource != library.librarySource) { |
| + Library importedLibrary = _libraryMap[_asyncLibrarySource]; |
| + if (importedLibrary == null) { |
| + importedLibrary = _createLibraryOrNull(_asyncLibrarySource); |
| + if (importedLibrary != null) { |
| + _computeLibraryDependencies(importedLibrary); |
| + } |
| + } |
| + } |
| } |
| /** |
| @@ -8560,11 +8640,21 @@ class LibraryResolver2 { |
| Source _coreLibrarySource; |
| /** |
| + * A source object representing the async library (dart:async). |
| + */ |
| + Source _asyncLibrarySource; |
| + |
| + /** |
| * The object representing the core library. |
| */ |
| ResolvableLibrary _coreLibrary; |
| /** |
| + * The object representing the async library. |
| + */ |
| + ResolvableLibrary _asyncLibrary; |
| + |
| + /** |
| * The object used to access the types from the core library. |
| */ |
| TypeProvider _typeProvider; |
| @@ -8589,6 +8679,8 @@ class LibraryResolver2 { |
| this._errorListener = new RecordingErrorListener(); |
| _coreLibrarySource = |
| analysisContext.sourceFactory.forUri(DartSdk.DART_CORE); |
| + _asyncLibrarySource = |
| + analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC); |
| } |
| /** |
| @@ -8627,6 +8719,7 @@ class LibraryResolver2 { |
| _libraryMap = _buildLibraryMap(); |
| ResolvableLibrary targetLibrary = _libraryMap[librarySource]; |
| _coreLibrary = _libraryMap[_coreLibrarySource]; |
| + _asyncLibrary = _libraryMap[_asyncLibrarySource]; |
| // |
| // Build the element models representing the libraries being resolved. |
| // This is done in three steps: |
| @@ -8650,8 +8743,12 @@ class LibraryResolver2 { |
| if (coreElement == null) { |
| missingCoreLibrary(analysisContext, _coreLibrarySource); |
| } |
| + LibraryElement asyncElement = _asyncLibrary.libraryElement; |
| + if (asyncElement == null) { |
| + missingAsyncLibrary(analysisContext, _asyncLibrarySource); |
| + } |
| _buildDirectiveModels(); |
| - _typeProvider = new TypeProviderImpl(coreElement); |
| + _typeProvider = new TypeProviderImpl(coreElement, asyncElement); |
| _buildEnumMembers(); |
| _buildTypeAliases(); |
| _buildTypeHierarchies(); |
| @@ -9068,6 +9165,16 @@ class LibraryResolver2 { |
| } |
| /** |
| + * Report that the async library could not be resolved in the given |
| + * [analysisContext] and throw an exception. [asyncLibrarySource] is the source |
| + * representing the async library. |
| + */ |
| + static void missingAsyncLibrary(AnalysisContext analysisContext, |
| + Source asyncLibrarySource) { |
| + throw new AnalysisException("Could not resolve dart:async"); |
| + } |
| + |
| + /** |
| * Report that the core library could not be resolved in the given analysis context and throw an |
| * exception. |
| * |
| @@ -13300,6 +13407,11 @@ abstract class TypeProvider { |
| InterfaceType get functionType; |
| /** |
| + * Return the type representing the built-in type 'Future'. |
| + */ |
| + InterfaceType get futureType; |
| + |
| + /** |
| * Return the type representing the built-in type 'int'. |
| * |
| * @return the type representing the built-in type 'int' |
| @@ -13411,6 +13523,11 @@ class TypeProviderImpl implements TypeProvider { |
| InterfaceType _functionType; |
| /** |
| + * The type representing the built-in type 'Future'. |
| + */ |
| + InterfaceType _futureType; |
| + |
| + /** |
| * The type representing the built-in type 'int'. |
| */ |
| InterfaceType _intType; |
| @@ -13470,8 +13587,8 @@ class TypeProviderImpl implements TypeProvider { |
| * |
| * @param coreLibrary the element representing the core library (dart:core). |
| */ |
| - TypeProviderImpl(LibraryElement coreLibrary) { |
| - _initializeFrom(coreLibrary); |
| + TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) { |
| + _initializeFrom(coreLibrary, asyncLibrary); |
| } |
| @override |
| @@ -13493,6 +13610,9 @@ class TypeProviderImpl implements TypeProvider { |
| InterfaceType get functionType => _functionType; |
| @override |
| + InterfaceType get futureType => _futureType; |
| + |
| + @override |
| InterfaceType get intType => _intType; |
| @override |
| @@ -13548,25 +13668,29 @@ class TypeProviderImpl implements TypeProvider { |
| * |
| * @param library the library containing the definitions of the core types |
| */ |
| - void _initializeFrom(LibraryElement library) { |
| - Namespace namespace = |
| - new NamespaceBuilder().createPublicNamespaceForLibrary(library); |
| - _boolType = _getType(namespace, "bool"); |
| + void _initializeFrom(LibraryElement coreLibrary, |
| + LibraryElement asyncLibrary) { |
| + Namespace coreNamespace = |
| + new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary); |
| + Namespace asyncNamespace = |
| + new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary); |
| + _boolType = _getType(coreNamespace, "bool"); |
| _bottomType = BottomTypeImpl.instance; |
| - _deprecatedType = _getType(namespace, "Deprecated"); |
| - _doubleType = _getType(namespace, "double"); |
| + _deprecatedType = _getType(coreNamespace, "Deprecated"); |
| + _doubleType = _getType(coreNamespace, "double"); |
| _dynamicType = DynamicTypeImpl.instance; |
| - _functionType = _getType(namespace, "Function"); |
| - _intType = _getType(namespace, "int"); |
| - _listType = _getType(namespace, "List"); |
| - _mapType = _getType(namespace, "Map"); |
| - _nullType = _getType(namespace, "Null"); |
| - _numType = _getType(namespace, "num"); |
| - _objectType = _getType(namespace, "Object"); |
| - _stackTraceType = _getType(namespace, "StackTrace"); |
| - _stringType = _getType(namespace, "String"); |
| - _symbolType = _getType(namespace, "Symbol"); |
| - _typeType = _getType(namespace, "Type"); |
| + _functionType = _getType(coreNamespace, "Function"); |
| + _futureType = _getType(asyncNamespace, "Future"); |
| + _intType = _getType(coreNamespace, "int"); |
| + _listType = _getType(coreNamespace, "List"); |
| + _mapType = _getType(coreNamespace, "Map"); |
| + _nullType = _getType(coreNamespace, "Null"); |
| + _numType = _getType(coreNamespace, "num"); |
| + _objectType = _getType(coreNamespace, "Object"); |
| + _stackTraceType = _getType(coreNamespace, "StackTrace"); |
| + _stringType = _getType(coreNamespace, "String"); |
| + _symbolType = _getType(coreNamespace, "Symbol"); |
| + _typeType = _getType(coreNamespace, "Type"); |
| _undefinedType = UndefinedTypeImpl.instance; |
| } |
| } |