So far there was Thread.sleep used with some hardcoded value to ensure that all events were propagated correctly after the build. In general it was: a) buld project with changes b) there are some post-build actions performed and events are sent in a background so wait 500 millis It was causing problems in case of Scala's Jenkins for which 500 millis was too low value. Also it's not the best idea to wait 500 millis (always) even if it's not needed. Therefore, this commit provides a bit smarter solution. From now on HCR-related publisher publishes the HCRSucceeded event, when HCR is finished. In tests we take into account what happens under the hood in aforementioned point b. It is: 1. perform HCR 2. send a message to the thread-related actor => some asynchronous processing (at the end we fire an event) 3. send a message to the breakpoints-related actor => some asynchronous processing 4. notify subscribers about finished HCR (asynchronously) In tests we wait for the events from points 2 and 4 (with some quite big time limit, what should be helpful in case of Jenkins), and after that check whether current stack frame is correct, variables have proper values and so on. Unfortunately there's no event etc. from BreakpointSupport so we check nothing related to the third point. From now on the test checking whether disabling HCR works correctly checks only that ScalaHotCodeReplaceManager is not created for ScalaDebugTarget. It's enough. There's also added to ScalaHotCodeReplaceManager the detailed description how HCR works in case of errors in Java or Scala code (the differences are a result of differences in deltas which we get in events).
An expression evaluated in expression evaluator can contain the assignment to var or call a method having side effects like changes in some internal or global state. That's why we need to refresh the variables view - to have it up to date after such possible modifications. Unfortunately there's one related inconvenience. If user had some non-top-level node selected in the variables view, he can loose the current selection. Then it's needed to select this element once again. Therefore, there's also added an option in preferences which allows to turn this refreshing off. It's a tradeoff.
This commit provides corrections after the code review. A class and an object used as messages when reenabling breakpoints are described and placed in proper companion objects. ChangedClassFilesVisitor can't be reused anymore but we got rid of var and `reset` method. In case of error we use eclipseLog so users will be aware that something went wrong. I find it quite informative, when I see that redefining classes failed e.g. because of: java.lang.UnsupportedOperationException: Add method not implemented at org.eclipse.jdi.internal.VirtualMachineImpl.redefineClasses(VirtualMachineImpl.java:1245) (...) There's also used EclipseUtils.withSafeRunner when it's possible. Also corrected comments and logged messages (inter alia they are more consistent with other error messages which we have in Scala IDE).
This commit adds the possibility to modify and compile code, when an application is run in a debug mode, and to have these changes visible and taken into account by the debugged VM without restarting the application. This feature can be turned on/off (right now it's turned off by default). User can decide whether files containing compilation errors should be skipped. Stack frames affected by changes can be automatically dropped. Sometimes users don't like automatic dropping frames after HCR and they prefer to do that manually (see HCR in IntelliJ). Right now there's added also such a possibility. On the other hand it's a question whether it should be available, if we'll know it can cause problems. Therefore, it may be removed in the future, if the HCR with automatic dropping frames would be much more reliable. There are also added several integration JUnit tests. Note that HCR is limited by JVM's support for replacing classes. Its goal is to allow to experiment with the code inside methods/blocks rather than to develop the whole application in the interactive mode. Changes of methods' signatures etc. don't work - similarly to other HCR implementations from Eclipse or other IDEs. The implementation is inspired by the HCR support for Java. Scala debug target, threads etc. don't extend the default Java/JDI model and build their own one. Therefore, they are skipped when processing events by various Java-focused managers. There's added ScalaHotCodeReplaceManager which implements HCR support using the Scala model. Every ScalaDebugTarget has its instance of manager which is also the listener waiting for events related to changed resources. When we get an event about changed class files, we get byte arrays containing new versions of these files and replace the old ones in VM. After this operation it's needed to rebind frames (optionally also drop the obsolete ones) and to refresh breakpoints. Each from several added tests contains a fragment where the code is modified and recompiled. To ensure that all events and messages are correctly propagated after the additional incremental build, it was needed to use Thread.sleep with 500 millis. I know it's quite ugly solution but it seems to work well and there are not many such tests. There are serious reasons why this implementation is called the basic support: - Automatic dropping frames is based on the information which frames are marked as obsolete. - We get this information after performing HCR but it can cause problems. According to the comment from Eclipse's HCR implementation for Java, JVM is faulty when there are frames rendered as obsolete. Therefore, in Java implementation they try to find affected frames and drop them before performing HCR. We should do the same thing because VM sometimes crashes after HCR and some additional operations. This is the serious blocker. Anyway even current implementation can be quite helpful in many situations. Except JUnit tests it was used to debug e.g.some multithreaded application using futures. - There's also another problem. After performing HCR sometimes already existing breakpoints behave strange. I had situations where from time to time I was getting a JDI event for the line breakpoint with the different location than the line specified for this breakpoint (sometimes it was one line before or after the expected one). I was investigating this for a while but didn't figure out what to do with that. Also I wasn't able to reproduce such a behaviour in tests. It's something, what should be checked once again after the addition of the new approach to drop affected frames. In case of problems it's always possible to recreate given frame manually, drop to the above frame and go to the expected breakpoint once again. Note: it's sometimes hard to hit breakpoints in Scala IDE even without HCR (they quite often are nondeterministic from the end-user's point of view of). Hence, it's not so simple to test this. It's not possible to fix everything, which basically is not related to this particular feature, but is also used when debugging. - Dialogs shown when replacing classes is not supported by VM or fails don't contain buttons to terminate or restart debug session. Currently there's only an adequate message.
If multiple debug handlers exist and one answers with a `SuspendExecution` and another one answers with a `ContinueExecution` event, we should not send multiple times the event command to the internal debugger logic.
Instead of returning an untyped Option, the `eventHandler` method of `DebugEventHandler` can now return a meaningful subclass of the `JdiEventCommand` trait. Furthermore, all debug event handlers are now processed and not just the first one that returns a meaningful result.
Instead of sharing a preference page with the debugger, the expression evaluator should have its own one. Furthermore, it also uses its own preference store, to not get in conflict with debugger preferences and to make it more independent from the debugger itself.
- There is a common problem when definitions should be shared that are defined in plugin fragments. It turned out that this is necessary for the test fragments. They define some reusable test classes which should be accessed in other test fragments. Because these test classes are only defined in fragments but not in their corresponding plugins, it is not directly possible to access them. However, by defining the property Eclipse-ExtensibleAPI: true in the `MANIFEST.MF` of a plugin, the Eclipse builder allows to access fragment definitions at compile time. More information about this property can be found at http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fbundle_manifest.html Other solutions and a more in depth explanation to the class sharing problem can be found at https://rcpquickstart.wordpress.com/2007/06/20/unit-testing-plug-ins-with-fragments/ - The above solution of adding the `Eclipse-ExtensibleAPI` does only work for the Eclipse builder but not for our build tool maven. In order to allow maven to access the classes of fragments one has to put the property jars.extra.classpath = platform:/fragment/<id> to the `build.properties` of the fragment that needs to access another fragments' definitions. `<id>` has to be replaced with the plugin id of the fragment, whose definitions should be accessed. - The `build.properties` of a plugin should include the current directory (represented as .) in the `bin.includes` property. If it is not included there, no classes are put into the output directory. In Eclipse itself, one does not get a warning about that, but the maven build fails because it can't find the classes.
Allows user to evaluate any Scala expression in context of some breakpoint during debug. Expression is transformed in multiple phases and evaluated using calls to remote, debuged machine and result is fetched back to user. Because of complexity of Scala language, implementation details of JVM platform and necessity for manual evaluation not all Scala features are supported yet. Co-authored-by: - Pawel Batko <email@example.com> - Piotr Kukielka <firstname.lastname@example.org> - Jerzy Muller <email@example.com> - Michal Pociecha <firstname.lastname@example.org> - Krzysztof Romanowski <email@example.com>
ScalaDebugger now capture frame indexes. Frame indexes are needed to evaluate expressions on stack frames differrent than current one. Correct SuspendPolicy handling. Before, debugger always suspended thread, now suspending whole VM is correclty handled. DebugTarget now stores classpath of underlying project, which is used to load files to inspect for generics, imports etc. Minor corrections to ScalaClassFile. Some minor boyscouting here and there.
- expanded and corrected documentation about source maps and related methods. - removed one instance of ⇒ that made Eclipse go nuts in that file (line spacing was increased, see (https://bugs.eclipse.org/bugs/show_bug.cgi?id=206740)
The associated compilation unit may change (see #1002251) when the editor is reused. On top of that, the structured editor in the Play plugin needs a no-arg constructor (it’s instantiated through an extension point). This change allows the Play plugin to use plain Scala hovers, including all the goodies (configured font and CSS, scaladoc, etc).
…uild. This commit “merges” the platform/luna branch into master, using separate source folders for the source-incompatible differences between the two platforms. In this way we don’t need to regularly merge master into Luna, and it makes it easier to use Luna for developing the IDE itself. * Changes that proved to be source-compatible, but only added in Luna, I merged them as-is (without relying on a separate source dir for those) * jdt.core versions in the manifest file are now replaced when they are copied using the maven-antrun plugin. The substitution is performed automatically, but the syntax is slightly different than for pure maven resources. It’s not ideal but there is no way to both substitute variables and rename a given file. * I made src-luna be the default in project definitions.