/* * Copyright 2010-2015 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 org.jetbrains.kotlin.idea.debugger.breakpoints; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType; import com.intellij.debugger.ui.breakpoints.LineBreakpoint; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties; import org.jetbrains.kotlin.idea.KotlinIcons; import org.jetbrains.kotlin.psi.KtClassInitializer; import org.jetbrains.kotlin.psi.KtFunction; import javax.swing.*; import java.util.List; public class KotlinLineBreakpointType extends JavaLineBreakpointType { public KotlinLineBreakpointType() { super("kotlin-line", "Kotlin Line Breakpoints"); } @Override public boolean matchesPosition(@NotNull LineBreakpoint<?> breakpoint, @NotNull SourcePosition position) { JavaBreakpointProperties properties = getProperties(breakpoint); if (properties == null || properties instanceof JavaLineBreakpointProperties) { if (properties != null && ((JavaLineBreakpointProperties)properties).getLambdaOrdinal() == null) return true; PsiElement containingMethod = getContainingMethod(breakpoint); if (containingMethod == null) return false; return inTheMethod(position, containingMethod); } return true; } @Override @Nullable public PsiElement getContainingMethod(@NotNull LineBreakpoint<?> breakpoint) { SourcePosition position = breakpoint.getSourcePosition(); if (position == null) return null; JavaBreakpointProperties properties = getProperties(breakpoint); if (properties instanceof JavaLineBreakpointProperties) { Integer ordinal = ((JavaLineBreakpointProperties) properties).getLambdaOrdinal(); PsiElement lambda = getLambdaByOrdinal(position, ordinal); if (lambda != null) return lambda; } return getContainingMethod(position.getElementAt()); } @Nullable private static JavaBreakpointProperties getProperties(@NotNull LineBreakpoint<?> breakpoint) { XBreakpoint<?> xBreakpoint = breakpoint.getXBreakpoint(); return xBreakpoint != null ? (JavaBreakpointProperties) xBreakpoint.getProperties() : null; } @Nullable private static KtFunction getLambdaByOrdinal(SourcePosition position, Integer ordinal) { if (ordinal != null && ordinal >= 0) { List<KtFunction> lambdas = BreakpointTypeUtilsKt.getLambdasAtLineIfAny(position); if (lambdas.size() > ordinal) { return lambdas.get(ordinal); } } return null; } @Nullable public static PsiElement getContainingMethod(@Nullable PsiElement elem) { //noinspection unchecked return PsiTreeUtil.getParentOfType(elem, KtFunction.class, KtClassInitializer.class); } public static boolean inTheMethod(@NotNull SourcePosition pos, @NotNull PsiElement method) { PsiElement elem = pos.getElementAt(); if (elem == null) return false; return Comparing.equal(getContainingMethod(elem), method); } @Override public boolean canPutAt(@NotNull VirtualFile file, int line, @NotNull Project project) { return BreakpointTypeUtilsKt.canPutAt(file, line, project, getClass()); } @NotNull @Override public List<JavaBreakpointVariant> computeVariants(@NotNull Project project, @NotNull XSourcePosition position) { return BreakpointTypeUtilsKt.computeVariants(project, position, this); } @Nullable @Override public TextRange getHighlightRange(XLineBreakpoint<JavaLineBreakpointProperties> breakpoint) { JavaLineBreakpointProperties properties = breakpoint.getProperties(); if (properties != null) { Integer ordinal = properties.getLambdaOrdinal(); if (ordinal != null) { Breakpoint javaBreakpoint = BreakpointManager.getJavaBreakpoint(breakpoint); if (javaBreakpoint instanceof LineBreakpoint) { SourcePosition position = ((LineBreakpoint) javaBreakpoint).getSourcePosition(); if (position != null) { KtFunction lambda = getLambdaByOrdinal(position, ordinal); if (lambda != null) { return lambda.getTextRange(); } } } } } return null; } public class KotlinLambdaBreakpointVariant extends ExactJavaBreakpointVariant { public KotlinLambdaBreakpointVariant(XSourcePosition position, KtFunction function, Integer lambdaOrdinal) { super(position, function, lambdaOrdinal); } @Override public Icon getIcon() { return KotlinIcons.LAMBDA; } } public class KotlinLineBreakpointVariant extends ExactJavaBreakpointVariant { public KotlinLineBreakpointVariant(XSourcePosition position, PsiElement element) { super(position, element, -1); } @Override public String getText() { return StringsKt.replace(super.getText(), " ", "", true); } @Override public Icon getIcon() { return KotlinIcons.FUNCTION; } } }