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