| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed 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 com.intellij.debugger.ui.breakpoints; |
| |
| import com.intellij.debugger.SourcePosition; |
| import com.intellij.debugger.engine.BreakpointStepMethodFilter; |
| import com.intellij.debugger.engine.CompoundPositionManager; |
| import com.intellij.debugger.engine.DebugProcessImpl; |
| import com.intellij.debugger.engine.LambdaMethodFilter; |
| import com.intellij.debugger.engine.evaluation.EvaluateException; |
| import com.intellij.debugger.engine.requests.RequestManagerImpl; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.project.Project; |
| import com.sun.jdi.*; |
| import com.sun.jdi.request.BreakpointRequest; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.*; |
| |
| /** |
| * @author Eugene Zhuravlev |
| * Date: Sep 13, 2006 |
| */ |
| public class StepIntoBreakpoint extends RunToCursorBreakpoint { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.StepIntoBreakpoint"); |
| @NotNull |
| private final BreakpointStepMethodFilter myFilter; |
| |
| StepIntoBreakpoint(@NotNull Project project, @NotNull SourcePosition pos, @NotNull BreakpointStepMethodFilter filter) { |
| super(project, pos, false); |
| myFilter = filter; |
| } |
| |
| protected void createOrWaitPrepare(DebugProcessImpl debugProcess, SourcePosition classPosition) { |
| super.createOrWaitPrepare(debugProcess, classPosition); |
| } |
| |
| protected void createRequestForPreparedClass(DebugProcessImpl debugProcess, ReferenceType classType) { |
| try { |
| final CompoundPositionManager positionManager = debugProcess.getPositionManager(); |
| final SourcePosition startPosition = getSourcePosition(); |
| List<Location> locations = positionManager.locationsOfLine(classType, startPosition); |
| |
| if (locations.isEmpty()) { |
| // sometimes first statements are mapped to some weird line number, or there are no executable instructions at first statement's line |
| // so if lambda or method body spans for more than one lines, try get some locations from these lines |
| final int lastLine = myFilter.getLastStatementLine(); |
| if (lastLine >= 0) { |
| int nextLine = startPosition.getLine() + 1; |
| while (nextLine <= lastLine && locations.isEmpty()) { |
| locations = positionManager.locationsOfLine(classType, SourcePosition.createFromLine(startPosition.getFile(), nextLine++)); |
| } |
| } |
| } |
| |
| if (!locations.isEmpty()) { |
| final Set<Method> methods = new HashSet<Method>(); |
| for (Location loc : locations) { |
| if (acceptLocation(debugProcess, classType, loc)) { |
| methods.add(loc.method()); |
| } |
| } |
| Location location = null; |
| final int methodsFound = methods.size(); |
| if (methodsFound == 1) { |
| location = methods.iterator().next().location(); |
| } |
| else { |
| if (myFilter instanceof LambdaMethodFilter) { |
| final LambdaMethodFilter lambdaFilter = (LambdaMethodFilter)myFilter; |
| if (lambdaFilter.getLambdaOrdinal() < methodsFound) { |
| final Method[] candidates = methods.toArray(new Method[methodsFound]); |
| Arrays.sort(candidates, new Comparator<Method>() { |
| public int compare(Method m1, Method m2) { |
| return getMethodOrdinal(m1) - getMethodOrdinal(m2); |
| } |
| }); |
| location = candidates[lambdaFilter.getLambdaOrdinal()].location(); |
| } |
| } |
| else { |
| if (methodsFound > 0) { |
| location = methods.iterator().next().location(); |
| } |
| } |
| } |
| if (location != null) { |
| final RequestManagerImpl requestsManager = debugProcess.getRequestsManager(); |
| final BreakpointRequest request = requestsManager.createBreakpointRequest(this, location); |
| requestsManager.enableRequest(request); |
| } |
| } |
| } |
| catch (ClassNotPreparedException ex) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("ClassNotPreparedException: " + ex.getMessage()); |
| } |
| } |
| catch (ObjectCollectedException ex) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("ObjectCollectedException: " + ex.getMessage()); |
| } |
| } |
| catch (InternalException ex) { |
| LOG.info(ex); |
| } |
| catch(Exception ex) { |
| LOG.info(ex); |
| } |
| } |
| |
| private static int getMethodOrdinal(Method m) { |
| final String name = m.name(); |
| final int dollarIndex = name.lastIndexOf("$"); |
| if (dollarIndex < 0) { |
| return 0; |
| } |
| try { |
| return Integer.parseInt(name.substring(dollarIndex + 1)); |
| } |
| catch (NumberFormatException e) { |
| return 0; |
| } |
| } |
| |
| protected boolean acceptLocation(DebugProcessImpl debugProcess, ReferenceType classType, Location loc) { |
| try { |
| return myFilter.locationMatches(debugProcess, loc); |
| } |
| catch (EvaluateException e) { |
| LOG.info(e); |
| } |
| return true; |
| } |
| |
| @Nullable |
| protected static StepIntoBreakpoint create(@NotNull Project project, @NotNull BreakpointStepMethodFilter filter) { |
| final SourcePosition pos = filter.getBreakpointPosition(); |
| if (pos != null) { |
| final StepIntoBreakpoint breakpoint = new StepIntoBreakpoint(project, pos, filter); |
| breakpoint.init(); |
| return breakpoint; |
| } |
| return null; |
| } |
| } |