From d198a9fa7f43ac9f0231182637eaf17a123be1a1 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 5 Jun 2015 13:13:27 +0300 Subject: [PATCH] Minor: move class to separate file --- .../breakpoints/KotlinFieldBreakpoint.kt | 301 ++++++++++++++++++ .../breakpoints/KotlinFieldBreakpointType.kt | 253 --------------- 2 files changed, 301 insertions(+), 253 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpoint.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpoint.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpoint.kt new file mode 100644 index 00000000000..2140d1eb8a7 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpoint.kt @@ -0,0 +1,301 @@ +/* + * 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.DebuggerBundle +import com.intellij.debugger.SourcePosition +import com.intellij.debugger.engine.DebugProcessImpl +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl +import com.intellij.debugger.impl.PositionUtil +import com.intellij.debugger.requests.Requestor +import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter +import com.intellij.debugger.ui.breakpoints.FieldBreakpoint +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.xdebugger.breakpoints.XBreakpoint +import com.sun.jdi.AbsentInformationException +import com.sun.jdi.Method +import com.sun.jdi.ReferenceType +import com.sun.jdi.event.* +import com.sun.jdi.request.EventRequest +import com.sun.jdi.request.MethodEntryRequest +import org.jetbrains.annotations.TestOnly +import org.jetbrains.java.debugger.breakpoints.properties.JavaFieldBreakpointProperties +import org.jetbrains.kotlin.codegen.PropertyCodegen +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.load.kotlin.PackageClassUtils +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext + +class KotlinFieldBreakpoint(project: Project, breakpoint: XBreakpoint) : FieldBreakpoint(project, breakpoint) { + companion object { + private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpoint") + } + + private enum class BreakpointType { + FIELD, + METHOD + } + + private val breakpointType: BreakpointType + + init { + val element = getField()!! + val bindingContext = element.analyzeAndGetResult().bindingContext + var descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) + if (descriptor is ValueParameterDescriptor) { + descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor) + } + + breakpointType = if (bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor as PropertyDescriptor)) { + BreakpointType.FIELD + } + else { + BreakpointType.METHOD + } + } + + override fun isValid(): Boolean { + if (!BreakpointWithHighlighter.isPositionValid(getXBreakpoint().getSourcePosition())) return false + + return runReadAction { + val field = getField() + field != null && field.isValid() + } + } + + public fun getField(): JetCallableDeclaration? { + val sourcePosition = getSourcePosition() + return getProperty(sourcePosition) + } + + private fun getProperty(sourcePosition: SourcePosition?): JetCallableDeclaration? { + val property: JetProperty? = PositionUtil.getPsiElementAt(getProject(), javaClass(), sourcePosition) + if (property != null) { + return property + } + val parameter: JetParameter? = PositionUtil.getPsiElementAt(getProject(), javaClass(), sourcePosition) + if (parameter != null) { + return parameter + } + return null + } + + override fun reload(psiFile: PsiFile?) { + val property = getProperty(getSourcePosition()) + if (property != null) { + setFieldName(property.getName()) + + if (property is JetProperty && property.isTopLevel()) { + getProperties().myClassName = PackageClassUtils.getPackageClassFqName(property.getContainingJetFile().getPackageFqName()).asString() + } + else { + val jetClass: JetClassOrObject? = PsiTreeUtil.getParentOfType(property, javaClass()) + if (jetClass is JetClassOrObject) { + val fqName = jetClass.getFqName() + if (fqName != null) { + getProperties().myClassName = fqName.asString() + } + } + } + setInstanceFiltersEnabled(false) + } + } + + override fun createRequestForPreparedClass(debugProcess: DebugProcessImpl?, refType: ReferenceType?) { + if (debugProcess == null || refType == null) return + + val vm = debugProcess.getVirtualMachineProxy() + try { + when (breakpointType) { + BreakpointType.FIELD -> { + val field = refType.fieldByName(getFieldName()) + if (field != null) { + val manager = debugProcess.getRequestsManager() + if (getProperties().WATCH_MODIFICATION && vm.canWatchFieldModification()) { + val request = manager.createModificationWatchpointRequest(this, field) + debugProcess.getRequestsManager().enableRequest(request) + if (LOG.isDebugEnabled()) { + LOG.debug("Modification request added") + } + } + if (getProperties().WATCH_ACCESS && vm.canWatchFieldAccess()) { + val request = manager.createAccessWatchpointRequest(this, field) + debugProcess.getRequestsManager().enableRequest(request) + if (LOG.isDebugEnabled()) { + LOG.debug("Field access request added (field = ${field.name()}; refType = ${refType.name()})") + } + } + } + } + BreakpointType.METHOD -> { + val propertyName = Name.identifier(getFieldName()) + + if (getProperties().WATCH_ACCESS) { + val getter = refType.methodsByName(PropertyCodegen.getterName(propertyName)).firstOrNull() + if (getter != null) { + createMethodBreakpoint(debugProcess, refType, getter) + } + } + + if (getProperties().WATCH_MODIFICATION) { + val setter = refType.methodsByName(PropertyCodegen.setterName(propertyName)).firstOrNull() + if (setter != null) { + createMethodBreakpoint(debugProcess, refType, setter) + } + } + } + } + } + catch (ex: Exception) { + LOG.debug(ex) + } + } + + private fun createMethodBreakpoint(debugProcess: DebugProcessImpl, refType: ReferenceType, accessor: Method) { + val manager = debugProcess.getRequestsManager() + val line = accessor.allLineLocations().firstOrNull() + if (line != null) { + val request = manager.createBreakpointRequest(this, line) + debugProcess.getRequestsManager().enableRequest(request) + if (LOG.isDebugEnabled()) { + LOG.debug("Breakpoint request added") + } + } + else { + var entryRequest: MethodEntryRequest? = findRequest(debugProcess, javaClass(), this) + if (entryRequest == null) { + entryRequest = manager.createMethodEntryRequest(this)!! + if (LOG.isDebugEnabled()) { + LOG.debug("Method entry request added (method = ${accessor.name()}; refType = ${refType.name()})") + } + } + else { + entryRequest.disable() + } + entryRequest.addClassFilter(refType) + manager.enableRequest(entryRequest) + } + } + + inline fun findRequest(debugProcess: DebugProcessImpl, requestClass: Class, requestor: Requestor): T? { + val requests = debugProcess.getRequestsManager().findRequests(requestor) + for (eventRequest in requests) { + if (eventRequest.javaClass == requestClass) { + return eventRequest as T + } + } + return null + } + + override fun evaluateCondition(context: EvaluationContextImpl, event: LocatableEvent): Boolean { + if (breakpointType == BreakpointType.METHOD && !matchesEvent(event)) { + return false + } + return super.evaluateCondition(context, event) + } + + public fun matchesEvent(event: LocatableEvent): Boolean { + val method = event.location().method() + // TODO check property type + return method != null && method.name() in getMethodsName() + } + + private fun getMethodsName(): List { + val propertyName = Name.identifier(getFieldName()) + return arrayListOf(PropertyCodegen.getterName(propertyName), PropertyCodegen.setterName(propertyName)) + + } + + override fun getEventMessage(event: LocatableEvent): String { + val location = event.location() + val locationQName = location.declaringType().name() + "." + location.method().name() + val locationFileName = try { + location.sourceName() + } + catch (e: AbsentInformationException) { + getFileName() + } + + val locationLine = location.lineNumber() + when (event) { + is ModificationWatchpointEvent-> { + val field = event.field() + return DebuggerBundle.message( + "status.static.field.watchpoint.reached.access", + field.declaringType().name(), + field.name(), + locationQName, + locationFileName, + locationLine) + } + is AccessWatchpointEvent -> { + val field = event.field() + return DebuggerBundle.message( + "status.static.field.watchpoint.reached.access", + field.declaringType().name(), + field.name(), + locationQName, + locationFileName, + locationLine) + } + is MethodEntryEvent -> { + val method = event.method() + return DebuggerBundle.message( + "status.method.entry.breakpoint.reached", + method.declaringType().name() + "." + method.name() + "()", + locationQName, + locationFileName, + locationLine) + } + is MethodExitEvent -> { + val method = event.method() + return DebuggerBundle.message( + "status.method.exit.breakpoint.reached", + method.declaringType().name() + "." + method.name() + "()", + locationQName, + locationFileName, + locationLine) + } + } + return DebuggerBundle.message( + "status.line.breakpoint.reached", + locationQName, + locationFileName, + locationLine) + } + + fun setFieldName(fieldName: String) { + getProperties().myFieldName = fieldName + } + + @TestOnly + fun setWatchAccess(value: Boolean) { + getProperties().WATCH_ACCESS = value + } + + @TestOnly + fun setWatchModification(value: Boolean) { + getProperties().WATCH_MODIFICATION = value + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpointType.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpointType.kt index b90aa49e120..bbc3ff3d3f7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpointType.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/breakpoints/KotlinFieldBreakpointType.kt @@ -246,257 +246,4 @@ public class KotlinFieldBreakpointType : JavaBreakpointType) : FieldBreakpoint(project, breakpoint) { - companion object { - private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpoint") - } - - private enum class BreakpointType { - FIELD, - METHOD - } - - private val breakpointType: BreakpointType - - init { - val element = getField()!! - val bindingContext = element.analyzeAndGetResult().bindingContext - var descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) - if (descriptor is ValueParameterDescriptor) { - descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor) - } - - breakpointType = if (bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor as PropertyDescriptor)) { - BreakpointType.FIELD - } - else { - BreakpointType.METHOD - } - } - - override fun isValid(): Boolean { - if (!BreakpointWithHighlighter.isPositionValid(getXBreakpoint().getSourcePosition())) return false - - return runReadAction { - val field = getField() - field != null && field.isValid() - } - } - - public fun getField(): JetCallableDeclaration? { - val sourcePosition = getSourcePosition() - return getProperty(sourcePosition) - } - - private fun getProperty(sourcePosition: SourcePosition?): JetCallableDeclaration? { - val property: JetProperty? = PositionUtil.getPsiElementAt(getProject(), javaClass(), sourcePosition) - if (property != null) { - return property - } - val parameter: JetParameter? = PositionUtil.getPsiElementAt(getProject(), javaClass(), sourcePosition) - if (parameter != null) { - return parameter - } - return null - } - - override fun reload(psiFile: PsiFile?) { - val property = getProperty(getSourcePosition()) - if (property != null) { - setFieldName(property.getName()) - - if (property is JetProperty && property.isTopLevel()) { - getProperties().myClassName = PackageClassUtils.getPackageClassFqName(property.getContainingJetFile().getPackageFqName()).asString() - } - else { - val jetClass: JetClassOrObject? = PsiTreeUtil.getParentOfType(property, javaClass()) - if (jetClass is JetClassOrObject) { - val fqName = jetClass.getFqName() - if (fqName != null) { - getProperties().myClassName = fqName.asString() - } - } - } - setInstanceFiltersEnabled(false) - } - } - - override fun createRequestForPreparedClass(debugProcess: DebugProcessImpl?, refType: ReferenceType?) { - if (debugProcess == null || refType == null) return - - val vm = debugProcess.getVirtualMachineProxy() - try { - when (breakpointType) { - BreakpointType.FIELD -> { - val field = refType.fieldByName(getFieldName()) - if (field != null) { - val manager = debugProcess.getRequestsManager() - if (getProperties().WATCH_MODIFICATION && vm.canWatchFieldModification()) { - val request = manager.createModificationWatchpointRequest(this, field) - debugProcess.getRequestsManager().enableRequest(request) - if (LOG.isDebugEnabled()) { - LOG.debug("Modification request added") - } - } - if (getProperties().WATCH_ACCESS && vm.canWatchFieldAccess()) { - val request = manager.createAccessWatchpointRequest(this, field) - debugProcess.getRequestsManager().enableRequest(request) - if (LOG.isDebugEnabled()) { - LOG.debug("Field access request added (field = ${field.name()}; refType = ${refType.name()})") - } - } - } - } - BreakpointType.METHOD -> { - val propertyName = Name.identifier(getFieldName()) - - if (getProperties().WATCH_ACCESS) { - val getter = refType.methodsByName(PropertyCodegen.getterName(propertyName)).firstOrNull() - if (getter != null) { - createMethodBreakpoint(debugProcess, refType, getter) - } - } - - if (getProperties().WATCH_MODIFICATION) { - val setter = refType.methodsByName(PropertyCodegen.setterName(propertyName)).firstOrNull() - if (setter != null) { - createMethodBreakpoint(debugProcess, refType, setter) - } - } - } - } - } - catch (ex: Exception) { - LOG.debug(ex) - } - } - - private fun createMethodBreakpoint(debugProcess: DebugProcessImpl, refType: ReferenceType, accessor: Method) { - val manager = debugProcess.getRequestsManager() - val line = accessor.allLineLocations().firstOrNull() - if (line != null) { - val request = manager.createBreakpointRequest(this, line) - debugProcess.getRequestsManager().enableRequest(request) - if (LOG.isDebugEnabled()) { - LOG.debug("Breakpoint request added") - } - } - else { - var entryRequest: MethodEntryRequest? = findRequest(debugProcess, javaClass(), this) - if (entryRequest == null) { - entryRequest = manager.createMethodEntryRequest(this)!! - if (LOG.isDebugEnabled()) { - LOG.debug("Method entry request added (method = ${accessor.name()}; refType = ${refType.name()})") - } - } - else { - entryRequest.disable() - } - entryRequest.addClassFilter(refType) - manager.enableRequest(entryRequest) - } - } - - inline fun findRequest(debugProcess: DebugProcessImpl, requestClass: Class, requestor: Requestor): T? { - val requests = debugProcess.getRequestsManager().findRequests(requestor) - for (eventRequest in requests) { - if (eventRequest.javaClass == requestClass) { - return eventRequest as T - } - } - return null - } - - override fun evaluateCondition(context: EvaluationContextImpl, event: LocatableEvent): Boolean { - if (breakpointType == BreakpointType.METHOD && !matchesEvent(event)) { - return false - } - return super.evaluateCondition(context, event) - } - - public fun matchesEvent(event: LocatableEvent): Boolean { - val method = event.location().method() - // TODO check property type - return method != null && method.name() in getMethodsName() - } - - private fun getMethodsName(): List { - val propertyName = Name.identifier(getFieldName()) - return arrayListOf(PropertyCodegen.getterName(propertyName), PropertyCodegen.setterName(propertyName)) - - } - - override fun getEventMessage(event: LocatableEvent): String { - val location = event.location() - val locationQName = location.declaringType().name() + "." + location.method().name() - val locationFileName = try { - location.sourceName() - } - catch (e: AbsentInformationException) { - getFileName() - } - - val locationLine = location.lineNumber() - when (event) { - is ModificationWatchpointEvent-> { - val field = event.field() - return DebuggerBundle.message( - "status.static.field.watchpoint.reached.access", - field.declaringType().name(), - field.name(), - locationQName, - locationFileName, - locationLine) - } - is AccessWatchpointEvent -> { - val field = event.field() - return DebuggerBundle.message( - "status.static.field.watchpoint.reached.access", - field.declaringType().name(), - field.name(), - locationQName, - locationFileName, - locationLine) - } - is MethodEntryEvent -> { - val method = event.method() - return DebuggerBundle.message( - "status.method.entry.breakpoint.reached", - method.declaringType().name() + "." + method.name() + "()", - locationQName, - locationFileName, - locationLine) - } - is MethodExitEvent -> { - val method = event.method() - return DebuggerBundle.message( - "status.method.exit.breakpoint.reached", - method.declaringType().name() + "." + method.name() + "()", - locationQName, - locationFileName, - locationLine) - } - } - return DebuggerBundle.message( - "status.line.breakpoint.reached", - locationQName, - locationFileName, - locationLine) - } - - fun setFieldName(fieldName: String) { - getProperties().myFieldName = fieldName - } - - @TestOnly - fun setWatchAccess(value: Boolean) { - getProperties().WATCH_ACCESS = value - } - - @TestOnly - fun setWatchModification(value: Boolean) { - getProperties().WATCH_MODIFICATION = value - } } \ No newline at end of file