OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:collection'; | 5 import 'dart:collection'; |
6 import 'dart:typed_data'; | 6 import 'dart:typed_data'; |
7 | 7 |
8 import 'package:analyzer/file_system/file_system.dart'; | 8 import 'package:analyzer/file_system/file_system.dart'; |
9 import 'package:analyzer/src/dart/analysis/byte_store.dart'; | 9 import 'package:analyzer/src/dart/analysis/byte_store.dart'; |
10 import 'package:analyzer/src/dart/analysis/driver.dart'; | 10 import 'package:analyzer/src/dart/analysis/driver.dart'; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 */ | 52 */ |
53 final addedFiles = new LinkedHashSet<String>(); | 53 final addedFiles = new LinkedHashSet<String>(); |
54 | 54 |
55 /** | 55 /** |
56 * The set of files were reported as changed through [changeFile] and not | 56 * The set of files were reported as changed through [changeFile] and not |
57 * checked for actual changes yet. | 57 * checked for actual changes yet. |
58 */ | 58 */ |
59 final _changedFiles = new LinkedHashSet<String>(); | 59 final _changedFiles = new LinkedHashSet<String>(); |
60 | 60 |
61 /** | 61 /** |
62 * The set of files that are currently scheduled for analysis. | 62 * The set of files that are currently scheduled for analysis, which were |
| 63 * reported as changed through [changeFile]. |
63 */ | 64 */ |
64 final _pendingFiles = new LinkedHashSet<String>(); | 65 var _pendingChangedFiles = new LinkedHashSet<String>(); |
| 66 |
| 67 /** |
| 68 * The set of files that are currently scheduled for analysis, which directly |
| 69 * import a changed file. |
| 70 */ |
| 71 var _pendingImportFiles = new LinkedHashSet<String>(); |
| 72 |
| 73 /** |
| 74 * The set of files that are currently scheduled for analysis, which have an |
| 75 * error or a warning, which might be fixed by a changed file. |
| 76 */ |
| 77 var _pendingErrorFiles = new LinkedHashSet<String>(); |
| 78 |
| 79 /** |
| 80 * The set of files that are currently scheduled for analysis, and don't |
| 81 * have any special relation with changed files. |
| 82 */ |
| 83 var _pendingFiles = new LinkedHashSet<String>(); |
65 | 84 |
66 FileTracker( | 85 FileTracker( |
67 this.logger, | 86 this.logger, |
68 ByteStore byteStore, | 87 ByteStore byteStore, |
69 FileContentOverlay contentOverlay, | 88 FileContentOverlay contentOverlay, |
70 ResourceProvider resourceProvider, | 89 ResourceProvider resourceProvider, |
71 SourceFactory sourceFactory, | 90 SourceFactory sourceFactory, |
72 AnalysisOptions analysisOptions, | 91 AnalysisOptions analysisOptions, |
73 Uint32List salt, | 92 Uint32List salt, |
74 this._changeHook) | 93 this._changeHook) |
75 : fsState = new FileSystemState(logger, byteStore, contentOverlay, | 94 : fsState = new FileSystemState(logger, byteStore, contentOverlay, |
76 resourceProvider, sourceFactory, analysisOptions, salt); | 95 resourceProvider, sourceFactory, analysisOptions, salt); |
77 | 96 |
78 /** | 97 /** |
79 * Returns the path to exactly one that needs analysis. Throws a [StateError] | 98 * Returns the path to exactly one that needs analysis. Throws a [StateError] |
80 * if no files need analysis. | 99 * if no files need analysis. |
81 */ | 100 */ |
82 String get anyPendingFile => _pendingFiles.first; | 101 String get anyPendingFile { |
| 102 if (_pendingChangedFiles.isNotEmpty) { |
| 103 return _pendingChangedFiles.first; |
| 104 } |
| 105 if (_pendingImportFiles.isNotEmpty) { |
| 106 return _pendingImportFiles.first; |
| 107 } |
| 108 if (_pendingErrorFiles.isNotEmpty) { |
| 109 return _pendingErrorFiles.first; |
| 110 } |
| 111 return _pendingFiles.first; |
| 112 } |
83 | 113 |
84 /** | 114 /** |
85 * Returns a boolean indicating whether there are any files that have changed, | 115 * Returns a boolean indicating whether there are any files that have changed, |
86 * but for which the impact of the changes hasn't been measured. | 116 * but for which the impact of the changes hasn't been measured. |
87 */ | 117 */ |
88 bool get hasChangedFiles => _changedFiles.isNotEmpty; | 118 bool get hasChangedFiles => _changedFiles.isNotEmpty; |
89 | 119 |
90 /** | 120 /** |
| 121 * Return `true` if there are changed files that need analysis. |
| 122 */ |
| 123 bool get hasPendingChangedFiles => _pendingChangedFiles.isNotEmpty; |
| 124 |
| 125 /** |
| 126 * Return `true` if there are files that have an error or warning, and that |
| 127 * need analysis. |
| 128 */ |
| 129 bool get hasPendingErrorFiles => _pendingErrorFiles.isNotEmpty; |
| 130 |
| 131 /** |
91 * Returns a boolean indicating whether there are any files that need | 132 * Returns a boolean indicating whether there are any files that need |
92 * analysis. | 133 * analysis. |
93 */ | 134 */ |
94 bool get hasPendingFiles => _pendingFiles.isNotEmpty; | 135 bool get hasPendingFiles { |
| 136 return hasPendingChangedFiles || |
| 137 hasPendingImportFiles || |
| 138 hasPendingErrorFiles || |
| 139 _pendingFiles.isNotEmpty; |
| 140 } |
| 141 |
| 142 /** |
| 143 * Return `true` if there are files that directly import a changed file that |
| 144 * need analysis. |
| 145 */ |
| 146 bool get hasPendingImportFiles => _pendingImportFiles.isNotEmpty; |
95 | 147 |
96 /** | 148 /** |
97 * Returns a count of how many files need analysis. | 149 * Returns a count of how many files need analysis. |
98 */ | 150 */ |
99 int get numberOfPendingFiles => _pendingFiles.length; | 151 int get numberOfPendingFiles { |
| 152 return _pendingChangedFiles.length + |
| 153 _pendingImportFiles.length + |
| 154 _pendingErrorFiles.length + |
| 155 _pendingFiles.length; |
| 156 } |
100 | 157 |
101 /** | 158 /** |
102 * Adds the given [path] to the set of "added files". | 159 * Adds the given [path] to the set of "added files". |
103 */ | 160 */ |
104 void addFile(String path) { | 161 void addFile(String path) { |
105 addedFiles.add(path); | 162 addedFiles.add(path); |
106 _pendingFiles.add(path); | 163 _pendingFiles.add(path); |
107 _changeHook(); | 164 _changeHook(); |
108 } | 165 } |
109 | 166 |
110 /** | 167 /** |
111 * Adds the given [paths] to the set of "added files". | 168 * Adds the given [paths] to the set of "added files". |
112 */ | 169 */ |
113 void addFiles(Iterable<String> paths) { | 170 void addFiles(Iterable<String> paths) { |
114 addedFiles.addAll(paths); | 171 addedFiles.addAll(paths); |
115 _pendingFiles.addAll(paths); | 172 _pendingFiles.addAll(paths); |
116 _changeHook(); | 173 _changeHook(); |
117 } | 174 } |
118 | 175 |
119 /** | 176 /** |
120 * Adds the given [path] to the set of "changed files". | 177 * Adds the given [path] to the set of "changed files". |
121 */ | 178 */ |
122 void changeFile(String path) { | 179 void changeFile(String path) { |
123 _changedFiles.add(path); | 180 _changedFiles.add(path); |
124 if (addedFiles.contains(path)) { | 181 if (addedFiles.contains(path)) { |
125 _pendingFiles.add(path); | 182 _pendingChangedFiles.add(path); |
126 } | 183 } |
127 _changeHook(); | 184 _changeHook(); |
128 } | 185 } |
129 | 186 |
130 /** | 187 /** |
131 * Removes the given [path] from the set of "pending files". | 188 * Removes the given [path] from the set of "pending files". |
132 * | 189 * |
133 * Should be called after the client has analyzed a file. | 190 * Should be called after the client has analyzed a file. |
134 */ | 191 */ |
135 void fileWasAnalyzed(String path) { | 192 void fileWasAnalyzed(String path) { |
| 193 _pendingChangedFiles.remove(path); |
| 194 _pendingImportFiles.remove(path); |
| 195 _pendingErrorFiles.remove(path); |
136 _pendingFiles.remove(path); | 196 _pendingFiles.remove(path); |
137 } | 197 } |
138 | 198 |
139 /** | 199 /** |
140 * Returns a boolean indicating whether the given [path] points to a file that | 200 * Returns a boolean indicating whether the given [path] points to a file that |
141 * requires analysis. | 201 * requires analysis. |
142 */ | 202 */ |
143 bool isFilePending(String path) => _pendingFiles.contains(path); | 203 bool isFilePending(String path) { |
| 204 return _pendingChangedFiles.contains(path) || |
| 205 _pendingImportFiles.contains(path) || |
| 206 _pendingErrorFiles.contains(path) || |
| 207 _pendingFiles.contains(path); |
| 208 } |
144 | 209 |
145 /** | 210 /** |
146 * Removes the given [path] from the set of "added files". | 211 * Removes the given [path] from the set of "added files". |
147 */ | 212 */ |
148 void removeFile(String path) { | 213 void removeFile(String path) { |
149 addedFiles.remove(path); | 214 addedFiles.remove(path); |
| 215 _pendingChangedFiles.remove(path); |
| 216 _pendingImportFiles.remove(path); |
| 217 _pendingErrorFiles.remove(path); |
150 _pendingFiles.remove(path); | 218 _pendingFiles.remove(path); |
151 // TODO(paulberry): removing the path from [fsState] and re-analyzing all | 219 // TODO(paulberry): removing the path from [fsState] and re-analyzing all |
152 // files seems extreme. | 220 // files seems extreme. |
153 fsState.removeFile(path); | 221 fsState.removeFile(path); |
154 _pendingFiles.addAll(addedFiles); | 222 _pendingFiles.addAll(addedFiles); |
155 _changeHook(); | 223 _changeHook(); |
156 } | 224 } |
157 | 225 |
158 /** | 226 /** |
159 * Verify the API signature for the file with the given [path], and decide | 227 * Verify the API signature for the file with the given [path], and decide |
160 * which linked libraries should be invalidated, and files reanalyzed. | 228 * which linked libraries should be invalidated, and files reanalyzed. |
161 */ | 229 */ |
162 FileState verifyApiSignature(String path) { | 230 FileState verifyApiSignature(String path) { |
163 return logger.run('Verify API signature of $path', () { | 231 return logger.run('Verify API signature of $path', () { |
164 bool anyApiChanged = false; | 232 bool anyApiChanged = false; |
165 List<FileState> files = fsState.getFilesForPath(path); | 233 List<FileState> files = fsState.getFilesForPath(path); |
166 for (FileState file in files) { | 234 for (FileState file in files) { |
167 bool apiChanged = file.refresh(); | 235 bool apiChanged = file.refresh(); |
168 if (apiChanged) { | 236 if (apiChanged) { |
169 anyApiChanged = true; | 237 anyApiChanged = true; |
170 } | 238 } |
171 } | 239 } |
172 if (anyApiChanged) { | 240 if (anyApiChanged) { |
173 logger.writeln('API signatures mismatch found for $path'); | 241 logger.writeln('API signatures mismatch found for $path'); |
174 // TODO(scheglov) schedule analysis of only affected files | 242 // TODO(scheglov) schedule analysis of only affected files |
175 _pendingFiles.addAll(addedFiles); | 243 var pendingChangedFiles = new LinkedHashSet<String>(); |
| 244 var pendingImportFiles = new LinkedHashSet<String>(); |
| 245 var pendingErrorFiles = new LinkedHashSet<String>(); |
| 246 var pendingFiles = new LinkedHashSet<String>(); |
| 247 |
| 248 // Add the changed file. |
| 249 if (addedFiles.contains(path)) { |
| 250 pendingChangedFiles.add(path); |
| 251 } |
| 252 |
| 253 // Add files that directly import the changed file. |
| 254 for (String addedPath in addedFiles) { |
| 255 FileState addedFile = fsState.getFileForPath(addedPath); |
| 256 for (FileState changedFile in files) { |
| 257 if (addedFile.importedFiles.contains(changedFile)) { |
| 258 pendingImportFiles.add(addedPath); |
| 259 } |
| 260 } |
| 261 } |
| 262 |
| 263 // Add files with errors or warnings that might be fixed. |
| 264 for (String addedPath in addedFiles) { |
| 265 FileState addedFile = fsState.getFileForPath(addedPath); |
| 266 if (addedFile.hasErrorOrWarning) { |
| 267 pendingErrorFiles.add(addedPath); |
| 268 } |
| 269 } |
| 270 |
| 271 // Add all previous pending files. |
| 272 pendingChangedFiles.addAll(_pendingChangedFiles); |
| 273 pendingImportFiles.addAll(_pendingImportFiles); |
| 274 pendingErrorFiles.addAll(_pendingErrorFiles); |
| 275 pendingFiles.addAll(_pendingFiles); |
| 276 |
| 277 // Add all the rest. |
| 278 pendingFiles.addAll(addedFiles); |
| 279 |
| 280 // Replace pending files. |
| 281 _pendingChangedFiles = pendingChangedFiles; |
| 282 _pendingImportFiles = pendingImportFiles; |
| 283 _pendingErrorFiles = pendingErrorFiles; |
| 284 _pendingFiles = pendingFiles; |
176 } | 285 } |
177 return files[0]; | 286 return files[0]; |
178 }); | 287 }); |
179 } | 288 } |
180 | 289 |
181 /** | 290 /** |
182 * If at least one file is in the "changed files" set, determines the impact | 291 * If at least one file is in the "changed files" set, determines the impact |
183 * of the change, updates the set of pending files, and returns `true`. | 292 * of the change, updates the set of pending files, and returns `true`. |
184 * | 293 * |
185 * If no files are in the "changed files" set, returns `false`. | 294 * If no files are in the "changed files" set, returns `false`. |
186 */ | 295 */ |
187 bool verifyChangedFilesIfNeeded() { | 296 bool verifyChangedFilesIfNeeded() { |
188 // Verify all changed files one at a time. | 297 // Verify all changed files one at a time. |
189 if (_changedFiles.isNotEmpty) { | 298 if (_changedFiles.isNotEmpty) { |
190 String path = _changedFiles.first; | 299 String path = _changedFiles.first; |
191 _changedFiles.remove(path); | 300 _changedFiles.remove(path); |
192 // If the file has not been accessed yet, we either will eventually read | 301 // If the file has not been accessed yet, we either will eventually read |
193 // it later while analyzing one of the added files, or don't need it. | 302 // it later while analyzing one of the added files, or don't need it. |
194 if (fsState.knownFilePaths.contains(path)) { | 303 if (fsState.knownFilePaths.contains(path)) { |
195 verifyApiSignature(path); | 304 verifyApiSignature(path); |
196 } | 305 } |
197 return true; | 306 return true; |
198 } | 307 } |
199 return false; | 308 return false; |
200 } | 309 } |
201 } | 310 } |
OLD | NEW |