You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by sk...@apache.org on 2022/05/05 08:59:27 UTC
[netbeans] branch delivery updated: Smart stepping implemented for Groovy. SmartSteppingFilterWrapper introduced as a step-specific filter.
This is an automated email from the ASF dual-hosted git repository.
skygo 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 d1de9d57a2 Smart stepping implemented for Groovy. SmartSteppingFilterWrapper introduced as a step-specific filter.
new 35437b17bc Merge pull request #4073 from ebarboni/deliverymissingpr2
d1de9d57a2 is described below
commit d1de9d57a28323cf8747adb5d9fb99ce98120de0
Author: Martin Entlicher <ma...@oracle.com>
AuthorDate: Wed May 4 18:36:01 2022 +0200
Smart stepping implemented for Groovy. SmartSteppingFilterWrapper introduced as a step-specific filter.
---
.../groovy/support/debug/GroovySmartStepping.java | 105 +++++++++++++++++++++
.../spi/debugger/jpda/SmartSteppingCallback.java | 13 ++-
.../debugger/jpda/ui/SmartSteppingImpl.java | 12 +--
.../ui/actions/JPDAMethodChooserFactoryUIImpl.java | 6 ++
.../modules/debugger/jpda/JPDADebuggerImpl.java | 11 +--
.../modules/debugger/jpda/JPDAStepImpl.java | 36 ++-----
.../jpda/actions/SmartSteppingFilterImpl.java | 47 +--------
.../jpda/actions/SmartSteppingFilterWrapper.java | 87 +++++++++++++++++
.../debugger/jpda/actions/StepActionProvider.java | 49 +++++++---
.../debugger/jpda/actions/StepIntoNextMethod.java | 41 ++++----
10 files changed, 287 insertions(+), 120 deletions(-)
diff --git a/groovy/groovy.support/src/org/netbeans/modules/groovy/support/debug/GroovySmartStepping.java b/groovy/groovy.support/src/org/netbeans/modules/groovy/support/debug/GroovySmartStepping.java
new file mode 100644
index 0000000000..946a74f786
--- /dev/null
+++ b/groovy/groovy.support/src/org/netbeans/modules/groovy/support/debug/GroovySmartStepping.java
@@ -0,0 +1,105 @@
+/*
+ * 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.groovy.support.debug;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import org.netbeans.api.debugger.jpda.CallStackFrame;
+import org.netbeans.api.debugger.jpda.JPDAStep;
+import org.netbeans.api.debugger.jpda.JPDAThread;
+import org.netbeans.api.debugger.jpda.SmartSteppingFilter;
+import org.netbeans.spi.debugger.ContextProvider;
+import org.netbeans.spi.debugger.jpda.SmartSteppingCallback;
+
+/**
+ * Stepping in Groovy, steps through the language implementation.
+ */
+@SmartSteppingCallback.Registration(path="netbeans-JPDASession")
+public class GroovySmartStepping extends SmartSteppingCallback {
+
+ private static final String[] GROOVY_PACKAGES = { "org.codehaus.groovy.", "org.apache.groovy.", "groovy.", "groovyjar" }; // NOI18N
+ private static final Set<String> PATTERNS_SKIP_IN_GROOVY = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("java.", "jdk.internal.", "sun.", "com.sun."))); // NOI18N
+ private static final Set<String> FILTERS_SKIP_IN_GROOVY = PATTERNS_SKIP_IN_GROOVY.stream().map(pattern -> pattern + '*').collect(Collectors.toSet());
+
+ private static final Logger logger = Logger.getLogger(GroovySmartStepping.class.getName());
+
+ private final Map<SmartSteppingFilter, Boolean> steppingInGroovy = Collections.synchronizedMap(new WeakHashMap<>());
+
+ @Override
+ public void initFilter (SmartSteppingFilter filter) {
+ }
+
+ @Override
+ public boolean stopHere (ContextProvider lookupProvider, JPDAThread thread, SmartSteppingFilter filter) {
+ return true;
+ }
+
+ @Override
+ public StopOrStep stopAt(ContextProvider lookupProvider, CallStackFrame frame, SmartSteppingFilter filter) {
+ String className = frame.getClassName();
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("GroovySmartStepping.stopAt("+className+")");
+ }
+ JPDAThread thread = frame.getThread();
+ boolean inGroovy = false;
+ for (String gp : GROOVY_PACKAGES) {
+ if (className.startsWith(gp)) {
+ inGroovy = true;
+ steppingInGroovy.put(filter, true);
+ break;
+ }
+ }
+ if (inGroovy) {
+ // We need to step through the Groovy packages
+ logger.fine(" => In Groovy: Step In");
+ return StopOrStep.step(0, JPDAStep.STEP_INTO);
+ }
+ if (Boolean.TRUE.equals(steppingInGroovy.get(filter))) {
+ if (isPackageToSkip(className)) {
+ logger.fine(" => Was In Groovy: Step In");
+ filter.addExclusionPatterns(FILTERS_SKIP_IN_GROOVY);
+ return StopOrStep.step(0, JPDAStep.STEP_INTO);
+ } else {
+ logger.fine(" => FINISHED, stop");
+ return StopOrStep.stop();
+ }
+ } else {
+ logger.fine(" => FINISHED (no Groovy), stop");
+ return StopOrStep.stop();
+ }
+ }
+
+ private static boolean isPackageToSkip(String className) {
+ for (String pattern : PATTERNS_SKIP_IN_GROOVY) {
+ if (className.startsWith(pattern)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/java/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/SmartSteppingCallback.java b/java/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/SmartSteppingCallback.java
index b9f831e9ec..e905d02b27 100644
--- a/java/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/SmartSteppingCallback.java
+++ b/java/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/SmartSteppingCallback.java
@@ -26,6 +26,7 @@ import java.lang.annotation.Target;
import java.util.Map;
import java.util.Objects;
import org.netbeans.api.debugger.jpda.CallStackFrame;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.JPDAStep;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.api.debugger.jpda.SmartSteppingFilter;
@@ -55,10 +56,14 @@ public abstract class SmartSteppingCallback {
* This method is called during stepping through debugged application.
* The execution is stopped when all registered <code>SmartSteppingCallback</code>s
* returns true.
+ * <p>
+ * The {@link SmartSteppingFilter} instance is unique per step. Any changes to it applies
+ * to one ongoing step only. Use {@link JPDADebugger#getSmartSteppingFilter()} to make
+ * persistent changes.
*
* @param thread contains all available information about current position
* in debugged application
- * @param f a filter
+ * @param f a filter, unique to the ongoing step
* @return true if execution should be stopped on the current position
*/
public abstract boolean stopHere (ContextProvider lookupProvider, JPDAThread thread, SmartSteppingFilter f);
@@ -70,13 +75,17 @@ public abstract class SmartSteppingCallback {
* to check if the execution could be suspended there. This is valuable e.g. for step out.
* When a top frame is provided, this method can suggest a specific step to continue with,
* in case it's not possible to stop at the given location.
+ * <p>
+ * The {@link SmartSteppingFilter} instance is unique per step. Any changes to it applies
+ * to one ongoing step only. Register a {@link SmartSteppingFilter} implementation
+ * to make persistent changes.
*
* The default implementation calls {@link #stopHere(org.netbeans.spi.debugger.ContextProvider, org.netbeans.api.debugger.jpda.JPDAThread, org.netbeans.api.debugger.jpda.SmartSteppingFilter)}
* when called with a top frame and throws an {@link UnsupportedOperationException} otherwise.
*
* @param lookupProvider The debugger services lookup
* @param frame The frame in question
- * @param f a filter
+ * @param f a filter, unique to the ongoing step
* @return whether the debugger can stop at this location, or whether it should continue with a step.
* @since 3.5
*/
diff --git a/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/SmartSteppingImpl.java b/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/SmartSteppingImpl.java
index e25fcb12ae..8c0f6f7e96 100644
--- a/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/SmartSteppingImpl.java
+++ b/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/SmartSteppingImpl.java
@@ -153,15 +153,15 @@ PropertyChangeListener {
HashSet s = new HashSet ();
s.add (name.replace ('/', '.') + ".*");
- addExclusionPatterns (s);
+ addExclusionPatterns (s, f);
return false;
}
- private void addExclusionPatterns (
- Set ep
- ) {
- smartSteppingFilter.addExclusionPatterns (ep);
- exclusionPatterns.addAll (ep);
+ private void addExclusionPatterns(Set ep, SmartSteppingFilter f) {
+ f.addExclusionPatterns (ep);
+ if (f == smartSteppingFilter) {
+ exclusionPatterns.addAll (ep);
+ }
}
private void removeExclusionPatterns () {
diff --git a/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/JPDAMethodChooserFactoryUIImpl.java b/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/JPDAMethodChooserFactoryUIImpl.java
index d2ebe98798..451c6836ab 100644
--- a/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/JPDAMethodChooserFactoryUIImpl.java
+++ b/java/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/JPDAMethodChooserFactoryUIImpl.java
@@ -20,6 +20,8 @@
package org.netbeans.modules.debugger.jpda.ui.actions;
import com.sun.jdi.ReferenceType;
+import java.awt.GraphicsEnvironment;
+import javax.swing.SwingUtilities;
import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
import org.netbeans.modules.debugger.jpda.actions.JPDAMethodChooserFactory;
import org.netbeans.modules.debugger.jpda.actions.StepIntoActionProvider;
@@ -38,6 +40,10 @@ public class JPDAMethodChooserFactoryUIImpl implements JPDAMethodChooserFactory
@Override
public boolean initChooserUI(JPDADebuggerImpl debugger, String url, ReferenceType clazz, int methodLine) {
+ if (GraphicsEnvironment.isHeadless()) {
+ // Not supported in headless environment
+ return false;
+ }
final MethodChooserSupport cSupport = new MethodChooserSupport(debugger, url, clazz, methodLine);
boolean continuedDirectly = cSupport.init();
if (cSupport.getSegmentsCount() == 0) {
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
index b3c3073977..16db46b46d 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
@@ -615,7 +615,7 @@ public class JPDADebuggerImpl extends JPDADebugger {
/**
* Test whether we should stop here according to the smart-stepping rules.
*/
- StopOrStep stopHere(JPDAThread t) {
+ StopOrStep stopHere(JPDAThread t, SmartSteppingFilter filter) {
CallStackFrame topFrame = null;
try {
CallStackFrame[] topFrameArr = t.getCallStack(0, 1);
@@ -624,12 +624,11 @@ public class JPDADebuggerImpl extends JPDADebugger {
}
} catch (AbsentInformationException aiex) {}
if (topFrame != null) {
- return getCompoundSmartSteppingListener().stopAt
- (lookupProvider, topFrame, getSmartSteppingFilter());
+ return getCompoundSmartSteppingListener().stopAt(lookupProvider, topFrame, filter);
} else {
- return getCompoundSmartSteppingListener().stopHere
- (lookupProvider, t, getSmartSteppingFilter()) ?
- StopOrStep.stop() : StopOrStep.skip();
+ return getCompoundSmartSteppingListener().stopHere(lookupProvider, t, filter) ?
+ StopOrStep.stop() :
+ StopOrStep.skip();
}
}
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java
index 2a3706fd16..e4bc7f25b0 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java
@@ -55,12 +55,11 @@ import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.JPDAStep;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.api.debugger.jpda.MethodBreakpoint;
-import org.netbeans.api.debugger.jpda.SmartSteppingFilter;
import org.netbeans.api.debugger.jpda.Variable;
import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent;
import org.netbeans.api.debugger.jpda.event.JPDABreakpointListener;
-import org.netbeans.modules.debugger.jpda.actions.CompoundSmartSteppingListener;
-import org.netbeans.modules.debugger.jpda.actions.SmartSteppingFilterImpl;
+import org.netbeans.modules.debugger.jpda.actions.SmartSteppingFilterWrapper;
+import org.netbeans.modules.debugger.jpda.actions.StepActionProvider;
import org.netbeans.modules.debugger.jpda.actions.StepIntoActionProvider;
import org.netbeans.modules.debugger.jpda.impl.StepUtils;
import org.netbeans.modules.debugger.jpda.jdi.ClassNotPreparedExceptionWrapper;
@@ -119,12 +118,14 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
private boolean wasInBoxingUnboxingLocation;
private StopHereCheck stopHereCheck;
private final Properties p;
+ private final SmartSteppingFilterWrapper smartSteppingFilter;
private final Session session;
public JPDAStepImpl(JPDADebugger debugger, Session session, int size, int depth) {
super(debugger, size, depth);
this.session = session;
+ this.smartSteppingFilter = new SmartSteppingFilterWrapper(debugger.getSmartSteppingFilter());
p = Properties.getDefault().getProperties("debugger.options.JPDA"); // NOI18N
}
@@ -134,7 +135,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
if (ignoreStepFilters || steppingFromFilteredLocation) {
exclusionPatterns = stepFilters;
} else {
- exclusionPatterns = debugger.getSmartSteppingFilter().getExclusionPatterns();
+ exclusionPatterns = smartSteppingFilter.getExclusionPatterns();
if (stepFilters != null) {
int epl = exclusionPatterns.length;
exclusionPatterns = Arrays.copyOf(exclusionPatterns, epl + stepFilters.length);
@@ -153,7 +154,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
}
private String[] getCurrentExclusionPatterns() {
- String[] exclusionPatterns = debugger.getSmartSteppingFilter().getExclusionPatterns();
+ String[] exclusionPatterns = smartSteppingFilter.getExclusionPatterns();
String[] stepFilters = getSteppingFilters();
if (stepFilters != null) {
int epl = exclusionPatterns.length;
@@ -200,8 +201,8 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
//SingleThreadedStepWatch.stepRequestDeleted(stepRequest);
debuggerImpl.getOperator().unregister(stepRequest);
}
- steppingFromFilteredLocation = !((SmartSteppingFilterImpl) debuggerImpl.getSmartSteppingFilter()).stopHere(tr.getClassName());
- steppingFromCompoundFilteredLocation = !debuggerImpl.stopHere(tr).isStop();
+ steppingFromFilteredLocation = !StepActionProvider.stopInClass(tr.getClassName(), smartSteppingFilter);
+ steppingFromCompoundFilteredLocation = !debuggerImpl.stopHere(tr, smartSteppingFilter).isStop();
int size = getSize();
boolean stepAdded = false;
if (logger.isLoggable(Level.FINE)) {
@@ -903,7 +904,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
if (steppingFromCompoundFilteredLocation) {
stop = StopOrStep.stop();
} else {
- stop = debuggerImpl.stopHere(t);
+ stop = debuggerImpl.stopHere(t, smartSteppingFilter);
}
if (stop.isStop() && !steppingFromFilteredLocation) {
String[] exclusionPatterns = getCurrentExclusionPatterns();
@@ -976,7 +977,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
}
// Not synthetic
- StopOrStep stop = debuggerImpl.stopHere(t);
+ StopOrStep stop = debuggerImpl.stopHere(t, smartSteppingFilter);
if (stop.isStop()) {
//S ystem.out.println("/nStepAction.exec end - do not resume");
return false; // do not resume
@@ -1124,23 +1125,6 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
return topFrame;
}
- private SmartSteppingFilterImpl smartSteppingFilter;
-
- private SmartSteppingFilterImpl getSmartSteppingFilterImpl () {
- if (smartSteppingFilter == null) {
- smartSteppingFilter = (SmartSteppingFilterImpl) session.lookupFirst(null, SmartSteppingFilter.class);
- }
- return smartSteppingFilter;
- }
-
- private CompoundSmartSteppingListener compoundSmartSteppingListener;
-
- private CompoundSmartSteppingListener getCompoundSmartSteppingListener () {
- if (compoundSmartSteppingListener == null)
- compoundSmartSteppingListener = session.lookupFirst(null, CompoundSmartSteppingListener.class);
- return compoundSmartSteppingListener;
- }
-
public void setIgnoreStepFilters(boolean ignoreStepFilters) {
this.ignoreStepFilters = ignoreStepFilters;
}
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterImpl.java
index 276f483423..cf2b4078a9 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterImpl.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterImpl.java
@@ -21,10 +21,8 @@ package org.netbeans.modules.debugger.jpda.actions;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
import org.netbeans.api.debugger.Properties;
import org.netbeans.api.debugger.jpda.SmartSteppingFilter;
@@ -40,9 +38,6 @@ import org.openide.util.WeakListeners;
public class SmartSteppingFilterImpl implements SmartSteppingFilter {
private final HashSet<String> filter = new HashSet<String>();
- private final ArrayList<String> exact = new ArrayList<String>();
- private final ArrayList<String> start = new ArrayList<String>();
- private final ArrayList<String> end = new ArrayList<String>();
private final PropertyChangeSupport pcs;
{pcs = new PropertyChangeSupport (this);}
private final Properties options = Properties.getDefault().
@@ -76,11 +71,7 @@ public class SmartSteppingFilterImpl implements SmartSteppingFilter {
}
synchronized (filter) {
filter.clear();
- exact.clear();
- start.clear();
- end.clear();
filter.addAll (patterns);
- refreshFilters (patterns);
}
pcs.firePropertyChange (PROP_EXCLUSION_PATTERNS, null, patterns);
}
@@ -102,7 +93,6 @@ public class SmartSteppingFilterImpl implements SmartSteppingFilter {
synchronized (filter) {
filter.addAll (reallyNew);
- refreshFilters (reallyNew);
}
pcs.firePropertyChange (PROP_EXCLUSION_PATTERNS, null, reallyNew);
@@ -117,10 +107,6 @@ public class SmartSteppingFilterImpl implements SmartSteppingFilter {
public void removeExclusionPatterns (Set<String> patterns) {
synchronized (filter) {
filter.removeAll (patterns);
- exact.clear();
- start.clear();
- end.clear();
- refreshFilters (filter);
}
pcs.firePropertyChange (PROP_EXCLUSION_PATTERNS, patterns, null);
@@ -138,21 +124,8 @@ public class SmartSteppingFilterImpl implements SmartSteppingFilter {
}
public boolean stopHere (String className) {
- synchronized (filter) {
- int i, k = exact.size ();
- for (i = 0; i < k; i++) {
- if (exact.get (i).equals (className)) return false;
- }
- k = start.size ();
- for (i = 0; i < k; i++) {
- if (className.startsWith (start.get (i))) return false;
- }
- k = end.size ();
- for (i = 0; i < k; i++) {
- if (className.endsWith (end.get (i))) return false;
- }
- }
- return true;
+ // Retained for compatibility
+ return StepActionProvider.stopInClass(className, this);
}
/**
@@ -177,20 +150,4 @@ public class SmartSteppingFilterImpl implements SmartSteppingFilter {
pcs.removePropertyChangeListener (l);
}
- /**
- * Updates exact, start and end filter lists.
- */
- private void refreshFilters (Set<String> newFilters) {
- Iterator<String> i = newFilters.iterator ();
- while (i.hasNext ()) {
- String p = i.next ();
- if (p.startsWith ("*"))
- end.add (p.substring (1));
- else
- if (p.endsWith ("*"))
- start.add (p.substring (0, p.length () - 1));
- else
- exact.add (p);
- }
- }
}
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterWrapper.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterWrapper.java
new file mode 100644
index 0000000000..0cd704d28f
--- /dev/null
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/SmartSteppingFilterWrapper.java
@@ -0,0 +1,87 @@
+/*
+ * 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.debugger.jpda.actions;
+
+import java.beans.PropertyChangeListener;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.api.debugger.jpda.SmartSteppingFilter;
+
+/**
+ * A wrapper over {@link JPDADebugger#getSmartSteppingFilter()}. A new instance
+ * of this class is created for every step to store step's specific patterns.
+ */
+public final class SmartSteppingFilterWrapper implements SmartSteppingFilter {
+
+ private final SmartSteppingFilter delegate;
+ private Set<String> addedPatterns;
+ private Set<String> removedPatterns;
+
+ public SmartSteppingFilterWrapper(SmartSteppingFilter delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public synchronized void addExclusionPatterns(Set<String> patterns) {
+ if (addedPatterns == null) {
+ addedPatterns = new LinkedHashSet<>();
+ }
+ addedPatterns.addAll(patterns);
+ }
+
+ @Override
+ public synchronized void removeExclusionPatterns(Set<String> patterns) {
+ if (removedPatterns == null) {
+ removedPatterns = new LinkedHashSet<>();
+ }
+ removedPatterns.addAll(patterns);
+ }
+
+ @Override
+ public String[] getExclusionPatterns() {
+ String[] patterns = delegate.getExclusionPatterns();
+ synchronized (this) {
+ if (addedPatterns == null && removedPatterns == null) {
+ return patterns;
+ }
+ Set<String> newPatterns = new LinkedHashSet<>(Arrays.asList(patterns));
+ if (removedPatterns != null) {
+ newPatterns.removeAll(removedPatterns);
+ }
+ if (addedPatterns != null) {
+ newPatterns.addAll(addedPatterns);
+ }
+ return newPatterns.toArray(new String[newPatterns.size()]);
+ }
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ // No listening on the temporary wrapper
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ // No listening on the temporary wrapper
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
index 6cff450a5e..05602aff90 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
@@ -168,7 +168,32 @@ implements Executor {
}
});
}
-
+
+ /**
+ * Returns whether we can stop in the class based on the smart stepping filter.
+ */
+ public static boolean stopInClass(String className, SmartSteppingFilter filter) {
+ for (String pattern : filter.getExclusionPatterns()) {
+ if (pattern.startsWith ("*")) {
+ String end = pattern.substring(1);
+ if (className.endsWith(end)) {
+ return false;
+ }
+ } else if (pattern.endsWith ("*")) {
+ String start = pattern.substring(0, pattern.length() - 1);
+ if (className.startsWith(start)) {
+ return false;
+ }
+ } else {
+ // exact match
+ if (className.equals(pattern)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
public void runAction(final Object action) {
runAction(getJDIAction(action), StepRequest.STEP_LINE, true, null, null, null);
}
@@ -209,6 +234,7 @@ implements Executor {
}
}
}
+ smartSteppingFilter = new SmartSteppingFilterWrapper(debugger.getSmartSteppingFilter());
resumeThread.waitUntilMethodInvokeDone();
ThreadReference tr = resumeThread.getThreadReference ();
removeStepRequests (tr);
@@ -258,17 +284,17 @@ implements Executor {
if (isSteppingFromFilteredLocation != null) {
steppingFromFilteredLocation = isSteppingFromFilteredLocation;
} else {
- steppingFromFilteredLocation = !getSmartSteppingFilterImpl ().stopHere(className);
+ steppingFromFilteredLocation = !stopInClass(className, smartSteppingFilter);
}
if (isSteppingFromCompoundFilteredLocation != null) {
steppingFromCompoundFilteredLocation = isSteppingFromCompoundFilteredLocation;
} else {
if (topFrame != null) {
steppingFromCompoundFilteredLocation = !getCompoundSmartSteppingListener ().stopAt
- (lookupProvider, topFrame, getSmartSteppingFilterImpl()).isStop();
+ (lookupProvider, topFrame, smartSteppingFilter).isStop();
} else {
steppingFromCompoundFilteredLocation = !getCompoundSmartSteppingListener ().stopHere
- (lookupProvider, resumeThread, getSmartSteppingFilterImpl());
+ (lookupProvider, resumeThread, smartSteppingFilter);
}
}
if (logger.isLoggable(Level.FINE)) {
@@ -449,7 +475,7 @@ implements Executor {
if (steppingFromFilteredLocation) {
fsh = StopOrStep.stop();
} else {
- fsh = getSmartSteppingFilterImpl().stopHere(className) ? StopOrStep.stop() : StopOrStep.skip();
+ fsh = stopInClass(className, smartSteppingFilter) ? StopOrStep.stop() : StopOrStep.skip();
}
if (loggerStep.isLoggable(Level.FINE))
loggerStep.fine("SS SmartSteppingFilter.stopHere (" + className + ") ? " + fsh);
@@ -461,10 +487,10 @@ implements Executor {
CallStackFrame topFrame = getTopFrame(t);
if (topFrame != null) {
fsh = getCompoundSmartSteppingListener ().stopAt
- (lookupProvider, topFrame, getSmartSteppingFilterImpl());
+ (lookupProvider, topFrame, smartSteppingFilter);
} else {
fsh = getCompoundSmartSteppingListener ().stopHere
- (lookupProvider, t, getSmartSteppingFilterImpl()) ? StopOrStep.stop() : StopOrStep.skip();
+ (lookupProvider, t, smartSteppingFilter) ? StopOrStep.stop() : StopOrStep.skip();
}
}
if (fsh.isStop()) {
@@ -741,15 +767,8 @@ implements Executor {
return stepIntoActionProvider;
}
- private SmartSteppingFilterImpl smartSteppingFilterImpl;
+ private SmartSteppingFilterWrapper smartSteppingFilter;
- private SmartSteppingFilterImpl getSmartSteppingFilterImpl () {
- if (smartSteppingFilterImpl == null)
- smartSteppingFilterImpl = (SmartSteppingFilterImpl) lookupProvider.
- lookupFirst (null, SmartSteppingFilter.class);
- return smartSteppingFilterImpl;
- }
-
private CompoundSmartSteppingListener compoundSmartSteppingListener;
private CompoundSmartSteppingListener getCompoundSmartSteppingListener () {
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java
index 4f7ed77f2c..4bdcf8c3cf 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java
@@ -86,20 +86,22 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
private int depth;
private final JPDADebuggerImpl debugger;
private final ContextProvider contextProvider;
- private boolean smartSteppingStepOut;
+ private final boolean smartSteppingStepOut;
private boolean steppingFromFilteredLocation;
private boolean steppingFromCompoundFilteredLocation;
+ private SmartSteppingFilterWrapper smartSteppingFilter;
+ private boolean didStepThrough;
private final Properties p;
public StepIntoNextMethod(ContextProvider contextProvider) {
this.debugger = (JPDADebuggerImpl) contextProvider.lookupFirst(null, JPDADebugger.class);
this.contextProvider = contextProvider;
- getSmartSteppingFilterImpl ().addPropertyChangeListener (this);
+ debugger.getSmartSteppingFilter().addPropertyChangeListener (this);
SourcePath ec = contextProvider.lookupFirst(null, SourcePath.class);
ec.addPropertyChangeListener (this);
Map properties = contextProvider.lookupFirst(null, Map.class);
- if (properties != null)
- smartSteppingStepOut = properties.containsKey (StepIntoActionProvider.SS_STEP_OUT);
+ smartSteppingStepOut = (properties != null) ?
+ properties.containsKey (StepIntoActionProvider.SS_STEP_OUT) : false;
p = Properties.getDefault().getProperties("debugger.options.JPDA"); // NOI18N
}
@@ -125,6 +127,8 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
smartLogger.finer("Can not step into next method! No current thread!");
return ;
}
+ smartSteppingFilter = new SmartSteppingFilterWrapper(debugger.getSmartSteppingFilter());
+ didStepThrough = false;
boolean locked = lock == null;
try {
if (lock == null) {
@@ -152,7 +156,7 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
if (isSteppingFromFilteredLocation != null) {
steppingFromFilteredLocation = isSteppingFromFilteredLocation.booleanValue();
} else {
- steppingFromFilteredLocation = !getSmartSteppingFilterImpl ().stopHere(t.getClassName());
+ steppingFromFilteredLocation = !StepActionProvider.stopInClass(t.getClassName(), smartSteppingFilter);
}
if (isSteppingFromCompoundFilteredLocation != null) {
steppingFromCompoundFilteredLocation = isSteppingFromCompoundFilteredLocation.booleanValue();
@@ -160,10 +164,10 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
CallStackFrame topFrame = getTopFrame(t);
if (topFrame != null) {
steppingFromCompoundFilteredLocation = !getCompoundSmartSteppingListener ().stopAt
- (contextProvider, topFrame, getSmartSteppingFilterImpl()).isStop();
+ (contextProvider, topFrame, smartSteppingFilter).isStop();
} else {
steppingFromCompoundFilteredLocation = !getCompoundSmartSteppingListener ().stopHere
- (contextProvider, t, getSmartSteppingFilterImpl ());
+ (contextProvider, t, smartSteppingFilter);
}
}
@@ -299,7 +303,7 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
boolean useStepFilters = p.getBoolean("UseStepFilters", true);
boolean stepThrough = useStepFilters && p.getBoolean("StepThroughFilters", false)
&& !smartSteppingStepOut;
- if (!stepThrough && isFilteredClassOnStack(tr, depth)) {
+ if (!stepThrough && !didStepThrough && isFilteredClassOnStack(tr, depth)) {
// There's a class that was skipped by step on the stack.
// If step through is false, we should step out from here.
smartLogger.finer(" stoped with a filtered class on stack and step through is false.");
@@ -348,10 +352,10 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
CallStackFrame topFrame = getTopFrame(t);
if (topFrame != null) {
stop = getCompoundSmartSteppingListener().stopAt
- (contextProvider, topFrame, getSmartSteppingFilterImpl());
+ (contextProvider, topFrame, smartSteppingFilter);
} else {
stop = getCompoundSmartSteppingListener().stopHere
- (contextProvider, t, getSmartSteppingFilterImpl()) ? StopOrStep.stop() : StopOrStep.skip();
+ (contextProvider, t, smartSteppingFilter) ? StopOrStep.stop() : StopOrStep.skip();
}
}
if (stop.isStop()) {
@@ -379,11 +383,14 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
stepSize = StepRequest.STEP_LINE;
}
if (stepDepth == 0) {
- if (!stepThrough) {
+ if (!stepThrough || smartSteppingStepOut) {
stepDepth = StepRequest.STEP_OUT;
} else {
stepDepth = StepRequest.STEP_INTO;
}
+ } else if (stepDepth == StepRequest.STEP_INTO) {
+ // We're stepping through in this case
+ didStepThrough = true;
}
StepRequest newSR = setStepRequest(stepDepth);
if (newSR == null) {
@@ -457,6 +464,7 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
synchronized (this) {
if (stepIntoRequest != null) {
try {
+ addPatternsToRequest(smartSteppingFilter.getExclusionPatterns(), stepIntoRequest);
try {
EventRequestWrapper.enable (stepIntoRequest);
enabledStepRequest = stepIntoRequest;
@@ -527,7 +535,7 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
try {
if (!steppingFromFilteredLocation) {
addPatternsToRequest (
- getSmartSteppingFilterImpl ().getExclusionPatterns (),
+ smartSteppingFilter.getExclusionPatterns (),
stepRequest
);
}
@@ -562,13 +570,6 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
return stepRequest;
}
- private SmartSteppingFilterImpl smartSteppingFilter;
-
- private SmartSteppingFilterImpl getSmartSteppingFilterImpl () {
- if (smartSteppingFilter == null)
- smartSteppingFilter = (SmartSteppingFilterImpl) contextProvider.lookupFirst(null, SmartSteppingFilter.class);
- return smartSteppingFilter;
- }
private CompoundSmartSteppingListener compoundSmartSteppingListener;
@@ -596,7 +597,7 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener {
if (steppingFromFilteredLocation) {
return false;
}
- String[] patterns = getSmartSteppingFilterImpl ().getExclusionPatterns();
+ String[] patterns = smartSteppingFilter.getExclusionPatterns();
if (patterns.length == 0) return false;
try {
int n = ThreadReferenceWrapper.frameCount(tr);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists