IDEA-133347 Can't set breakpoint and debug in decompiled code
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / ui / breakpoints / JavaLineBreakpointTypeBase.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.debugger.ui.breakpoints;
17
18 import com.intellij.debugger.engine.DebuggerUtils;
19 import com.intellij.openapi.editor.Document;
20 import com.intellij.openapi.fileEditor.FileDocumentManager;
21 import com.intellij.openapi.fileTypes.StdFileTypes;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.util.Ref;
24 import com.intellij.openapi.vfs.VirtualFile;
25 import com.intellij.psi.*;
26 import com.intellij.psi.util.PsiTreeUtil;
27 import com.intellij.util.Processor;
28 import com.intellij.xdebugger.XDebuggerUtil;
29 import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
30 import com.intellij.xdebugger.breakpoints.XLineBreakpointType;
31 import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel;
32 import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
33 import org.jetbrains.annotations.Nls;
34 import org.jetbrains.annotations.NonNls;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
37 import org.jetbrains.java.debugger.JavaDebuggerEditorsProvider;
38 import org.jetbrains.java.debugger.breakpoints.JavaBreakpointFiltersPanel;
39 import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties;
40
41 /**
42  * Base class for java line-connected exceptions (line, method, field)
43  * @author egor
44  */
45 public abstract class JavaLineBreakpointTypeBase<P extends JavaBreakpointProperties> extends XLineBreakpointType<P> {
46   public JavaLineBreakpointTypeBase(@NonNls @NotNull String id, @Nls @NotNull String title) {
47     super(id, title);
48   }
49
50   @Override
51   public boolean isAddBreakpointButtonVisible() {
52     return false;
53   }
54
55   @Override
56   public final boolean isSuspendThreadSupported() {
57     return true;
58   }
59
60   @Nullable
61   @Override
62   public final XBreakpointCustomPropertiesPanel<XLineBreakpoint<P>> createCustomRightPropertiesPanel(@NotNull Project project) {
63     return new JavaBreakpointFiltersPanel<P, XLineBreakpoint<P>>(project);
64   }
65
66   @Nullable
67   @Override
68   public final XDebuggerEditorsProvider getEditorsProvider(@NotNull XLineBreakpoint<P> breakpoint, @NotNull Project project) {
69     return new JavaDebuggerEditorsProvider();
70   }
71
72   @Override
73   public String getDisplayText(XLineBreakpoint<P> breakpoint) {
74     BreakpointWithHighlighter javaBreakpoint = (BreakpointWithHighlighter)BreakpointManager.getJavaBreakpoint(breakpoint);
75     if (javaBreakpoint != null) {
76       return javaBreakpoint.getDescription();
77     }
78     else {
79       return super.getDisplayText(breakpoint);
80     }
81   }
82
83   @Override
84   public final boolean canPutAt(@NotNull final VirtualFile file, final int line, @NotNull Project project) {
85     final PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
86     // JSPX supports jvm debugging, but not in XHTML files
87     if (psiFile == null || psiFile.getVirtualFile().getFileType() == StdFileTypes.XHTML) {
88       return false;
89     }
90
91     if (!StdFileTypes.CLASS.equals(psiFile.getFileType()) && !DebuggerUtils.isBreakpointAware(psiFile)) {
92       return false;
93     }
94
95     final Document document = FileDocumentManager.getInstance().getDocument(file);
96     final Ref<Class<? extends JavaLineBreakpointTypeBase>> result = Ref.create();
97     XDebuggerUtil.getInstance().iterateLine(project, document, line, new Processor<PsiElement>() {
98       @Override
99       public boolean process(PsiElement element) {
100         // avoid comments
101         if ((element instanceof PsiWhiteSpace) || (PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null)) {
102           return true;
103         }
104         PsiElement parent = element;
105         while(element != null) {
106           // skip modifiers
107           if (element instanceof PsiModifierList) {
108             element = element.getParent();
109             continue;
110           }
111
112           final int offset = element.getTextOffset();
113           if (offset >= 0) {
114             if (document.getLineNumber(offset) != line) {
115               break;
116             }
117           }
118           parent = element;
119           element = element.getParent();
120         }
121
122         if(parent instanceof PsiMethod) {
123           if (parent.getTextRange().getEndOffset() >= document.getLineEndOffset(line)) {
124             PsiCodeBlock body = ((PsiMethod)parent).getBody();
125             if (body != null) {
126               PsiStatement[] statements = body.getStatements();
127               if (statements.length > 0 && document.getLineNumber(statements[0].getTextOffset()) == line) {
128                 result.set(JavaLineBreakpointType.class);
129               }
130             }
131           }
132           if (result.isNull()) {
133             result.set(JavaMethodBreakpointType.class);
134           }
135         }
136         else if (parent instanceof PsiField) {
137           if (result.isNull()) {
138             result.set(JavaFieldBreakpointType.class);
139           }
140         }
141         else {
142           result.set(JavaLineBreakpointType.class);
143         }
144         return true;
145       }
146     });
147     return result.get() == getClass();
148   }
149 }