Skip to content

Commit

Permalink
#23 WIP Draft version of MeasureService
Browse files Browse the repository at this point in the history
  • Loading branch information
veptechno committed May 19, 2022
1 parent 1a01f39 commit ef49b2a
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 35 deletions.
15 changes: 9 additions & 6 deletions src/main/kotlin/com/justai/jaicf/plugin/contexts/StateContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import com.justai.jaicf.plugin.utils.VersionService
import com.justai.jaicf.plugin.utils.boundedCallExpressionOrNull
import com.justai.jaicf.plugin.utils.getBoundedLambdaArgumentOrNull
import com.justai.jaicf.plugin.utils.isJaicfInclude
import com.justai.jaicf.plugin.utils.measure
import org.jetbrains.kotlin.psi.KtCallExpression

class StateContext : TemplateContextType("STATE", "State") {
override fun isInContext(templateActionContext: TemplateActionContext): Boolean {
if (!VersionService.getInstance(templateActionContext.file.project).isJaicfInclude) return false
override fun isInContext(templateActionContext: TemplateActionContext): Boolean =
templateActionContext.file.project.measure("StateContext.isInContext") {
if (!VersionService.getInstance(templateActionContext.file.project).isJaicfInclude) return@measure false

val probeElement = templateActionContext.file.findElementAt(templateActionContext.startOffset)
val boundedLambda = probeElement?.getBoundedLambdaArgumentOrNull(KtCallExpression::class.java) ?: return false
return boundedLambda.boundedCallExpressionOrNull?.isStateDeclaration == true
}
val probeElement = templateActionContext.file.findElementAt(templateActionContext.startOffset)
val boundedLambda =
probeElement?.getBoundedLambdaArgumentOrNull(KtCallExpression::class.java) ?: return@measure false
return@measure boundedLambda.boundedCallExpressionOrNull?.isStateDeclaration == true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class StatePathInspection : LocalInspectionTool() {
NavigateToState("Go to unrelated state declaration ${suggestion.fullPath}", suggestion)
)
}
is StateFound, is StatesFound, OutOfStateBoundUsage -> {}
}
}
}
Expand Down
17 changes: 10 additions & 7 deletions src/main/kotlin/com/justai/jaicf/plugin/inspections/Visitors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.justai.jaicf.plugin.utils.VersionService
import com.justai.jaicf.plugin.utils.innerPathExpressions
import com.justai.jaicf.plugin.utils.isExist
import com.justai.jaicf.plugin.utils.isJaicfInclude
import com.justai.jaicf.plugin.utils.measure
import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression
Expand All @@ -25,16 +26,18 @@ abstract class StateVisitor(holder: ProblemsHolder) : VisitorBase(holder) {
abstract fun visitState(state: State)

override fun visitFile(file: PsiFile) {
if (!checkEnvironmentAndNotify(file))
return
file.project.measure("${this.javaClass.simpleName}.visitFile(${file.name})") {
if (!checkEnvironmentAndNotify(file))
return@measure

if (file !is KtFile)
return
if (file !is KtFile)
return@measure

val service = ScenarioDataService.getInstance(file) ?: return
val service = ScenarioDataService.getInstance(file) ?: return@measure

service.getScenarios(file)?.forEach {
recursiveEntryIntoState(it.innerState)
service.getScenarios(file)?.forEach {
recursiveEntryIntoState(it.innerState)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.justai.jaicf.plugin.utils.VersionService
import com.justai.jaicf.plugin.utils.cached
import com.justai.jaicf.plugin.utils.isSupportedJaicfInclude

abstract class JaicfService(protected val project: Project) {
abstract class JaicfService(/*TODO protected*/ val project: Project) {

protected val enabled: Boolean by cached(JaicfVersionTracker.getInstance(project)) {
VersionService.getInstance(project).isSupportedJaicfInclude
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ import com.justai.jaicf.plugin.scenarios.psi.ScenarioDataService
import com.justai.jaicf.plugin.scenarios.psi.dto.Scenario
import com.justai.jaicf.plugin.scenarios.psi.dto.State
import com.justai.jaicf.plugin.utils.isRemoved
import com.justai.jaicf.plugin.utils.measure
import org.jetbrains.kotlin.psi.KtFile

val PsiElement.framingState: State?
get() {
get() = measure("PsiElement.framingState") {
if (isRemoved)
return null
return@measure null

val file = this.containingFile as? KtFile ?: return null
val scenarios = ScenarioDataService.getInstance(this)?.getScenarios(file) ?: return null
val file = containingFile as? KtFile ?: return@measure null
val scenarios = ScenarioDataService.getInstance(this@framingState)?.getScenarios(file) ?: return@measure null

return scenarios.findBoundingScenario(this)
?.let { recursiveFindState(it.innerState, this) }
return@measure scenarios.findBoundingScenario(this@framingState)
?.let { recursiveFindState(it.innerState, this@framingState) }
}

fun List<Scenario>.findBoundingScenario(element: PsiElement) = filter { contains(it.innerState, element) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.justai.jaicf.plugin.scenarios.JaicfService
import com.justai.jaicf.plugin.scenarios.psi.builders.buildScenario
import com.justai.jaicf.plugin.scenarios.psi.dto.Scenario
import com.justai.jaicf.plugin.trackers.JaicfVersionTracker
import com.justai.jaicf.plugin.utils.CREATE_MODEL_METHOD_NAME
import com.justai.jaicf.plugin.utils.LiveMapByFiles
import com.justai.jaicf.plugin.utils.SCENARIO_EXTENSIONS_CLASS_NAME
import com.justai.jaicf.plugin.utils.SCENARIO_METHOD_NAME
import com.justai.jaicf.plugin.utils.SCENARIO_PACKAGE
import com.justai.jaicf.plugin.utils.isExist
import com.justai.jaicf.plugin.utils.measure
import org.jetbrains.kotlin.idea.search.fileScope
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtFile
Expand All @@ -31,13 +33,15 @@ class ScenarioDataService(project: Project) : JaicfService(project) {
?: emptyList()
}

fun getScenarios(file: KtFile) =
fun getScenarios(file: KtFile): List<Scenario>? = measure("ScenarioDataService.getScenarios(${file.name})") {
if (enabled) (file.originalFile as? KtFile)?.let { scenariosMap[it] }
else null
}

fun getScenarios() =
fun getScenarios(): List<Scenario> = measure("ScenarioDataService.getScenarios()") {
if (enabled) scenariosMap.getNotNullValues().flatten()
else emptyList()
}

companion object {
fun getInstance(element: PsiElement): ScenarioDataService? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ import com.justai.jaicf.plugin.utils.argumentExpressionsByAnnotation
import com.justai.jaicf.plugin.utils.argumentExpressionsOrDefaultValuesByAnnotation
import com.justai.jaicf.plugin.utils.declaration
import com.justai.jaicf.plugin.utils.findChildOfType
import com.justai.jaicf.plugin.utils.findChildrenOfType
import com.justai.jaicf.plugin.utils.getMethodAnnotations
import com.justai.jaicf.plugin.utils.isRemoved
import com.justai.jaicf.plugin.utils.measure
import com.justai.jaicf.plugin.utils.stringValueOrNull
import org.jetbrains.kotlin.psi.KtAnnotatedExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull

fun buildState(
Expand Down Expand Up @@ -56,7 +55,7 @@ val KtCallExpression.annotatedLambdaBlockInDeclaration: KtLambdaExpression?
get() = this.declaration?.bodyExpression?.findChildOfType<KtAnnotatedExpression>()?.baseExpression as? KtLambdaExpression

val KtCallExpression.isStateDeclaration: Boolean
get() = getMethodAnnotations(STATE_DECLARATION_ANNOTATION_NAME).isNotEmpty()
get() = measure("isStateDeclaration") { getMethodAnnotations(STATE_DECLARATION_ANNOTATION_NAME).isNotEmpty() }

private val KtCallExpression.identifierOfStateExpression: StateIdentifier
get() {
Expand Down
87 changes: 87 additions & 0 deletions src/main/kotlin/com/justai/jaicf/plugin/utils/LoadingService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.justai.jaicf.plugin.utils

import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.jetbrains.rd.util.currentThreadName
import com.justai.jaicf.plugin.scenarios.JaicfService
import kotlin.system.measureTimeMillis
import java.util.concurrent.ConcurrentHashMap

class LoadingService {


// TODO rename
fun load() {

}

// TODO rename
fun await() {

}

companion object {
fun getInstance(project: Project): LoadingService =
project.getService(LoadingService::class.java)

fun getInstance(element: PsiElement): LoadingService? =
if (element.isExist) element.project.getService(LoadingService::class.java)
else null
}
}

class MeasureService(val project: Project) {

private val threads = ConcurrentHashMap<String, Int>()

private val allowedRoots = listOf("StateContext.isInContext")

fun <T> measure(method: () -> String, block: Project.() -> T): T {
val result: Result<T>
val indent: String

if (threads.getOrDefault(currentThreadName(), 0) == 0 && method() !in allowedRoots)
return project.block()

synchronized(this) {
threads.getOrDefault(currentThreadName(), 0).also {
threads[currentThreadName()] = it + 1
indent = (1..it * 4).joinToString("") { " " }
}
}
measureTimeMillis { result = runCatching { project.block() } }.also {
if (it > 2) println("$indent|${method()}: $it")
}
synchronized(this) {
threads[currentThreadName()]?.also { threads[currentThreadName()] = it - 1 }
}
return result.getOrThrow()
}

companion object {
fun getInstance(project: Project): MeasureService =
project.getService(MeasureService::class.java)

fun getInstance(element: PsiElement): MeasureService? =
if (element.isExist) element.project.getService(MeasureService::class.java)
else null
}
}

fun <T> PsiElement.measure(method: String, block: Project.() -> T): T {
return MeasureService.getInstance(this)?.measure({method}, block) ?: project.block()
}
fun <T> PsiElement.measure(method: () -> String, block: Project.() -> T): T {
return MeasureService.getInstance(this)?.measure(method, block) ?: project.block()
}

fun <T> Project.measure(method: String, block: Project.() -> T): T {
return MeasureService.getInstance(this).measure({ method }, block) ?: block()
}
fun <T> Project.blockMeasure(method: String, block: Project.() -> T) {
MeasureService.getInstance(this).measure({ method }, block) ?: block()
}

fun <T> JaicfService.measure(method: String, block: Project.() -> T): T {
return MeasureService.getInstance(this.project).measure({ method }, block) ?: project.block()
}
19 changes: 12 additions & 7 deletions src/main/kotlin/com/justai/jaicf/plugin/utils/PsiElementUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.SlowOperations.allowSlowOperations
import java.lang.Integer.min
import org.jetbrains.kotlin.idea.debugger.sequence.psi.callName
import org.jetbrains.kotlin.idea.debugger.sequence.psi.receiverType
import org.jetbrains.kotlin.name.FqName
Expand Down Expand Up @@ -79,8 +78,9 @@ fun KtCallExpression.parametersByAnnotation(name: String) =
fun KtCallExpression.getMethodAnnotations(name: String) =
declaration?.getMethodAnnotations(name) ?: emptyList()

fun KtFunction.getMethodAnnotations(name: String) =
fun KtFunction.getMethodAnnotations(name: String) = measure("KtFunction.getMethodAnnotations") {
annotationEntries.filter { it.shortName?.asString() == name }
}

val KtFunction.isBinary get() = isExist && containingFile.name.endsWith(".class")

Expand Down Expand Up @@ -109,12 +109,14 @@ val KtParameter.annotationNames: List<String>
get() = annotationEntries.mapNotNull { it.shortName?.asString() }

val KtCallElement.declaration: KtFunction?
get() = allowSlowOperations<KtFunction?, Throwable> {
if (isExist) referenceExpression?.resolveToSource else null
get() = measure("KtCallElement.declaration") {
allowSlowOperations<KtFunction?, Throwable> {
if (isExist) referenceExpression?.resolveToSource else null
}
}

val KtCallElement.referenceExpression: KtReferenceExpression?
get() = findChildOfType<KtNameReferenceExpression>()
get() = measure("KtCallElement.referenceExpression") { findChildOfType<KtNameReferenceExpression>() }

val KtReferenceExpression.resolveToSource: KtFunction?
get() = (safeResolve() as? KtFunction)?.let {
Expand All @@ -124,7 +126,10 @@ val KtReferenceExpression.resolveToSource: KtFunction?

fun KtReferenceExpression.safeResolve() =
try {
resolve()
measure({
"KtReferenceExpression.safeResolve() ${this.presentation} " +
"${this.hashCode()}"
}) { resolve() }
} catch (e: IndexNotReadyException) {
null
}
Expand Down Expand Up @@ -237,7 +242,7 @@ val KtValueArgument.definedIdentifier: String?
get() = getArgumentName()?.asName?.identifier

val KtValueArgument.boundedCallExpressionOrNull
get() = getParentOfType<KtCallExpression>(true)
get() = measure("boundedCallExpressionOrNull") { getParentOfType<KtCallExpression>(true) }

val PsiElement.isRemoved: Boolean
get() = !this.isValid || containingFile == null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package com.justai.jaicf.plugin.widgets

import com.intellij.icons.AllIcons
import com.intellij.openapi.editor.EditorFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.popup.ListPopup
import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.wm.StatusBar
import com.intellij.openapi.wm.StatusBarWidget
import com.intellij.openapi.wm.StatusBarWidget.MultipleTextValuesPresentation
import com.intellij.openapi.wm.StatusBarWidget.WidgetPresentation
import com.intellij.openapi.wm.StatusBarWidgetFactory
import com.intellij.openapi.wm.impl.status.EditorBasedWidget
import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager
import com.intellij.ui.AnimatedIcon
import com.intellij.util.Consumer
import com.justai.jaicf.plugin.utils.VersionService
import com.justai.jaicf.plugin.utils.isSupportedJaicfInclude
import javax.swing.Icon
import kotlin.random.Random
import org.jetbrains.kotlin.idea.debugger.getService
import java.awt.event.MouseEvent
import java.lang.Thread.sleep


class LoadingStatusBarWidgetFactory : StatusBarWidgetFactory {
Expand All @@ -33,22 +42,36 @@ class LoadingStatusBarWidgetFactory : StatusBarWidgetFactory {
}

class MyWidget(project: Project?) : EditorBasedWidget(project!!) {

init {
Thread {
while (true) {
sleep(1000)
myStatusBar.updateWidget(ID())
}
}.start()
}

override fun ID(): String {

return "MyWidget"
}

override fun getPresentation(): WidgetPresentation {
return MyPresentation()
}


}

class MyPresentation : MultipleTextValuesPresentation {

override fun getPopupStep(): ListPopup? {
return null
}

override fun getSelectedValue(): String {
return "Selected value"
return "Selected value ${Random.nextInt()}"
}

override fun getTooltipText(): String {
Expand All @@ -58,4 +81,9 @@ class MyPresentation : MultipleTextValuesPresentation {
override fun getClickConsumer(): Consumer<MouseEvent>? {
return null
}

override fun getIcon(): Icon {
val icon = AllIcons.Toolbar.Locale
return AnimatedIcon(1000, icon, IconLoader.getDisabledIcon(icon))
}
}
Loading

0 comments on commit ef49b2a

Please sign in to comment.