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; | 
| } | 
| } |