This is an automated email from the ASF dual-hosted git repository. geertjan pushed a commit to branch delivery in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/delivery by this push: new af63abb Correct the breakpoint functionality in cpplite debugger. new ac5046d Merge pull request #2726 from entlicher/CPPLiteDebugBreakpoints af63abb is described below commit af63abbe04d1e02e70807302552ce2ce7375e9bc Author: Martin Entlicher <martin.entlic...@oracle.com> AuthorDate: Tue Feb 2 11:24:52 2021 +0100 Correct the breakpoint functionality in cpplite debugger. --- .../org.netbeans.spi.viewmodel.NodeModel | 1 - .../org.netbeans.spi.debugger.ActionsProvider | 2 - ...tbeans.api.debugger.LazyDebuggerManagerListener | 2 - .../org.netbeans.api.debugger.Properties$Reader | 1 - .../modules/cpplite/debugger/Bundle.properties | 27 --- .../cpplite/debugger/CPPLiteActionsProvider.java | 144 +++++++++++ .../modules/cpplite/debugger/CPPLiteDebugger.java | 263 ++++++++++---------- .../modules/cpplite/debugger/CPPThread.java | 3 + .../cpplite/debugger/DebuggerAnnotation.java | 37 ++- .../debugger/DebuggerBreakpointAnnotation.java | 115 +++++++-- .../breakpoints/BreakpointAnnotationListener.java | 111 --------- .../breakpoints/BreakpointAnnotationProvider.java | 269 +++++++++++++++++++++ .../debugger/breakpoints/BreakpointModel.java | 21 +- .../debugger/breakpoints/BreakpointsReader.java | 40 +-- .../debugger/breakpoints/CPPLiteBreakpoint.java | 74 ++++-- .../CPPLiteBreakpointActionProvider.java | 28 +-- .../debugger/breakpoints/LoadBreakpoints.java | 41 ---- .../debugger/breakpoints/PersistenceManager.java | 2 + .../debuggingview/DebuggingViewSupportImpl.java | 2 +- .../cpplite/debugger/AbstractDebugTest.java | 111 +++++++++ .../modules/cpplite/debugger/BreakpointsTest.java | 147 +++++++++++ .../modules/cpplite/debugger/StepTest.java | 69 +----- .../src/org/netbeans/api/debugger/Breakpoint.java | 2 +- 23 files changed, 1040 insertions(+), 472 deletions(-) diff --git a/cpplite/cpplite.debugger/src/META-INF/debugger/BreakpointsView/org.netbeans.spi.viewmodel.NodeModel b/cpplite/cpplite.debugger/src/META-INF/debugger/BreakpointsView/org.netbeans.spi.viewmodel.NodeModel deleted file mode 100644 index b2ec1a2..0000000 --- a/cpplite/cpplite.debugger/src/META-INF/debugger/BreakpointsView/org.netbeans.spi.viewmodel.NodeModel +++ /dev/null @@ -1 +0,0 @@ -org.netbeans.modules.cpplite.debugger.breakpoints.BreakpointModel \ No newline at end of file diff --git a/cpplite/cpplite.debugger/src/META-INF/debugger/CPPLiteSession/org.netbeans.spi.debugger.ActionsProvider b/cpplite/cpplite.debugger/src/META-INF/debugger/CPPLiteSession/org.netbeans.spi.debugger.ActionsProvider deleted file mode 100644 index 948c17a..0000000 --- a/cpplite/cpplite.debugger/src/META-INF/debugger/CPPLiteSession/org.netbeans.spi.debugger.ActionsProvider +++ /dev/null @@ -1,2 +0,0 @@ -org.netbeans.modules.cpplite.debugger.CPPLiteDebugger -org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpointActionProvider \ No newline at end of file diff --git a/cpplite/cpplite.debugger/src/META-INF/debugger/org.netbeans.api.debugger.LazyDebuggerManagerListener b/cpplite/cpplite.debugger/src/META-INF/debugger/org.netbeans.api.debugger.LazyDebuggerManagerListener deleted file mode 100644 index b7903e7..0000000 --- a/cpplite/cpplite.debugger/src/META-INF/debugger/org.netbeans.api.debugger.LazyDebuggerManagerListener +++ /dev/null @@ -1,2 +0,0 @@ -org.netbeans.modules.cpplite.debugger.breakpoints.BreakpointAnnotationListener -org.netbeans.modules.cpplite.debugger.breakpoints.PersistenceManager \ No newline at end of file diff --git a/cpplite/cpplite.debugger/src/META-INF/debugger/org.netbeans.api.debugger.Properties$Reader b/cpplite/cpplite.debugger/src/META-INF/debugger/org.netbeans.api.debugger.Properties$Reader deleted file mode 100644 index 4ce300b..0000000 --- a/cpplite/cpplite.debugger/src/META-INF/debugger/org.netbeans.api.debugger.Properties$Reader +++ /dev/null @@ -1 +0,0 @@ -org.netbeans.modules.cpplite.debugger.breakpoints.BreakpointsReader \ No newline at end of file diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/Bundle.properties b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/Bundle.properties index fa230e4..5ccc602 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/Bundle.properties +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/Bundle.properties @@ -18,30 +18,3 @@ OpenIDE-Module-Display-Category=C/C++ OpenIDE-Module-Name=CPPLite Debugger -# RunTargetsAction -LBL_run_other_targets=Other Targets -LBL_run_advanced=Advanced... -TITLE_run_advanced=Debug Ant Target -LBL_run_advanced_run=Debug -LBL_run_advanced_cancel=Cancel - -# AdvancedActionsPanel -AdvancedActionsPanel.targetLabel.text=Select &target(s) to debug\: -AdvancedActionsPanel.targetDescriptionLabel.text=Target description\: -AdvancedActionsPanel.propertiesLabel.text=Special Ant &properties\: -AdvancedActionsPanel.verbosityLabel.text=&Verbosity level\: -LBL_verbosity_warn=Quiet -LBL_verbosity_info=Normal -LBL_verbosity_verbose=Verbose -LBL_verbosity_debug=Debug - -#org.netbeans.modules.debugger.jpda.ui.DebuggerAnnotation -TOOLTIP_DISABLED_CONDITIONAL_BREAKPOINT=Disabled Conditional Breakpoint -TOOLTIP_DISABLED_BREAKPOINT=Disabled Breakpoint -TOOLTIP_CALLSITE=Call Stack Line -TOOLTIP_BREAKPOINT=Breakpoint -TOOLTIP_CONDITIONAL_BREAKPOINT=Conditional Breakpoint -TOOLTIP_CURRENT_PC=Current Program Counter -TOOLTIP_CURRENT_PC_2=Current Target - -CTL_WatchDisabled=>disabled< diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteActionsProvider.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteActionsProvider.java new file mode 100644 index 0000000..8ce1378 --- /dev/null +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteActionsProvider.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.cpplite.debugger; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.netbeans.api.debugger.ActionsManager; +import org.netbeans.spi.debugger.ActionsProvider; +import org.netbeans.spi.debugger.ActionsProviderSupport; +import org.netbeans.spi.debugger.ContextProvider; +import org.openide.util.RequestProcessor; + +/** + * The CPP Lite Debugger's actions provider. + */ +@ActionsProvider.Registration(path="CPPLiteSession", actions={"start", "stepInto", "stepOver", "stepOut", + "pause", "continue", "kill"}) +public final class CPPLiteActionsProvider extends ActionsProviderSupport { + + private static final Logger LOGGER = Logger.getLogger(CPPLiteActionsProvider.class.getName()); + + private static final Set<Object> ACTIONS = new HashSet<>(); + private static final Set<Object> ACTIONS_TO_DISABLE = new HashSet<>(); + + static { + ACTIONS.add (ActionsManager.ACTION_KILL); + ACTIONS.add (ActionsManager.ACTION_CONTINUE); + ACTIONS.add (ActionsManager.ACTION_PAUSE); + ACTIONS.add (ActionsManager.ACTION_START); + ACTIONS.add (ActionsManager.ACTION_STEP_INTO); + ACTIONS.add (ActionsManager.ACTION_STEP_OVER); + ACTIONS.add (ActionsManager.ACTION_STEP_OUT); + ACTIONS_TO_DISABLE.addAll(ACTIONS); + // Ignore the KILL action + ACTIONS_TO_DISABLE.remove(ActionsManager.ACTION_KILL); + } + + /** The ReqeustProcessor used by action performers. */ + private static RequestProcessor actionsRequestProcessor; + private static RequestProcessor killRequestProcessor; + + private final CPPLiteDebugger debugger; + + public CPPLiteActionsProvider(ContextProvider contextProvider) { + debugger = contextProvider.lookupFirst(null, CPPLiteDebugger.class); + // init actions + for (Object action : ACTIONS) { + setEnabled (action, true); + } + } + + @Override + public Set getActions () { + return ACTIONS; + } + + @Override + public void doAction (Object action) { + LOGGER.log(Level.FINE, "CPPLiteDebugger.doAction({0}), is kill = {1}", new Object[]{action, action == ActionsManager.ACTION_KILL}); + if (action == ActionsManager.ACTION_KILL) { + debugger.finish(); + } else + if (action == ActionsManager.ACTION_CONTINUE) { + debugger.resume(); + } else + if (action == ActionsManager.ACTION_PAUSE) { + debugger.pause(); + } else + if (action == ActionsManager.ACTION_START) { + return ; + } else + if ( action == ActionsManager.ACTION_STEP_INTO || + action == ActionsManager.ACTION_STEP_OUT || + action == ActionsManager.ACTION_STEP_OVER + ) { + debugger.doStep (action); + } + } + + @Override + public void postAction(final Object action, final Runnable actionPerformedNotifier) { + if (action == ActionsManager.ACTION_KILL) { + synchronized (CPPLiteDebugger.class) { + if (killRequestProcessor == null) { + killRequestProcessor = new RequestProcessor("CPPLite debugger finish RP", 1); + } + } + killRequestProcessor.post(new Runnable() { + @Override + public void run() { + try { + doAction(action); + } finally { + actionPerformedNotifier.run(); + } + } + }); + return ; + } + setDebugActionsEnabled(false); + synchronized (CPPLiteDebugger.class) { + if (actionsRequestProcessor == null) { + actionsRequestProcessor = new RequestProcessor("CPPLite debugger actions RP", 1); + } + } + actionsRequestProcessor.post(new Runnable() { + @Override + public void run() { + try { + doAction(action); + } finally { + actionPerformedNotifier.run(); + setDebugActionsEnabled(true); + } + } + }); + } + + private void setDebugActionsEnabled(boolean enabled) { + for (Object action : ACTIONS_TO_DISABLE) { + setEnabled(action, enabled); + } + } + +} diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java index 0193378..87d6587 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java @@ -19,6 +19,8 @@ package org.netbeans.modules.cpplite.debugger; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -27,10 +29,9 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; import java.util.EventListener; -import java.util.Iterator; -import java.util.HashSet; import java.util.List; -import java.util.Set; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; @@ -43,6 +44,7 @@ import org.netbeans.api.debugger.Breakpoint; import org.netbeans.api.debugger.DebuggerEngine; import org.netbeans.api.debugger.DebuggerInfo; import org.netbeans.api.debugger.DebuggerManager; +import org.netbeans.api.debugger.DebuggerManagerAdapter; import org.netbeans.modules.cnd.debugger.gdb2.mi.MICommand; import org.netbeans.modules.cnd.debugger.gdb2.mi.MICommandInjector; import org.netbeans.modules.cnd.debugger.gdb2.mi.MIConst; @@ -54,7 +56,6 @@ import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory; import org.netbeans.modules.nativeexecution.api.pty.Pty; import org.netbeans.modules.nativeexecution.api.pty.PtySupport; -import org.netbeans.spi.debugger.ActionsProviderSupport; import org.netbeans.spi.debugger.ContextProvider; import org.netbeans.spi.debugger.DebuggerEngineProvider; import org.netbeans.spi.debugger.SessionProvider; @@ -62,6 +63,7 @@ import org.netbeans.spi.debugger.ui.DebuggingView; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; +import org.openide.text.Annotatable; import org.openide.text.Line; import org.openide.util.Exceptions; import org.openide.util.Pair; @@ -72,22 +74,19 @@ import org.openide.util.RequestProcessor; * * @author Honza */ -public class CPPLiteDebugger extends ActionsProviderSupport { +public final class CPPLiteDebugger { private static final Logger LOGGER = Logger.getLogger(CPPLiteDebugger.class.getName()); - /** The ReqeustProcessor used by action performers. */ - private static RequestProcessor actionsRequestProcessor; - private static RequestProcessor killRequestProcessor; - private CPPLiteDebuggerConfig configuration; private CPPLiteDebuggerEngineProvider engineProvider; private ContextProvider contextProvider; private Process debuggee; private LiteMIProxy proxy; - private Object currentLine; + private volatile Object currentLine; private volatile boolean suspended = false; private final List<StateListener> stateListeners = new CopyOnWriteArrayList<>(); + private final BreakpointsHandler breakpointsHandler = new BreakpointsHandler(); private final ThreadsCollector threadsCollector = new ThreadsCollector(this); private volatile CPPThread currentThread; @@ -98,10 +97,6 @@ public class CPPLiteDebugger extends ActionsProviderSupport { configuration = contextProvider.lookupFirst(null, CPPLiteDebuggerConfig.class); // init engineProvider engineProvider = (CPPLiteDebuggerEngineProvider) contextProvider.lookupFirst(null, DebuggerEngineProvider.class); - // init actions - for (Iterator it = actions.iterator(); it.hasNext(); ) { - setEnabled (it.next(), true); - } } void setDebuggee(Process debuggee) { @@ -125,17 +120,7 @@ public class CPPLiteDebugger extends ActionsProviderSupport { proxy.waitStarted(); - for (Breakpoint b : DebuggerManager.getDebuggerManager ().getBreakpoints ()) { - if (b instanceof CPPLiteBreakpoint) { - CPPLiteBreakpoint cpplineBreakpoint = (CPPLiteBreakpoint) b; - Line l = cpplineBreakpoint.getLine(); - FileObject source = l.getLookup().lookup(FileObject.class); - File sourceFile = source != null ? FileUtil.toFile(source) : null; - if (sourceFile != null) { - proxy.send(new Command("-break-insert " + sourceFile.getAbsolutePath() + ":" + (l.getLineNumber() + 1))); - } - } - } + breakpointsHandler.init(); proxy.send(new Command("-gdb-set target-async")); //proxy.send(new Command("-gdb-set scheduler-locking on")); @@ -143,55 +128,6 @@ public class CPPLiteDebugger extends ActionsProviderSupport { proxy.send(new Command("-exec-run")); } - // ActionsProvider ......................................................... - - private static final Set<Object> actions = new HashSet<>(); - private static final Set<Object> actionsToDisable = new HashSet<>(); - static { - actions.add (ActionsManager.ACTION_KILL); - actions.add (ActionsManager.ACTION_CONTINUE); - actions.add (ActionsManager.ACTION_PAUSE); - actions.add (ActionsManager.ACTION_START); - actions.add (ActionsManager.ACTION_STEP_INTO); - actions.add (ActionsManager.ACTION_STEP_OVER); - actions.add (ActionsManager.ACTION_STEP_OUT); - actionsToDisable.addAll(actions); - // Ignore the KILL action - actionsToDisable.remove(ActionsManager.ACTION_KILL); - } - - @Override - public Set getActions () { - return actions; - } - - @Override - public void doAction (Object action) { - LOGGER.log(Level.FINE, "CPPLiteDebugger.doAction({0}), is kill = {1}", new Object[]{action, action == ActionsManager.ACTION_KILL}); - if (action == ActionsManager.ACTION_KILL) { - finish (); - } else - if (action == ActionsManager.ACTION_CONTINUE) { - CPPThread thread = currentThread; - if (thread != null) { - thread.notifyRunning(); - } - proxy.send(new Command("-exec-continue --all")); - } else - if (action == ActionsManager.ACTION_PAUSE) { - proxy.send(new Command("-exec-interrupt --all")); - } else - if (action == ActionsManager.ACTION_START) { - return ; - } else - if ( action == ActionsManager.ACTION_STEP_INTO || - action == ActionsManager.ACTION_STEP_OUT || - action == ActionsManager.ACTION_STEP_OVER - ) { - doStep (action); - } - } - private static class CPPLiteInjector implements MICommandInjector { private final OutputStream out; @@ -218,51 +154,6 @@ public class CPPLiteDebugger extends ActionsProviderSupport { } - @Override - public void postAction(final Object action, final Runnable actionPerformedNotifier) { - if (action == ActionsManager.ACTION_KILL) { - synchronized (CPPLiteDebugger.class) { - if (killRequestProcessor == null) { - killRequestProcessor = new RequestProcessor("CPPLite debugger finish RP", 1); - } - } - killRequestProcessor.post(new Runnable() { - @Override - public void run() { - try { - doAction(action); - } finally { - actionPerformedNotifier.run(); - } - } - }); - return ; - } - setDebugActionsEnabled(false); - synchronized (CPPLiteDebugger.class) { - if (actionsRequestProcessor == null) { - actionsRequestProcessor = new RequestProcessor("CPPLite debugger actions RP", 1); - } - } - actionsRequestProcessor.post(new Runnable() { - @Override - public void run() { - try { - doAction(action); - } finally { - actionPerformedNotifier.run(); - setDebugActionsEnabled(true); - } - } - }); - } - - private void setDebugActionsEnabled(boolean enabled) { - for (Object action : actionsToDisable) { - setEnabled(action, enabled); - } - } - MIRecord sendAndGet(String command) throws InterruptedException { return sendAndGet(command, false); } @@ -434,7 +325,7 @@ public class CPPLiteDebugger extends ActionsProviderSupport { /** * should define callStack based on callStackInternal & action. */ - private void doStep (Object action) { + void doStep (Object action) { CPPThread thread = currentThread; String threadId = ""; if (thread != null) { @@ -450,12 +341,22 @@ public class CPPLiteDebugger extends ActionsProviderSupport { } } - private void finish () { + void pause() { + proxy.send(new Command("-exec-interrupt --all")); + } + + void resume() { + threadsCollector.running("all"); + proxy.send(new Command("-exec-continue --all")); + } + + void finish () { LOGGER.fine("CPPLiteDebugger.finish()"); if (finished) { LOGGER.fine("finish(): already finished."); return ; } + breakpointsHandler.dispose(); proxy.send(new Command("-gdb-exit")); Utils.unmarkCurrent (); engineProvider.getDestructor().killEngine(); @@ -526,8 +427,10 @@ public class CPPLiteDebugger extends ActionsProviderSupport { if (frame != null) { Line currentLine = frame.location(); if (currentLine != null) { - Utils.markCurrent(new Line[] {currentLine}); - Utils.showLine(new Line[] {currentLine}); + Annotatable[] lines = new Annotatable[] {currentLine}; + CPPLiteDebugger.this.currentLine = lines; + Utils.markCurrent(lines); + Utils.showLine(lines); } } break; @@ -645,7 +548,7 @@ public class CPPLiteDebugger extends ActionsProviderSupport { } - public static @NonNull Pair<CPPLiteDebugger, Process> startDebugging (CPPLiteDebuggerConfig configuration) throws IOException { + public static @NonNull Pair<DebuggerEngine, Process> startDebugging (CPPLiteDebuggerConfig configuration) throws IOException { DebuggerInfo di = DebuggerInfo.create ( "CPPLiteDebuggerInfo", new Object[] { @@ -702,7 +605,7 @@ public class CPPLiteDebugger extends ActionsProviderSupport { }); debugger.setDebuggee(debuggee); - return Pair.of(debugger, new Process() { + return Pair.of(es[0], new Process() { @Override public OutputStream getOutputStream() { return pty.getOutputStream(); @@ -734,4 +637,114 @@ public class CPPLiteDebugger extends ActionsProviderSupport { } }); } + + private class BreakpointsHandler extends DebuggerManagerAdapter implements PropertyChangeListener { + + private final Map<String, CPPLiteBreakpoint> breakpointsById = new ConcurrentHashMap<>(); + private final Map<CPPLiteBreakpoint, String> breakpointIds = new ConcurrentHashMap<>(); + + BreakpointsHandler() { + } + + private void init() { + DebuggerManager.getDebuggerManager().addDebuggerListener(DebuggerManager.PROP_BREAKPOINTS, this); + for (Breakpoint b : DebuggerManager.getDebuggerManager().getBreakpoints()) { + if (b instanceof CPPLiteBreakpoint) { + CPPLiteBreakpoint cpplineBreakpoint = (CPPLiteBreakpoint) b; + addBreakpoint(cpplineBreakpoint); + } + } + } + + void dispose() { + DebuggerManager.getDebuggerManager().removeDebuggerListener(DebuggerManager.PROP_BREAKPOINTS, this); + for (Breakpoint b : DebuggerManager.getDebuggerManager().getBreakpoints()) { + if (b instanceof CPPLiteBreakpoint) { + b.removePropertyChangeListener(this); + } + } + } + + @Override + public void breakpointAdded(Breakpoint breakpoint) { + if (breakpoint instanceof CPPLiteBreakpoint) { + addBreakpoint((CPPLiteBreakpoint) breakpoint); + } + } + + @Override + public void breakpointRemoved(Breakpoint breakpoint) { + if (breakpoint instanceof CPPLiteBreakpoint) { + removeBreakpoint((CPPLiteBreakpoint) breakpoint); + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Object source = evt.getSource(); + if (source instanceof CPPLiteBreakpoint) { + String id = breakpointIds.get((CPPLiteBreakpoint) source); + if (id != null) { + String propertyName = evt.getPropertyName(); + switch (propertyName) { + case Breakpoint.PROP_ENABLED: + if (Boolean.TRUE.equals(evt.getNewValue())) { + proxy.send(new Command("-break-enable " + id)); + } else { + proxy.send(new Command("-break-disable " + id)); + } + break; + } + } + } + } + + private void addBreakpoint(CPPLiteBreakpoint breakpoint) { + Line l = breakpoint.getLine(); + FileObject source = l.getLookup().lookup(FileObject.class); + File sourceFile = source != null ? FileUtil.toFile(source) : null; + if (sourceFile != null) { + String disabled = breakpoint.isEnabled() ? "" : "-d "; + Command command = new Command("-break-insert " + disabled + sourceFile.getAbsolutePath() + ":" + (l.getLineNumber() + 1)) { + @Override + protected void onDone(MIRecord record) { + MIValue bkpt = record.results().valueOf("bkpt"); + if (bkpt instanceof MITList) { + breakpointResolved(breakpoint, (MITList) bkpt); + } + super.onDone(record); + } + + @Override + protected void onError(MIRecord record) { + String msg = record.results().getConstValue("msg"); + breakpointError(breakpoint, msg); + super.onError(record); + } + }; + proxy.send(command); + } + breakpoint.addPropertyChangeListener(this); + } + + private void removeBreakpoint(CPPLiteBreakpoint breakpoint) { + String id = breakpointIds.remove(breakpoint); + if (id != null) { + breakpoint.removePropertyChangeListener(this); + Command command = new Command("-break-delete " + id); + proxy.send(command); + } + } + + private void breakpointResolved(CPPLiteBreakpoint breakpoint, MITList list) { + breakpoint.setCPPValidity(Breakpoint.VALIDITY.VALID, null); + String id = list.getConstValue("number"); + breakpointsById.put(id, breakpoint); + breakpointIds.put(breakpoint, id); + } + + private void breakpointError(CPPLiteBreakpoint breakpoint, String msg) { + breakpoint.setCPPValidity(Breakpoint.VALIDITY.INVALID, msg); + } + } } diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java index b3e945c..6158f6e 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java @@ -258,6 +258,9 @@ public final class CPPThread implements DVThread { void notifyRunning() { synchronized (this) { + if (status == Status.RUNNING) { + return ; + } status = Status.RUNNING; topFrame = null; stack = null; diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerAnnotation.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerAnnotation.java index c792b0c..3642570 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerAnnotation.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerAnnotation.java @@ -42,34 +42,33 @@ public class DebuggerAnnotation extends Annotation { /** Annotation type constant. */ public static final String CALL_STACK_FRAME_ANNOTATION_TYPE = "CallSite"; - private Annotatable annotatable; - private String type; - - + private final String type; + public DebuggerAnnotation (String type, Annotatable annotatable) { this.type = type; - this.annotatable = annotatable; attach (annotatable); } - + @Override public String getAnnotationType () { return type; } - + @Override + @NbBundle.Messages({"TTP_CurrentPC=Current Program Counter", + "TTP_CurrentPC2=Current Target", + "TTP_Callsite=Call Stack Line"}) public String getShortDescription () { - if (type == CURRENT_LINE_ANNOTATION_TYPE) - return NbBundle.getMessage(DebuggerAnnotation.class, "TOOLTIP_CURRENT_PC"); - else - if (type == CURRENT_LINE_ANNOTATION_TYPE2) - return NbBundle.getMessage(DebuggerAnnotation.class, "TOOLTIP_CURRENT_PC_2"); - else - if (type == CURRENT_LINE_PART_ANNOTATION_TYPE) - return NbBundle.getMessage(DebuggerAnnotation.class, "TOOLTIP_CURRENT_PC"); - else - if (type == CALL_STACK_FRAME_ANNOTATION_TYPE) - return NbBundle.getMessage(DebuggerAnnotation.class, "TOOLTIP_CALLSITE"); - return null; + switch (type) { + case CURRENT_LINE_ANNOTATION_TYPE: + case CURRENT_LINE_PART_ANNOTATION_TYPE: + return Bundle.TTP_CurrentPC(); + case CURRENT_LINE_ANNOTATION_TYPE2: + return Bundle.TTP_CurrentPC2(); + case CALL_STACK_FRAME_ANNOTATION_TYPE: + return Bundle.TTP_Callsite(); + default: + throw new IllegalStateException(type); + } } } diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java index bb51639..f5e90b3 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java @@ -19,7 +19,11 @@ package org.netbeans.modules.cpplite.debugger; +import java.util.LinkedList; +import java.util.List; + import org.netbeans.api.debugger.Breakpoint; +import org.netbeans.api.debugger.Breakpoint.HIT_COUNT_FILTERING_STYLE; import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint; import org.netbeans.spi.debugger.ui.BreakpointAnnotation; import org.openide.text.Annotatable; @@ -42,41 +46,104 @@ public class DebuggerBreakpointAnnotation extends BreakpointAnnotation { /** Annotation type constant. */ public static final String DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE = "DisabledCondBreakpoint"; // NOI18N - private Annotatable annotatable; - private String type; - private CPPLiteBreakpoint breakpoint; - - + private final String type; + private final CPPLiteBreakpoint breakpoint; + public DebuggerBreakpointAnnotation (String type, CPPLiteBreakpoint b) { this.type = type; - this.annotatable = b.getLine (); this.breakpoint = b; + Annotatable annotatable = b.getLine (); attach (annotatable); } - + @Override public String getAnnotationType () { return type; } - + @Override + @NbBundle.Messages({"TTP_Breakpoint_Hits=Hits when:", + "# {0} - hit count", + "TTP_Breakpoint_HitsEqual=Hit count \\= {0}", + "# {0} - hit count", + "TTP_Breakpoint_HitsGreaterThan=Hit count > {0}", + "# {0} - hit count", + "TTP_Breakpoint_HitsMultipleOf=Hit count is multiple of {0}"}) public String getShortDescription () { - if (type == BREAKPOINT_ANNOTATION_TYPE) - return NbBundle.getMessage - (DebuggerBreakpointAnnotation.class, "TOOLTIP_BREAKPOINT"); - else - if (type == DISABLED_BREAKPOINT_ANNOTATION_TYPE) - return NbBundle.getMessage - (DebuggerBreakpointAnnotation.class, "TOOLTIP_DISABLED_BREAKPOINT"); - else - if (type == CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE) - return NbBundle.getMessage - (DebuggerBreakpointAnnotation.class, "TOOLTIP_CONDITIONAL_BREAKPOINT"); - else - if (type == DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE) - return NbBundle.getMessage - (DebuggerBreakpointAnnotation.class, "TOOLTIP_DISABLED_CONDITIONAL_BREAKPOINT"); - return null; + List<String> list = new LinkedList<>(); + //add condition if available + String condition = breakpoint.getCondition(); + if (condition != null) { + list.add(condition); + } + + // add hit count if available + HIT_COUNT_FILTERING_STYLE hitCountFilteringStyle = breakpoint.getHitCountFilteringStyle(); + if (hitCountFilteringStyle != null) { + int hcf = breakpoint.getHitCountFilter(); + String tooltip; + switch (hitCountFilteringStyle) { + case EQUAL: + tooltip = Bundle.TTP_Breakpoint_HitsEqual(hcf); + break; + case GREATER: + tooltip = Bundle.TTP_Breakpoint_HitsGreaterThan(hcf); + break; + case MULTIPLE: + tooltip = Bundle.TTP_Breakpoint_HitsMultipleOf(hcf); + break; + default: + throw new IllegalStateException("Unknown HitCountFilteringStyle: "+hitCountFilteringStyle); // NOI18N + } + list.add(tooltip); + } + + String typeDesc = getBPTypeDescription(); + if (list.isEmpty()) { + return typeDesc; + } + StringBuilder result = new StringBuilder(typeDesc); + //append more information + result.append("\n"); // NOI18N + result.append(Bundle.TTP_Breakpoint_Hits()); + for (String text : list) { + result.append("\n"); // NOI18N + result.append(text); + } + return result.toString(); + } + + @NbBundle.Messages({"TTP_Breakpoint=Breakpoint", + "TTP_BreakpointDisabled=Disabled Breakpoint", + "TTP_BreakpointConditional=Conditional Breakpoint", + "TTP_BreakpointDisabledConditional=Disabled Conditional Breakpoint", + "TTP_BreakpointBroken=Broken breakpoint - It is not possible to stop on this line.", + "# {0} - Reason for being invalid", + "TTP_BreakpointBrokenInvalid=Broken breakpoint: {0}", + "TTP_BreakpointStroke=Deactivated breakpoint"}) + private String getBPTypeDescription () { + if (type.endsWith("_broken")) { // NOI18N + if (breakpoint.getValidity() == Breakpoint.VALIDITY.INVALID) { + String msg = breakpoint.getValidityMessage(); + return Bundle.TTP_BreakpointBrokenInvalid(msg); + } + return Bundle.TTP_BreakpointBroken(); + } + if (type.endsWith("_stroke")) { // NOI18N + return Bundle.TTP_BreakpointStroke(); + } + switch (type) { + case BREAKPOINT_ANNOTATION_TYPE: + return Bundle.TTP_Breakpoint(); + case DISABLED_BREAKPOINT_ANNOTATION_TYPE: + return Bundle.TTP_BreakpointDisabled(); + case CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE: + return Bundle.TTP_BreakpointConditional(); + case DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE: + return Bundle.TTP_BreakpointDisabledConditional(); + default: + throw new IllegalStateException(type); + } } @Override diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationListener.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationListener.java deleted file mode 100644 index 44b20da..0000000 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationListener.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.netbeans.modules.cpplite.debugger.breakpoints; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.HashMap; -import java.util.Map; -import org.netbeans.api.debugger.Breakpoint; -import org.netbeans.api.debugger.DebuggerManager; - -import org.netbeans.api.debugger.DebuggerManagerAdapter; -import org.netbeans.modules.cpplite.debugger.DebuggerBreakpointAnnotation; - - -/** - * Listens on {@org.netbeans.api.debugger.DebuggerManager} on - * {@link org.netbeans.api.debugger.DebuggerManager#PROP_BREAKPOINTS} - * property and annotates JPDA Debugger line breakpoints in NetBeans editor. - * - * @author Jan Jancura - */ -public class BreakpointAnnotationListener extends DebuggerManagerAdapter -implements PropertyChangeListener { - - private Map<CPPLiteBreakpoint, DebuggerBreakpointAnnotation> breakpointToAnnotation = new HashMap<>(); - - @Override - public String[] getProperties () { - return new String[] {DebuggerManager.PROP_BREAKPOINTS}; - } - - /** - * Called when some breakpoint is added. - * - * @param b breakpoint - */ - @Override - public void breakpointAdded (Breakpoint b) { - if (! (b instanceof CPPLiteBreakpoint)) return; - addAnnotation ((CPPLiteBreakpoint) b); - } - - /** - * Called when some breakpoint is removed. - * - * @param breakpoint - */ - @Override - public void breakpointRemoved (Breakpoint b) { - if (! (b instanceof CPPLiteBreakpoint)) return; - removeAnnotation (b); - } - - /** - * This method gets called when a bound property is changed. - * @param evt A PropertyChangeEvent object describing the event source - * and the property that has changed. - */ - - @Override - public void propertyChange (PropertyChangeEvent evt) { - if (evt.getPropertyName () != Breakpoint.PROP_ENABLED) return; - removeAnnotation ((Breakpoint) evt.getSource ()); - addAnnotation ((CPPLiteBreakpoint) evt.getSource ()); - } - - private void addAnnotation (CPPLiteBreakpoint b) { - breakpointToAnnotation.put ( - b, - new DebuggerBreakpointAnnotation ( - b.isEnabled () ? - DebuggerBreakpointAnnotation.BREAKPOINT_ANNOTATION_TYPE : - DebuggerBreakpointAnnotation.DISABLED_BREAKPOINT_ANNOTATION_TYPE, - b - ) - ); - b.addPropertyChangeListener ( - Breakpoint.PROP_ENABLED, - this - ); - } - - private void removeAnnotation (Breakpoint b) { - DebuggerBreakpointAnnotation annotation = (DebuggerBreakpointAnnotation) - breakpointToAnnotation.remove (b); - if (annotation == null) return; - annotation.detach (); - b.removePropertyChangeListener ( - Breakpoint.PROP_ENABLED, - this - ); - } -} diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java new file mode 100644 index 0000000..aac9137 --- /dev/null +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java @@ -0,0 +1,269 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.cpplite.debugger.breakpoints; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.netbeans.api.debugger.Breakpoint; +import org.netbeans.api.debugger.Breakpoint.VALIDITY; +import org.netbeans.api.debugger.DebuggerManager; +import org.netbeans.api.debugger.DebuggerManagerAdapter; +import org.netbeans.modules.cpplite.debugger.DebuggerBreakpointAnnotation; + +import org.openide.filesystems.FileObject; +import org.openide.loaders.DataObject; +import org.openide.text.Annotation; +import org.openide.text.AnnotationProvider; +import org.openide.text.Line; +import org.openide.util.Lookup; +import org.openide.util.RequestProcessor; +import org.openide.util.WeakListeners; +import org.openide.util.WeakSet; + + +/** + * This class is called when some file in editor is opened. It changes if + * some breakpoints are added or removed. + * + * @author Jan Jancura, Martin Entlicher + */ +@org.openide.util.lookup.ServiceProvider(service=org.openide.text.AnnotationProvider.class) +public class BreakpointAnnotationProvider extends DebuggerManagerAdapter implements AnnotationProvider { + + private final Map<CPPLiteBreakpoint, Set<Annotation>> breakpointToAnnotations = new IdentityHashMap<>(); + private final Set<FileObject> annotatedFiles = new WeakSet<>(); + private Set<PropertyChangeListener> dataObjectListeners; + private volatile boolean breakpointsActive = true; + private final RequestProcessor annotationProcessor = new RequestProcessor("CPP BP Annotation Refresh", 1); + + public BreakpointAnnotationProvider() { + DebuggerManager.getDebuggerManager().addDebuggerListener(DebuggerManager.PROP_BREAKPOINTS, this); + } + + @Override + public void annotate (Line.Set set, Lookup lookup) { + final FileObject fo = lookup.lookup(FileObject.class); + if (fo != null) { + DataObject dobj = lookup.lookup(DataObject.class); + if (dobj != null) { + PropertyChangeListener pchl = new PropertyChangeListener() { + /** annotate renamed files. */ + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (DataObject.PROP_PRIMARY_FILE.equals(evt.getPropertyName())) { + DataObject dobj = (DataObject) evt.getSource(); + final FileObject newFO = dobj.getPrimaryFile(); + annotationProcessor.post(new Runnable() { + @Override + public void run() { + annotate(newFO); + } + }); + } + } + }; + dobj.addPropertyChangeListener(WeakListeners.propertyChange(pchl, dobj)); + synchronized (this) { + if (dataObjectListeners == null) { + dataObjectListeners = new HashSet<>(); + } + // Prevent from GC. + dataObjectListeners.add(pchl); + } + } + annotate(fo); + } + } + + private void annotate (final FileObject fo) { + synchronized (breakpointToAnnotations) { + for (Breakpoint breakpoint : DebuggerManager.getDebuggerManager().getBreakpoints()) { + if (breakpoint instanceof CPPLiteBreakpoint) { + CPPLiteBreakpoint b = (CPPLiteBreakpoint) breakpoint; + if (isAt(b, fo)) { + if (!breakpointToAnnotations.containsKey(b)) { + b.addPropertyChangeListener(this); + } + removeAnnotations(b); // Remove any staled breakpoint annotations + addAnnotationTo(b); + } + } + } + annotatedFiles.add(fo); + } + } + + private static boolean isAt(CPPLiteBreakpoint b, FileObject fo) { + FileObject bfo = (FileObject) b.getLine().getLookup().lookup(FileObject.class); + return fo.equals(bfo); + } + + @Override + public void breakpointAdded(Breakpoint breakpoint) { + if (breakpoint instanceof CPPLiteBreakpoint) { + postAnnotationRefresh((CPPLiteBreakpoint) breakpoint, false, true); + breakpoint.addPropertyChangeListener (this); + } + } + + @Override + public void breakpointRemoved(Breakpoint breakpoint) { + if (breakpoint instanceof CPPLiteBreakpoint) { + breakpoint.removePropertyChangeListener (this); + postAnnotationRefresh((CPPLiteBreakpoint) breakpoint, true, false); + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Object source = evt.getSource(); + if (source instanceof CPPLiteBreakpoint) { + String propertyName = evt.getPropertyName (); + switch (propertyName) { + case Breakpoint.PROP_ENABLED: + case Breakpoint.PROP_VALIDITY: + case CPPLiteBreakpoint.PROP_CONDITION: + postAnnotationRefresh((CPPLiteBreakpoint) source, true, true); + } + } + } + + void setBreakpointsActive(boolean active) { + if (breakpointsActive == active) { + return ; + } + breakpointsActive = active; + annotationProcessor.post(new AnnotationRefresh(null, true, true)); + } + + private void postAnnotationRefresh(CPPLiteBreakpoint b, boolean remove, boolean add) { + annotationProcessor.post(new AnnotationRefresh(b, remove, add)); + } + + private final class AnnotationRefresh implements Runnable { + + private final CPPLiteBreakpoint b; + private final boolean remove; + private final boolean add; + + public AnnotationRefresh(CPPLiteBreakpoint b, boolean remove, boolean add) { + this.b = b; + this.remove = remove; + this.add = add; + } + + @Override + public void run() { + synchronized (breakpointToAnnotations) { + if (b != null) { + refreshAnnotation(b); + } else { + List<CPPLiteBreakpoint> bpts = new ArrayList<>(breakpointToAnnotations.keySet()); + for (CPPLiteBreakpoint bp : bpts) { + refreshAnnotation(bp); + } + } + } + } + + private void refreshAnnotation(CPPLiteBreakpoint b) { + assert Thread.holdsLock(breakpointToAnnotations); + removeAnnotations(b); + if (remove) { + if (!add) { + breakpointToAnnotations.remove(b); + } + } + if (add) { + breakpointToAnnotations.put(b, new WeakSet<>()); + for (FileObject fo : annotatedFiles) { + if (isAt(b, fo)) { + addAnnotationTo(b); + } + } + } + } + + } + + private static String getAnnotationType(CPPLiteBreakpoint b, boolean isConditional, + boolean active) { + boolean isInvalid = b.getValidity() == VALIDITY.INVALID; + String annotationType = b.isEnabled() ? + (isConditional ? DebuggerBreakpointAnnotation.CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE : + DebuggerBreakpointAnnotation.BREAKPOINT_ANNOTATION_TYPE) : + (isConditional ? DebuggerBreakpointAnnotation.DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE : + DebuggerBreakpointAnnotation.DISABLED_BREAKPOINT_ANNOTATION_TYPE); + if (!active) { + annotationType += "_stroke"; // NOI18N + } else if (isInvalid && b.isEnabled ()) { + annotationType += "_broken"; // NOI18N + } + return annotationType; + } + + private void addAnnotationTo(CPPLiteBreakpoint b) { + assert Thread.holdsLock(breakpointToAnnotations); + String condition = getCondition(b); + boolean isConditional = condition.trim().length() > 0 || b.getHitCountFilteringStyle() != null; + String annotationType = getAnnotationType(b, isConditional, breakpointsActive); + DebuggerBreakpointAnnotation annotation = new DebuggerBreakpointAnnotation (annotationType, b); + Set<Annotation> bpAnnotations = breakpointToAnnotations.get(b); + if (bpAnnotations == null) { + Set<Annotation> set = new WeakSet<>(); + set.add(annotation); + breakpointToAnnotations.put(b, set); + } else { + bpAnnotations.add(annotation); + breakpointToAnnotations.put(b, bpAnnotations); + } + } + + private void removeAnnotations(CPPLiteBreakpoint b) { + assert Thread.holdsLock(breakpointToAnnotations); + Set<Annotation> annotations = breakpointToAnnotations.remove(b); + if (annotations == null) { + return ; + } + for (Annotation a : annotations) { + a.detach(); + } + } + + /** + * Gets the condition of a breakpoint. + * @param b The breakpoint + * @return The condition or empty {@link String} if no condition is supported. + */ + static String getCondition(Breakpoint b) { + if (b instanceof CPPLiteBreakpoint) { + return ""; // TODO + } else { + throw new IllegalStateException(b.toString()); + } + } +} diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java index 895f4d5..6939797 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java @@ -19,12 +19,14 @@ package org.netbeans.modules.cpplite.debugger.breakpoints; -import java.util.Vector; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import org.netbeans.api.debugger.DebuggerEngine; import org.netbeans.api.debugger.DebuggerManager; import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger; import org.netbeans.modules.cpplite.debugger.Utils; +import org.netbeans.spi.debugger.DebuggerServiceRegistration; import org.netbeans.spi.viewmodel.ModelEvent; import org.netbeans.spi.viewmodel.NodeModel; import org.netbeans.spi.viewmodel.ModelListener; @@ -35,16 +37,17 @@ import org.openide.filesystems.FileObject; * * @author Jan Jancura */ +@DebuggerServiceRegistration(path="BreakpointsView", types={NodeModel.class}) public class BreakpointModel implements NodeModel { public static final String LINE_BREAKPOINT = - "org/netbeans/modules/debugger/resources/editor/Breakpoint"; + "org/netbeans/modules/debugger/resources/breakpointsView/Breakpoint"; public static final String LINE_BREAKPOINT_PC = - "org/netbeans/modules/debugger/resources/editor/Breakpoint+PC"; + "org/netbeans/modules/debugger/resources/breakpointsView/BreakpointHit"; public static final String DISABLED_LINE_BREAKPOINT = - "org/netbeans/modules/debugger/resources/editor/DisabledBreakpoint"; + "org/netbeans/modules/debugger/resources/breakpointsView/DisabledBreakpoint"; - private Vector<ModelListener> listeners = new Vector<>(); + private List<ModelListener> listeners = new CopyOnWriteArrayList<>(); // NodeModel implementation ................................................ @@ -138,10 +141,10 @@ public class BreakpointModel implements NodeModel { public void fireChanges () { - Vector<ModelListener> v = (Vector<ModelListener>)listeners.clone(); - int i, k = v.size (); - for (i = 0; i < k; i++) - v.get(i).modelChanged(new ModelEvent.TreeChanged(this)); + ModelEvent event = new ModelEvent.TreeChanged(this); + for (ModelListener l : listeners) { + l.modelChanged(event); + } } private static CPPLiteDebugger getDebugger () { diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java index 79339f4..e0d9020 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java @@ -23,6 +23,7 @@ import java.net.MalformedURLException; import java.net.URL; import org.netbeans.api.debugger.Breakpoint; import org.netbeans.api.debugger.Properties; +import org.netbeans.spi.debugger.DebuggerServiceRegistration; import org.openide.cookies.LineCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.URLMapper; @@ -35,6 +36,7 @@ import org.openide.text.Line; * * @author Jan Jancura */ +@DebuggerServiceRegistration(types={Properties.Reader.class}) public class BreakpointsReader implements Properties.Reader { @@ -67,6 +69,10 @@ public class BreakpointsReader implements Properties.Reader { hitCountFilteringStyle = null; } b.setHitCountFilter(hitCountFilter, hitCountFilteringStyle); + String condition = properties.getString(CPPLiteBreakpoint.PROP_CONDITION, null); + if (condition != null && !condition.isEmpty()) { + b.setCondition(condition); + } if (properties.getBoolean (Breakpoint.PROP_ENABLED, true)) b.enable (); else @@ -77,21 +83,25 @@ public class BreakpointsReader implements Properties.Reader { @Override public void write (Object object, Properties properties) { CPPLiteBreakpoint b = (CPPLiteBreakpoint) object; - FileObject fo = (FileObject) b.getLine ().getLookup (). - lookup (FileObject.class); - properties.setString("url", fo.toURL().toString()); - properties.setInt ( - "lineNumber", - b.getLine ().getLineNumber () - ); - properties.setString ( - Breakpoint.PROP_GROUP_NAME, - b.getGroupName () - ); - properties.setBoolean (Breakpoint.PROP_ENABLED, b.isEnabled ()); - properties.setInt(Breakpoint.PROP_HIT_COUNT_FILTER, b.getHitCountFilter()); - Breakpoint.HIT_COUNT_FILTERING_STYLE style = b.getHitCountFilteringStyle(); - properties.setInt(Breakpoint.PROP_HIT_COUNT_FILTER+"_style", style != null ? style.ordinal() : 0); // NOI18N + FileObject fo = (FileObject) b.getLine().getLookup().lookup(FileObject.class); + properties.setString("url", fo.toURL().toString()); + properties.setInt ( + "lineNumber", + b.getLine ().getLineNumber () + ); + properties.setString ( + Breakpoint.PROP_GROUP_NAME, + b.getGroupName () + ); + properties.setBoolean (Breakpoint.PROP_ENABLED, b.isEnabled ()); + properties.setInt(Breakpoint.PROP_HIT_COUNT_FILTER, b.getHitCountFilter()); + Breakpoint.HIT_COUNT_FILTERING_STYLE style = b.getHitCountFilteringStyle(); + properties.setInt(Breakpoint.PROP_HIT_COUNT_FILTER+"_style", style != null ? style.ordinal() : 0); // NOI18N + String condition = b.getCondition(); + if (condition == null) { + condition = ""; + } + properties.setString(CPPLiteBreakpoint.PROP_CONDITION, condition); } diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java index e340d84..6f063ce 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java @@ -21,7 +21,10 @@ package org.netbeans.modules.cpplite.debugger.breakpoints; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import org.netbeans.api.debugger.Breakpoint; import org.netbeans.api.debugger.DebuggerEngine; import org.netbeans.api.debugger.DebuggerManager; @@ -41,13 +44,16 @@ import org.openide.util.WeakListeners; * * @author Honza */ -public class CPPLiteBreakpoint extends Breakpoint { +public final class CPPLiteBreakpoint extends Breakpoint { - private boolean enabled = true; - private Line line; + public static final String PROP_CONDITION = "condition"; // NOI18N + private volatile boolean enabled = true; + private final Map<CPPLiteDebugger, String> ids = new HashMap<>(); + private final Line line; + private volatile String condition; - /*test?*/public CPPLiteBreakpoint (Line line) { + public CPPLiteBreakpoint (Line line) { this.line = line; } @@ -64,7 +70,7 @@ public class CPPLiteBreakpoint extends Breakpoint { public boolean isEnabled () { return enabled; } - + /** * Disables the breakpoint. */ @@ -74,7 +80,7 @@ public class CPPLiteBreakpoint extends Breakpoint { enabled = false; firePropertyChange (PROP_ENABLED, Boolean.TRUE, Boolean.FALSE); } - + /** * Enables the breakpoint. */ @@ -85,18 +91,44 @@ public class CPPLiteBreakpoint extends Breakpoint { firePropertyChange (PROP_ENABLED, Boolean.FALSE, Boolean.TRUE); } + /** + * Get the breakpoint condition, or <code>null</code>. + */ + public String getCondition() { + return condition; + } + + /** + * Set the breakpoint condition. + */ + public void setCondition(String condition) { + String oldCondition; + synchronized (this) { + oldCondition = this.condition; + if (Objects.equals(oldCondition, condition)) { + return ; + } + this.condition = condition; + } + firePropertyChange (PROP_CONDITION, oldCondition, condition); + } + + public void setCPPValidity(VALIDITY validity, String reason) { + setValidity(validity, reason); + } + @Override public GroupProperties getGroupProperties() { - return new AntGroupProperties(); + return new CPPGroupProperties(); } - private final class AntGroupProperties extends GroupProperties { + private final class CPPGroupProperties extends GroupProperties { - private AntEngineListener engineListener; + private CPPEngineListener engineListener; @Override public String getLanguage() { - return "ANT"; + return "C/C++"; } @Override @@ -140,7 +172,7 @@ public class CPPLiteBreakpoint extends Breakpoint { @Override public DebuggerEngine[] getEngines() { if (engineListener == null) { - engineListener = new AntEngineListener(); + engineListener = new CPPEngineListener(); DebuggerManager.getDebuggerManager().addDebuggerListener( WeakListeners.create(DebuggerManagerListener.class, engineListener, @@ -151,7 +183,7 @@ public class CPPLiteBreakpoint extends Breakpoint { return null; } if (engines.length == 1) { - if (isAntEngine(engines[0])) { + if (isCPPEngine(engines[0])) { return engines; } else { return null; @@ -160,9 +192,9 @@ public class CPPLiteBreakpoint extends Breakpoint { // Several running sessions List<DebuggerEngine> antEngines = null; for (DebuggerEngine e : engines) { - if (isAntEngine(e)) { + if (isCPPEngine(e)) { if (antEngines == null) { - antEngines = new ArrayList<DebuggerEngine>(); + antEngines = new ArrayList<>(); } antEngines.add(e); } @@ -170,11 +202,11 @@ public class CPPLiteBreakpoint extends Breakpoint { if (antEngines == null) { return null; } else { - return antEngines.toArray(new DebuggerEngine[]{}); + return antEngines.toArray(new DebuggerEngine[antEngines.size()]); } } - private boolean isAntEngine(DebuggerEngine e) { + private boolean isCPPEngine(DebuggerEngine e) { return e.lookupFirst(null, CPPLiteDebugger.class) != null; } @@ -183,19 +215,19 @@ public class CPPLiteBreakpoint extends Breakpoint { return false; } - private final class AntEngineListener extends DebuggerManagerAdapter { + private final class CPPEngineListener extends DebuggerManagerAdapter { @Override public void engineAdded(DebuggerEngine engine) { - if (isAntEngine(engine)) { - firePropertyChange(PROP_GROUP_PROPERTIES, null, AntGroupProperties.this); + if (isCPPEngine(engine)) { + firePropertyChange(PROP_GROUP_PROPERTIES, null, CPPGroupProperties.this); } } @Override public void engineRemoved(DebuggerEngine engine) { - if (isAntEngine(engine)) { - firePropertyChange(PROP_GROUP_PROPERTIES, null, AntGroupProperties.this); + if (isCPPEngine(engine)) { + firePropertyChange(PROP_GROUP_PROPERTIES, null, CPPGroupProperties.this); } } diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java index 8ef0cc8..c166e25 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java @@ -25,11 +25,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; + import org.netbeans.api.debugger.ActionsManager; import org.netbeans.api.debugger.Breakpoint; import org.netbeans.api.debugger.DebuggerManager; import org.netbeans.spi.debugger.ActionsProvider.Registration; -import org.netbeans.spi.debugger.ActionsProvider.Registrations; import org.netbeans.spi.debugger.ActionsProviderSupport; import org.netbeans.spi.debugger.ui.EditorContextDispatcher; import org.openide.filesystems.FileObject; @@ -43,16 +43,16 @@ import org.openide.util.WeakListeners; @Registration(actions={"toggleBreakpoint"}, activateForMIMETypes={"text/X-c", "text/X-c++", "text/X-h", "text/X-h++"}) public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport implements PropertyChangeListener { - + private static final String[] C_MIME_TYPES = new String[] {"text/X-c", "text/X-c++", "text/X-h", "text/X-h++"}; // NOI18N private static final Set<String> C_MIME_TYPES_SET = new HashSet<>(Arrays.asList(C_MIME_TYPES)); - - private static final Set actions = Collections.singleton ( + + private static final Set ACTIONS = Collections.singleton ( ActionsManager.ACTION_TOGGLE_BREAKPOINT ); - + EditorContextDispatcher context = EditorContextDispatcher.getDefault(); - + public CPPLiteBreakpointActionProvider () { for (String mimeType : C_MIME_TYPES) { context.addPropertyChangeListener(mimeType, @@ -60,7 +60,7 @@ public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport } setEnabled (ActionsManager.ACTION_TOGGLE_BREAKPOINT, false); } - + /** * Called when the action is called (action button is pressed). * @@ -87,7 +87,7 @@ public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport ); //S ystem.out.println("toggle"); } - + /** * Returns set of actions supported by this ActionsProvider. * @@ -95,10 +95,9 @@ public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport */ @Override public Set getActions () { - return actions; + return ACTIONS; } - - + private static Line getCurrentLine () { FileObject fo = EditorContextDispatcher.getDefault().getCurrentFile(); //System.out.println("n = "+n+", FO = "+fo+" => is ANT = "+isAntFile(fo)); @@ -107,8 +106,7 @@ public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport } return EditorContextDispatcher.getDefault().getCurrentLine(); } - - + private static boolean isCFile(FileObject fo) { if (fo == null) { return false; @@ -116,12 +114,12 @@ public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport return C_MIME_TYPES_SET.contains(fo.getMIMEType()); } } - + @Override public void propertyChange(PropertyChangeEvent evt) { // We need to push the state there :-(( instead of wait for someone to be interested in... boolean enabled = getCurrentLine() != null; setEnabled (ActionsManager.ACTION_TOGGLE_BREAKPOINT, enabled); } - + } diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/LoadBreakpoints.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/LoadBreakpoints.java deleted file mode 100644 index 78cde77..0000000 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/LoadBreakpoints.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.netbeans.modules.cpplite.debugger.breakpoints; - -import org.netbeans.api.debugger.DebuggerManager; -import org.openide.modules.OnStart; -import org.openide.windows.WindowManager; - -/** - * - * @author lahvac - */ -@OnStart -public class LoadBreakpoints implements Runnable { - - @Override - public void run() { - //to load and assign breakpoints - //XXX: there must be a better/cleaner way, right? - WindowManager.getDefault().invokeWhenUIReady(() -> - DebuggerManager.getDebuggerManager ().getBreakpoints () - ); - } - -} diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java index c296967..d467600 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java @@ -30,6 +30,7 @@ import org.netbeans.api.debugger.LazyDebuggerManagerListener; import org.netbeans.api.debugger.Properties; import org.netbeans.api.debugger.Session; import org.netbeans.api.debugger.Watch; +import org.netbeans.spi.debugger.DebuggerServiceRegistration; /** * Listens on DebuggerManager and: @@ -39,6 +40,7 @@ import org.netbeans.api.debugger.Watch; * * @author Jan Jancura */ +@DebuggerServiceRegistration(types={LazyDebuggerManagerListener.class}) public class PersistenceManager implements LazyDebuggerManagerListener { @Override diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingViewSupportImpl.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingViewSupportImpl.java index d657e09..b0e30d7 100644 --- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingViewSupportImpl.java +++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingViewSupportImpl.java @@ -85,7 +85,7 @@ public class DebuggingViewSupportImpl extends DebuggingView.DVSupport implements @Override public void resume() { - debugger.doAction(ActionsManager.ACTION_CONTINUE); + session.getCurrentEngine().getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); } @Override diff --git a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java new file mode 100644 index 0000000..2d9d4bd --- /dev/null +++ b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.cpplite.debugger; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import junit.framework.Test; + +import org.netbeans.api.debugger.DebuggerEngine; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.junit.NbTestCase; + +public abstract class AbstractDebugTest extends NbTestCase { + + protected DebuggerEngine engine; + protected CPPLiteDebugger debugger; + + private final int[] suspendCount = new int[]{0}; + private final int[] resumeCount = new int[]{0}; + + protected AbstractDebugTest(String s) { + super(s); + } + + protected final static void compileC(String name, File wd) throws IOException, InterruptedException { + Process compile = new ProcessBuilder("gcc", "-o", name, "-g", name + ".c").directory(wd).start(); + assertEquals(0, compile.waitFor()); + } + + protected final static void compileCPP(String name, File wd) throws IOException, InterruptedException { + Process compile = new ProcessBuilder("g++", "-o", name, "-g", name + ".cpp").directory(wd).start(); + assertEquals(0, compile.waitFor()); + } + + protected final void startDebugging(String name, File wd) throws IOException { + engine = CPPLiteDebugger.startDebugging(new CPPLiteDebuggerConfig(Arrays.asList(new File(wd, name).getAbsolutePath()), wd)).first(); + debugger = engine.lookupFirst(null, CPPLiteDebugger.class); + debugger.addStateListener(new CPPLiteDebugger.StateListener() { + @Override + public void suspended(boolean suspended) { + int[] count; + if (suspended) { + count = suspendCount; + } else { + count = resumeCount; + } + synchronized (count) { + count[0]++; + count.notifyAll(); + } + } + + @Override + public void finished() { + } + + @Override + public void currentThread(CPPThread thread) { + } + + @Override + public void currentFrame(CPPFrame frame) { + } + }); + } + + protected final void waitSuspended(int count) throws InterruptedException { + synchronized (suspendCount) { + while (suspendCount[0] < count) { + suspendCount.wait(); + } + } + } + + protected final void waitResumed(int count) throws InterruptedException { + synchronized (resumeCount) { + while (resumeCount[0] < count) { + resumeCount.wait(); + } + } + } + + protected final void assertStoppedAt(URI file, int line) { + CPPFrame currentFrame = debugger.getCurrentFrame(); + assertNotNull(currentFrame); + assertEquals(file, currentFrame.getSourceURI()); + assertEquals(line, currentFrame.getLine()); + } + + public static Test suite() { + return NbModuleSuite.emptyConfiguration().gui(false).suite(); + } +} diff --git a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java new file mode 100644 index 0000000..f80bee8 --- /dev/null +++ b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.cpplite.debugger; + +import java.io.File; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import junit.framework.Test; + +import org.netbeans.api.debugger.ActionsManager; +import org.netbeans.api.debugger.DebuggerManager; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint; +import org.openide.cookies.LineCookie; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; + +/** + * Tests C/C++ debugger breakpoints. + */ +public class BreakpointsTest extends AbstractDebugTest { + + public BreakpointsTest (String s) { + super (s); + } + + @Override + protected void setUp() throws Exception { + clearWorkDir(); + } + + public void testBreakpoints() throws Exception { + File wd = getWorkDir(); + FileObject source = FileUtil.createData(FileUtil.toFileObject(wd), "breakpoints.c"); + try (OutputStream os = source.getOutputStream(); + Writer w = new OutputStreamWriter(os)) { + w.append("#include<stdio.h>\n" + + "\n" + + "long double loop(unsigned int N) {\n" + + " unsigned int i;\n" + + " long double f = 1;\n" + + " long double s = 0;\n" + + " for (i = 1; i <= N; i++) {\n" + + " f *= i;\n" + + " s += i;\n" + + " f /= s/i;\n" + + " }\n" + + " return f;\n" + + "}\n" + + "\n" + + "int main(int argc, char** args) {\n" + + " int N = 100;\n" + + " long double r = loop(N);\n" + + " printf(\"Result(%d) = %.40Lg\\n\", N, r);\n" + + "}"); + } + compileC("breakpoints", wd); + LineCookie lc = DataObject.find(source).getLookup().lookup(LineCookie.class); + assertNotNull(lc); + CPPLiteBreakpoint bp8 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(7)); + CPPLiteBreakpoint bp9 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(8)); + bp9.disable(); + DebuggerManager.getDebuggerManager().addBreakpoint(bp8); + DebuggerManager.getDebuggerManager().addBreakpoint(bp9); + startDebugging("breakpoints", wd); + + waitSuspended(1); + assertStoppedAt(source.toURI(), 8); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(1); + waitSuspended(2); + assertStoppedAt(source.toURI(), 8); + + bp9.enable(); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(2); + waitSuspended(3); + assertStoppedAt(source.toURI(), 9); + + CPPLiteBreakpoint bp10 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(9)); + DebuggerManager.getDebuggerManager().addBreakpoint(bp10); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(3); + waitSuspended(4); + assertStoppedAt(source.toURI(), 10); + + DebuggerManager.getDebuggerManager().removeBreakpoint(bp8); + DebuggerManager.getDebuggerManager().removeBreakpoint(bp9); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(4); + waitSuspended(5); + assertStoppedAt(source.toURI(), 10); + + bp10.disable(); + + bp8 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(7)); + DebuggerManager.getDebuggerManager().addBreakpoint(bp8); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(5); + waitSuspended(6); + assertStoppedAt(source.toURI(), 8); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(5); + waitSuspended(6); + assertStoppedAt(source.toURI(), 8); + + bp8.disable(); + + engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE); + waitResumed(6); + + engine.getActionsManager().doAction(ActionsManager.ACTION_KILL); + } + + public static Test suite() { + return NbModuleSuite.emptyConfiguration() + .addTest(BreakpointsTest.class) + .enableModules(".*", ".*") + .gui(false) + .suite(); + } +} diff --git a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java index 0361a20..a2042dd 100644 --- a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java +++ b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java @@ -23,12 +23,11 @@ import java.io.File; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; -import java.util.Arrays; import junit.framework.Test; + import org.netbeans.api.debugger.ActionsManager; import org.netbeans.api.debugger.DebuggerManager; import org.netbeans.junit.NbModuleSuite; -import org.netbeans.junit.NbTestCase; import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint; import org.openide.cookies.LineCookie; import org.openide.filesystems.FileObject; @@ -40,7 +39,7 @@ import org.openide.loaders.DataObject; * * @author Jan Jancura */ -public class StepTest extends NbTestCase { +public class StepTest extends AbstractDebugTest { public StepTest (String s) { super (s); @@ -55,7 +54,7 @@ public class StepTest extends NbTestCase { File wd = getWorkDir(); FileObject source = FileUtil.createData(FileUtil.toFileObject(wd), "main.cpp"); try (OutputStream os = source.getOutputStream(); - Writer w = new OutputStreamWriter(os)) { + Writer w = new OutputStreamWriter(os)) { w.append("#include <iostream>\n" + "\n" + "void test(void) {\n" + @@ -70,69 +69,25 @@ public class StepTest extends NbTestCase { " std::cout << \"Hello, second time!\" << std::endl;\n" + "}"); } - Process compile = new ProcessBuilder("g++", "-o", "main", "-g", "main.cpp").directory(wd).start(); - assertEquals(0, compile.waitFor()); + compileCPP("main", wd); LineCookie lc = DataObject.find(source).getLookup().lookup(LineCookie.class); assertNotNull(lc); DebuggerManager.getDebuggerManager().addBreakpoint(new CPPLiteBreakpoint(lc.getLineSet().getCurrent(4))); - CPPLiteDebugger d = CPPLiteDebugger.startDebugging(new CPPLiteDebuggerConfig(Arrays.asList(new File(wd, "main").getAbsolutePath()), wd)).first(); - int[] suspendCount = new int[1]; - int[] resumeCount = new int[1]; - d.addStateListener(new CPPLiteDebugger.StateListener() { - @Override - public void suspended(boolean suspended) { - int[] count; - if (suspended) { - count = suspendCount; - } else { - count = resumeCount; - } - synchronized (count) { - count[0]++; - count.notifyAll(); - } - } - - @Override - public void finished() { - } - - @Override - public void currentThread(CPPThread thread) { - } + startDebugging("main", wd); - @Override - public void currentFrame(CPPFrame frame) { - } - }); + waitSuspended(1); - synchronized (suspendCount) { - while (suspendCount[0] < 1) { - suspendCount.wait(); - } - } + assertStoppedAt(source.toURI(), 5); - //on line 4, there is a breakpoint and the PC - assertEquals(2, lc.getLineSet().getCurrent(4).getAnnotationCount()); + engine.getActionsManager().doAction(ActionsManager.ACTION_STEP_OVER); - d.doAction(ActionsManager.ACTION_STEP_OVER); + waitResumed(1); - synchronized (resumeCount) { - while (resumeCount[0] < 1) { - resumeCount.wait(); - } - } + waitSuspended(2); - synchronized (suspendCount) { - while (suspendCount[0] < 2) { - suspendCount.wait(); - } - } + assertStoppedAt(source.toURI(), 6); - //on line 4, there is a breakpoint - assertEquals(1, lc.getLineSet().getCurrent(4).getAnnotationCount()); - //PC: - assertEquals(1, lc.getLineSet().getCurrent(5).getAnnotationCount()); + engine.getActionsManager().doAction(ActionsManager.ACTION_KILL); } public static Test suite() { diff --git a/ide/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java b/ide/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java index f35418a..3602993 100644 --- a/ide/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java +++ b/ide/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java @@ -195,7 +195,7 @@ public abstract class Breakpoint { /** * Get group properties of the breakpoint. - * These are implementation-defined group properties as oposed to {@link #getGroupName()}, + * These are implementation-defined group properties as opposed to {@link #getGroupName()}, * which returns user-defined group name. * <p> * These properties are used by the Breakpoint Window to show a tree --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists