Please sign in to comment.
Fixes #1001268 - No more NPE in update occurrences when a source is d…
…eleted Deleting a source file could lead to NullPointerException (NPE) in `ScalaOccurrencesFinder`. The issue is actually easy to reproduce. Say you have a source `A` and that `ScalaOccurrencesFinder.findOccurrences` was just ran against it. At this point, the value of `ScalaOccurrencesFinder.indexCache` holds a reference to `A`. In this scenario, deleting `A` will cause a NPE to be thrown the next time `ScalaOccurrencesFinder.findOccurrences` is ran against any other source. The above described scenario happens because `ScalaOccurrencesFinder` is a singleton, and `ScalaOccurrencesFinder.getCachedIndex` is used to check for equality of source files. In the current implementation, checking equality on source files throws a NPE exception if the resource does no longer exist (have a look at `EclipseResource.equals`). The fix simply consists in linking each editor (and hence each source file) to a *different* `ScalaOccurrencesFinder` instance. By doing so, the `ScalaOccurrencesFinder.indexCache` no longer needs to hold a reference to the `SourceFile`, and hence the NPE can no longer occur. An additional positive aspect of not using a singleton `ScalaOccurrencesFinder` is that now the occurrences index (i.e., `MarkOccurrencesIndex`) is no longer rebuilt while switching among the active editors. Last, there are a number of refactoring that have been carried out, I'll mention the three I consider important: * The Eclipse `Job` instance used to execute the "update occurrences" task, used to have high priority (i.e., Job.INTERACTIVE), while it is now low priority. The reasoning is that while the information computed by "update occurrences" are useful, they are not critical. * The signature of `InteractiveCompilationUnitEditor` used to return an `Option[InteractiveCompilationUnit]`, ant it now returns a `InteractiveCompilationUnit`. The reasoning here is that an editor should always have a compilation unit attached to it. The only moment when this is not the case is during the editor initialization, but calling `getInteractiveCompilationUnit` on a yet not fully initialized editor doesn't make sense, and hence this should fail fast (i.e., throwing a NPE is a good way to inform the developer that is doing the wrong thing, returning None is not as good IMO). Furtheremore, if you look at the implementations of `getInteractiveCompilationUnit` in `ScalaSourceFileEditor` and `ScalaClassFileEditor`, you will see that both implementations already assumed that a compilation unit is already attached to the editor (the compilation unit is wrapped in a `Some`, not in an `Option`). Therefore, returning an `Option` appears like an unneeded overhead, and the current implementation should work no worse than the former. * Added debug output to know how much time is spent for 1) Building the mark occurrences index, and 2) end-to-end update occurrences action.
- Loading branch information...
Showing with 98 additions and 79 deletions.
- +1 −1 org.scala-ide.sdt.core.tests/src/scala/tools/eclipse/occurrences/OccurrencesFinderTest.scala
- +3 −3 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaClassFileEditor.scala
- +24 −25 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaSourceFileEditor.scala
- +50 −28 org.scala-ide.sdt.core/src/scala/tools/eclipse/markoccurrences/ScalaOccurrencesFinder.scala
- +1 −3 org.scala-ide.sdt.core/src/scala/tools/eclipse/ui/InteractiveCompilationUnitEditor.scala
- +1 −1 org.scala-ide.sdt.core/src/scala/tools/eclipse/util/EditorUtils.scala
- +18 −18 org.scala-ide.sdt.spy/src/org/scalaide/spy/SpyView.scala