| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library engine.incremental_resolver; | 5 library engine.incremental_resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 import 'dart:math' as math; | 8 import 'dart:math' as math; |
| 9 | 9 |
| 10 import 'package:analyzer/src/services/lint.dart'; | 10 import 'package:analyzer/src/services/lint.dart'; |
| 11 | 11 |
| 12 import 'ast.dart'; | 12 import 'ast.dart'; |
| 13 import 'element.dart'; | 13 import 'element.dart'; |
| 14 import 'engine.dart'; | 14 import 'engine.dart'; |
| 15 import 'error.dart'; | 15 import 'error.dart'; |
| 16 import 'error_verifier.dart'; | 16 import 'error_verifier.dart'; |
| 17 import 'incremental_logger.dart' show logger, LoggingTimer; | 17 import 'incremental_logger.dart' show logger, LoggingTimer; |
| 18 import 'java_engine.dart'; | 18 import 'java_engine.dart'; |
| 19 import 'parser.dart'; | 19 import 'parser.dart'; |
| 20 import 'resolver.dart'; | 20 import 'resolver.dart'; |
| 21 import 'scanner.dart'; | 21 import 'scanner.dart'; |
| 22 import 'source.dart'; | 22 import 'source.dart'; |
| 23 import 'utilities_collection.dart'; | |
| 24 import 'utilities_dart.dart'; | 23 import 'utilities_dart.dart'; |
| 25 | 24 |
| 26 | 25 |
| 27 /** | 26 /** |
| 28 * If `true`, an attempt to resolve API-changing modifications is made. | 27 * If `true`, an attempt to resolve API-changing modifications is made. |
| 29 */ | 28 */ |
| 30 bool _resolveApiChanges = false; | 29 bool _resolveApiChanges = false; |
| 31 | 30 |
| 32 | 31 |
| 33 /** | 32 /** |
| (...skipping 800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 int _updateDelta; | 833 int _updateDelta; |
| 835 | 834 |
| 836 RecordingErrorListener errorListener = new RecordingErrorListener(); | 835 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 837 ResolutionContext _resolutionContext; | 836 ResolutionContext _resolutionContext; |
| 838 | 837 |
| 839 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS; | 838 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS; |
| 840 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS; | 839 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS; |
| 841 List<AnalysisError> _lints = AnalysisError.NO_ERRORS; | 840 List<AnalysisError> _lints = AnalysisError.NO_ERRORS; |
| 842 | 841 |
| 843 /** | 842 /** |
| 844 * The elements that should be resolved because of API changes. | |
| 845 */ | |
| 846 HashSet<Element> _resolutionQueue = new HashSet<Element>(); | |
| 847 | |
| 848 /** | |
| 849 * Initialize a newly created incremental resolver to resolve a node in the | 843 * Initialize a newly created incremental resolver to resolve a node in the |
| 850 * given source in the given library. | 844 * given source in the given library. |
| 851 */ | 845 */ |
| 852 IncrementalResolver(this._units, this._definingUnit, this._updateOffset, | 846 IncrementalResolver(this._units, this._definingUnit, this._updateOffset, |
| 853 this._updateEndOld, this._updateEndNew) { | 847 this._updateEndOld, this._updateEndNew) { |
| 854 _updateDelta = _updateEndNew - _updateEndOld; | 848 _updateDelta = _updateEndNew - _updateEndOld; |
| 855 _definingLibrary = _definingUnit.library; | 849 _definingLibrary = _definingUnit.library; |
| 856 _librarySource = _definingLibrary.source; | 850 _librarySource = _definingLibrary.source; |
| 857 _source = _definingUnit.source; | 851 _source = _definingUnit.source; |
| 858 _context = _definingUnit.context; | 852 _context = _definingUnit.context; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 879 return false; | 873 return false; |
| 880 } | 874 } |
| 881 // resolve | 875 // resolve |
| 882 _resolveReferences(rootNode); | 876 _resolveReferences(rootNode); |
| 883 // verify | 877 // verify |
| 884 _verify(rootNode); | 878 _verify(rootNode); |
| 885 _generateHints(rootNode); | 879 _generateHints(rootNode); |
| 886 _generateLints(rootNode); | 880 _generateLints(rootNode); |
| 887 // update entry errors | 881 // update entry errors |
| 888 _updateEntry(); | 882 _updateEntry(); |
| 889 // resolve queue in response of API changes | |
| 890 _resolveQueue(); | |
| 891 // OK | 883 // OK |
| 892 return true; | 884 return true; |
| 893 } finally { | 885 } finally { |
| 894 logger.exit(); | 886 logger.exit(); |
| 895 } | 887 } |
| 896 } | 888 } |
| 897 | 889 |
| 898 void _buildElements(AstNode node) { | 890 void _buildElements(AstNode node) { |
| 899 LoggingTimer timer = logger.startTimer(); | 891 LoggingTimer timer = logger.startTimer(); |
| 900 try { | 892 try { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 927 // check the whole enclosing Element. | 919 // check the whole enclosing Element. |
| 928 if (node is Declaration) { | 920 if (node is Declaration) { |
| 929 node = node.parent; | 921 node = node.parent; |
| 930 } | 922 } |
| 931 Element element = _getElement(node); | 923 Element element = _getElement(node); |
| 932 DeclarationMatcher matcher = new DeclarationMatcher(); | 924 DeclarationMatcher matcher = new DeclarationMatcher(); |
| 933 DeclarationMatchKind matchKind = matcher.matches(node, element); | 925 DeclarationMatchKind matchKind = matcher.matches(node, element); |
| 934 if (matchKind == DeclarationMatchKind.MATCH) { | 926 if (matchKind == DeclarationMatchKind.MATCH) { |
| 935 return true; | 927 return true; |
| 936 } | 928 } |
| 937 // try to resolve a simple API change | |
| 938 if (_resolveApiChanges && matchKind == DeclarationMatchKind.MISMATCH_OK) { | |
| 939 _fillResolutionQueue(matcher); | |
| 940 return true; | |
| 941 } | |
| 942 // mismatch that cannot be incrementally fixed | 929 // mismatch that cannot be incrementally fixed |
| 943 return false; | 930 return false; |
| 944 } | 931 } |
| 945 | 932 |
| 946 /** | 933 /** |
| 947 * Return `true` if the given node can be resolved independently of any other | 934 * Return `true` if the given node can be resolved independently of any other |
| 948 * nodes. | 935 * nodes. |
| 949 * | 936 * |
| 950 * *Note*: This method needs to be kept in sync with | 937 * *Note*: This method needs to be kept in sync with |
| 951 * [ScopeBuilder.ContextBuilder]. | 938 * [ScopeBuilder.ContextBuilder]. |
| 952 * | 939 * |
| 953 * [node] - the node being tested. | 940 * [node] - the node being tested. |
| 954 */ | 941 */ |
| 955 bool _canBeResolved(AstNode node) => | 942 bool _canBeResolved(AstNode node) => |
| 956 node is ClassDeclaration || | 943 node is ClassDeclaration || |
| 957 node is ClassTypeAlias || | 944 node is ClassTypeAlias || |
| 958 node is CompilationUnit || | 945 node is CompilationUnit || |
| 959 node is ConstructorDeclaration || | 946 node is ConstructorDeclaration || |
| 960 node is FunctionDeclaration || | 947 node is FunctionDeclaration || |
| 961 node is FunctionTypeAlias || | 948 node is FunctionTypeAlias || |
| 962 node is MethodDeclaration || | 949 node is MethodDeclaration || |
| 963 node is TopLevelVariableDeclaration; | 950 node is TopLevelVariableDeclaration; |
| 964 | 951 |
| 965 void _fillResolutionQueue(DeclarationMatcher matcher) { | |
| 966 HashSet<Element> removedElements = matcher._removedElements; | |
| 967 logger.log('${removedElements.length} elements removed'); | |
| 968 for (Element removedElement in removedElements) { | |
| 969 AnalysisContextImpl context = removedElement.context; | |
| 970 IntSet users = removedElement.users; | |
| 971 while (!users.isEmpty) { | |
| 972 int id = users.remove(); | |
| 973 Element removedElementUser = context.findElementById(id); | |
| 974 _resolutionQueue.add(removedElementUser); | |
| 975 } | |
| 976 } | |
| 977 // TODO(scheglov) a method change might also require its class, and | |
| 978 // subclasses resolution | |
| 979 } | |
| 980 | |
| 981 /** | 952 /** |
| 982 * Starting at [node], find the smallest AST node that can be resolved | 953 * Starting at [node], find the smallest AST node that can be resolved |
| 983 * independently of any other nodes. Return the node that was found. | 954 * independently of any other nodes. Return the node that was found. |
| 984 * | 955 * |
| 985 * [node] - the node at which the search is to begin | 956 * [node] - the node at which the search is to begin |
| 986 * | 957 * |
| 987 * Throws [AnalysisException] if there is no such node. | 958 * Throws [AnalysisException] if there is no such node. |
| 988 */ | 959 */ |
| 989 AstNode _findResolutionRoot(AstNode node) { | 960 AstNode _findResolutionRoot(AstNode node) { |
| 990 while (node != null) { | 961 while (node != null) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 return null; | 1021 return null; |
| 1051 } | 1022 } |
| 1052 | 1023 |
| 1053 void _prepareResolutionContext(AstNode node) { | 1024 void _prepareResolutionContext(AstNode node) { |
| 1054 if (_resolutionContext == null) { | 1025 if (_resolutionContext == null) { |
| 1055 _resolutionContext = | 1026 _resolutionContext = |
| 1056 ResolutionContextBuilder.contextFor(node, errorListener); | 1027 ResolutionContextBuilder.contextFor(node, errorListener); |
| 1057 } | 1028 } |
| 1058 } | 1029 } |
| 1059 | 1030 |
| 1060 /** | |
| 1061 * Resolves elements [_resolutionQueue]. | |
| 1062 * | |
| 1063 * TODO(scheglov) work in progress | |
| 1064 * | |
| 1065 * TODO(scheglov) revisit later. Each task duration should be kept short. | |
| 1066 */ | |
| 1067 void _resolveQueue() { | |
| 1068 logger.log('${_resolutionQueue.length} elements in the resolution queue'); | |
| 1069 for (Element element in _resolutionQueue) { | |
| 1070 // TODO(scheglov) in general, we should not call Element.node, it | |
| 1071 // might perform complete unit resolution. | |
| 1072 logger.enter('resolve $element'); | |
| 1073 try { | |
| 1074 AstNode node = element.node; | |
| 1075 CompilationUnitElement unit = | |
| 1076 element.getAncestor((e) => e is CompilationUnitElement); | |
| 1077 IncrementalResolver resolver = | |
| 1078 new IncrementalResolver(_units, unit, node.offset, node.end, node.en
d); | |
| 1079 resolver._resolveReferences(node); | |
| 1080 resolver._verify(node); | |
| 1081 resolver._generateHints(node); | |
| 1082 resolver._generateLints(node); | |
| 1083 resolver._updateEntry(); | |
| 1084 } finally { | |
| 1085 logger.exit(); | |
| 1086 } | |
| 1087 } | |
| 1088 } | |
| 1089 | |
| 1090 _resolveReferences(AstNode node) { | 1031 _resolveReferences(AstNode node) { |
| 1091 LoggingTimer timer = logger.startTimer(); | 1032 LoggingTimer timer = logger.startTimer(); |
| 1092 try { | 1033 try { |
| 1093 _prepareResolutionContext(node); | 1034 _prepareResolutionContext(node); |
| 1094 Scope scope = _resolutionContext.scope; | 1035 Scope scope = _resolutionContext.scope; |
| 1095 // resolve types | 1036 // resolve types |
| 1096 { | 1037 { |
| 1097 TypeResolverVisitor visitor = new TypeResolverVisitor.con3( | 1038 TypeResolverVisitor visitor = new TypeResolverVisitor.con3( |
| 1098 _definingLibrary, | 1039 _definingLibrary, |
| 1099 _source, | 1040 _source, |
| (...skipping 819 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1919 String toString() => name; | 1860 String toString() => name; |
| 1920 } | 1861 } |
| 1921 | 1862 |
| 1922 | 1863 |
| 1923 class _TokenPair { | 1864 class _TokenPair { |
| 1924 final _TokenDifferenceKind kind; | 1865 final _TokenDifferenceKind kind; |
| 1925 final Token oldToken; | 1866 final Token oldToken; |
| 1926 final Token newToken; | 1867 final Token newToken; |
| 1927 _TokenPair(this.kind, this.oldToken, this.newToken); | 1868 _TokenPair(this.kind, this.oldToken, this.newToken); |
| 1928 } | 1869 } |
| OLD | NEW |