This commit is contained in:
Kagura 2024-10-29 23:03:45 +08:00
parent c7f8a7c30b
commit fa9ff80214
11 changed files with 552 additions and 84 deletions

124
.idea/uiDesigner.xml Normal file
View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View file

@ -28,7 +28,7 @@ compose.desktop {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
targetFormats(TargetFormat.Dmg, TargetFormat.Exe, TargetFormat.Deb)
packageName = "VariableRelation"
packageVersion = "1.0.0"
}

View file

@ -1,89 +1,183 @@
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.ButtonColors
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import core.SourceFile
import core.*
import ui.TextfieldWithLineNumber
import utils.*
@OptIn(ExperimentalTextApi::class)
@Composable
@Preview
fun App() {
var text by remember { mutableStateOf("") }
var isReady by remember { mutableStateOf(false) }
var source: SourceFile? = null
val showResult = remember { mutableStateOf(false) }
var defineList by remember { mutableStateOf("") }
var useList by remember { mutableStateOf("") }
var traceTree by remember { mutableStateOf("") }
var funcTraceTree by remember { mutableStateOf("") }
var page by remember { mutableStateOf(0) }
var ttGraph by remember { mutableStateOf("") }
var ivGraph by remember { mutableStateOf("") }
MaterialTheme {
Column(
when {
showResult.value -> {
Dialog(onDismissRequest = {
showResult.value = false
page = 0
}) {
AlertDialog(
title = {
Text(
text = when (page) {
0 -> "函数定义的变量"
1 -> "函数内每条语句的定义和使用"
2 -> "函数内每个变量 def-use 链"
3 -> "函数间每个变量 def-use 链"
else -> "出错了"
},
color = Color.Black,
fontWeight = FontWeight.Bold,
fontSize = 24.sp,
textAlign = TextAlign.Center
)
},
text = {
Text(
text = when (page) {
0 -> defineList
1 -> useList
2 -> traceTree
3 -> funcTraceTree
else -> "出错了(ง •̀_•́)ง"
},
modifier = Modifier
.fillMaxSize()
.wrapContentHeight(),
textAlign = TextAlign.Start,
color = Color.Black
)
},
onDismissRequest = {
showResult.value = false
},
confirmButton = {
TextButton(
onClick = {
page = (page + 1) % 4
}
) {
Text("下一个")
}
},
dismissButton = {
TextButton(
onClick = {
if (page < 2){
showResult.value = false
}else{
if (page == 2){
openGraph(ttGraph)
}else if (page == 3){
openGraph(ivGraph)
}
}
}
) {
Text(
if (page < 2){
"关闭"
}else{
"查看图像(在线)"
}
)
}
},
modifier = Modifier
.padding(5.dp)
.wrapContentSize(),
shape = RoundedCornerShape(20.dp),
backgroundColor = Color(0xffFAF0E6)
)
}
}
}
Surface(
modifier = Modifier.fillMaxSize()
.padding(horizontal = 10.dp, vertical = 5.dp),
.background(color = Color(0xFFFBFBFB))
) {
Column(
modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp, vertical = 5.dp),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Center
) {
Text("请输入您的代码")
TextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.fillMaxWidth(0.95f)
.weight(1f),
textStyle = TextStyle.Default.copy(fontFamily = FontFamily("monospace"))
)
Row(
modifier = Modifier.fillMaxWidth(0.9f)
.padding(vertical = 5.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
TextfieldWithLineNumber(
modifier = Modifier.weight(1f).fillMaxWidth(),
) {
Button(
modifier = Modifier.padding(vertical = 10.dp),
onClick = {
val s = SourceFile(text.toString())
text = s.content
source = s
},
) {
Text("格式化")
if (it.isEmpty()) {
return@TextfieldWithLineNumber
}
val sf = SourceFile(it)
source = sf
try {
sf.parseFunction()
} catch (e: Exception) {
// 分析失败
defineList = e.printStackTrace().toString()
return@TextfieldWithLineNumber
}
Button(
modifier = Modifier.padding(vertical = 10.dp),
onClick = {
source = SourceFile(text.toString())
isReady = true
},
enabled = !isReady
) {
Text("分析")
defineList =
try {
val def = getDefineList(sf.getDef())
def.ifEmpty {
"分析失败:可能输入有错误!"
}
} catch (e: Exception) {
e.printStackTrace().toString()
}
useList = try {
getUseList(sf.getUse())
} catch (e: Exception) {
e.printStackTrace().toString()
}
val relations = mutableMapOf<String, List<Relation>>()
val traceTreeStr = StringBuilder()
sf.functions.forEach { func ->
traceTreeStr.append(getTraceTreeString(func.getTraceTree().getStringRepr(),func.name))
relations.putAll(parseRelation(func.name,func.getTraceTree().getStringRepr()))
}
traceTree = traceTreeStr.toString()
funcTraceTree =
getInvokeTraceTreeString("main",sf,relations)
ttGraph = generateGraph(relations)
ivGraph = sf.functions.getInvokeGraph("main")
showResult.value = true
}
}
}
}
}
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
App()

View file

@ -127,16 +127,14 @@ fun List<CFunction>.find(name: String): CFunction? {
* @param name: 从哪个函数开始查找
* @return 特制的 TraceTree
*/
fun List<CFunction>.getInvokeTree(name: String): List<TraceTree> {
fun List<CFunction>.getInvokeTree(name: String): Map<String,List<TraceTree>> {
// 先找到开始的函数
val func = this.find(name)
if (func == null) {
return emptyList()
}
val func = this.find(name) ?: return emptyMap()
val invokeTrees = mutableListOf<TraceTree>()
val args = mutableListOf<String>()
var funcName = ""
val resultMap = mutableMapOf<String,List<TraceTree>>()
func.cParser.sentenceList.forEach { sentence ->
// 🌰:
@ -153,9 +151,12 @@ fun List<CFunction>.getInvokeTree(name: String): List<TraceTree> {
val tt = function.getTraceTree(info)
invokeTrees.addAll(tt)
}
if (funcName != "") {
resultMap[funcName] = invokeTrees
args.clear()
funcName = ""
}
}
return invokeTrees
}
return resultMap
}

View file

@ -24,8 +24,8 @@ fun generateGraph(relations: Map<String, List<Relation>>, crossLabelPaths: List<
// 处理跨函数
for (path in crossLabelPaths) {
val parts = path.split(":")
if (parts.size == 2) {
val subPath = parts[1].split("->") // 栗子: main:z->a->m
if (parts.size == 3) {
val subPath = parts[2].split("->") // 栗子: A:main:z->a->m
if (subPath.size >= 2) {
val fromNode = subPath[0] // 这里就是z
val toNode = subPath[1] // 下一个就是

View file

@ -4,6 +4,8 @@ package core
import java.io.File
import core.CLanguage.Companion.OPERATION.*
import utils.getDefineList
import utils.getUseList
class SourceFile {
companion object {
@ -20,7 +22,7 @@ class SourceFile {
}
val content: String
private var functions: List<CFunction> = emptyList()
var functions: List<CFunction> = emptyList()
constructor(file: File) {
if (!file.isFile) {
@ -52,8 +54,8 @@ class SourceFile {
return result
}
fun getUse(): List<List<String>> {
val globalResult = mutableListOf<List<String>>()
fun getUse(): Map<String,List<String>> {
val globalResult = mutableMapOf<String,List<String>>()
functions.forEach {
val funcResult = mutableListOf<String>()
@ -97,7 +99,7 @@ class SourceFile {
if (useCache.isNotEmpty()) {
funcResult.add(useCache.toString())
}
globalResult.add(funcResult)
globalResult[it.name] = funcResult
}
return globalResult
}
@ -120,4 +122,7 @@ fun main() {
println(sourceFile.getUse())
println(generateGraph(relations))
println(funcs.getInvokeGraph("main"))
println(getDefineList(sourceFile.getDef()))
println(getUseList(sourceFile.getUse()))
}

View file

@ -47,7 +47,12 @@ fun List<TraceTree>.getStringRepr(): String {
return result.toString()
}
fun List<TraceTree>.getFuncRepr(func: String): String {
val strs = this.getStringRepr()
return strs.split('\n').filter { it.startsWith(func) }.joinToString("\n")
fun Map<String, List<TraceTree>>.getFuncRepr(func: String): String {
val result = StringBuilder()
this.forEach { (name, list) ->
result.append("$name:")
val listRepr = list.getStringRepr()
result.append(listRepr.split('\n').filter { it.startsWith(func) }.joinToString("\n"))
}
return result.toString()
}

View file

@ -0,0 +1,154 @@
package ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import core.SourceFile
import utils.DefaultCode
@OptIn(ExperimentalTextApi::class)
@Composable
fun TextfieldWithLineNumber(
modifier: Modifier = Modifier,
onSubmit: (String) -> Unit
) {
var linesText by remember { mutableIntStateOf(DefaultCode.hashCode()) }
var text by remember { mutableStateOf(DefaultCode.toString()) }
val showFinishFormatDialog = remember { mutableStateOf(false) }
when {
showFinishFormatDialog.value -> {
FinishFormatDialog {
showFinishFormatDialog.value = false
}
}
}
val monospaceTextStyle = TextStyle.Default.copy( // 左右都是等宽字体
fontFamily = FontFamily("monospace"),
fontSize = 16.sp
)
// 同步左右滚动进度
val linesTextScroll = rememberScrollState()
val scriptTextScroll = rememberScrollState()
LaunchedEffect(linesTextScroll.value) {
scriptTextScroll.scrollTo(linesTextScroll.value)
}
LaunchedEffect(scriptTextScroll.value) {
linesTextScroll.scrollTo(scriptTextScroll.value)
}
Column(modifier = modifier) {
Row(
modifier = Modifier.fillMaxWidth()
.weight(1f)
.background(color = Color(0xFFfafafa))
) {
// 左边是行号
BasicTextField(
modifier = Modifier
.fillMaxHeight()
.width(12.dp * linesText.toString().length)
.verticalScroll(linesTextScroll),
value = IntRange(1, linesText).joinToString(separator = "\n"),
readOnly = true, // 不能去编辑行号那里
textStyle = monospaceTextStyle.copy(
textAlign = TextAlign.End,
color = Color(0xff69b0c5)
),
onValueChange = {})
Spacer(modifier = Modifier.width(10.dp))
// 输入内容的地方
BasicTextField(
modifier = Modifier
.fillMaxHeight()
.weight(1f)
.verticalScroll(scriptTextScroll),
value = text,
textStyle = monospaceTextStyle,
onValueChange = { textFieldValue ->
val nbLines = textFieldValue.count { it == '\n' } + 1
if (nbLines != linesText) linesText = nbLines
text = textFieldValue.replace("\t"," ") // \t 显示不了
},
)
}
}
Row(
modifier = Modifier.fillMaxWidth(0.9f)
.padding(vertical = 5.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
Button(
modifier = Modifier.padding(vertical = 10.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFC6E7FF)),
onClick = {
val s = SourceFile(text)
text = s.content
showFinishFormatDialog.value = true
},
) {
Text("格式化")
}
Button(
modifier = Modifier.padding(vertical = 10.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFD4F6FF)),
onClick = { onSubmit(text) },
) {
Text("分析")
}
}
}
@Composable
fun FinishFormatDialog(onDismissRequest: () -> Unit) {
Dialog(onDismissRequest = { onDismissRequest() }) {
Card(
modifier = Modifier
.height(130.dp)
.padding(16.dp),
shape = RoundedCornerShape(20.dp),
backgroundColor = Color(0xffFFE3E3)
) {
Text(
text = "格式化成功",
modifier = Modifier
.fillMaxSize()
.wrapContentSize(Alignment.Center),
textAlign = TextAlign.Center,
)
}
}
}

View file

@ -0,0 +1,25 @@
package utils
object DefaultCode {
override fun toString(): String {
return """
int main(){
int x=0,y =0;
int z =1;
printf("%d\n",z);//用户输入
x= A(z);
y= x;
printf("%d\n",y);//main函数尾部
}
int A(int a){
int m = a;
return m;
}
""".trimIndent()
}
override fun hashCode(): Int {
return this.toString().count { it == '\n' } + 1
}
}

View file

@ -0,0 +1,23 @@
package utils
import java.awt.Desktop
import java.net.URI
import java.util.*
fun openBrowser(uri: URI) {
val osName by lazy(LazyThreadSafetyMode.NONE) { System.getProperty("os.name").lowercase(Locale.getDefault()) }
val desktop = Desktop.getDesktop()
when {
Desktop.isDesktopSupported() && desktop.isSupported(Desktop.Action.BROWSE) -> desktop.browse(uri)
"mac" in osName -> Runtime.getRuntime().exec("open $uri")
"nix" in osName || "nux" in osName -> Runtime.getRuntime().exec("xdg-open $uri")
else -> desktop.browse(uri)
}
}
fun openGraph(graph: String){
val site = "https://dreampuf.github.io/GraphvizOnline/#"
val data = java.net.URLEncoder.encode(graph,"utf-8")
.replace("+","%20")
openBrowser(URI.create(site+data))
}

View file

@ -0,0 +1,37 @@
package utils
import core.*
fun getDefineList(defList: Map<String, List<String>>): String =
// Example:
// {main=[x, y, z], A=[a, m]}
defList.toString()
.replace("{", "")
.replace("}", "") // 解决左右括号
.replace("=", ":def")
fun getUseList(useList: Map<String, List<String>>): String =
// Example:
// {main=[void, x-def, y-def, z-def, z-use, x-def;z-use, y-def;x-use, y-use], A=[a-def, m-def;a-use, m-use]}
useList.toString()
.replace("{}", "") // 如果是空就直接删了
.replace("{", "") // 右括号留着
.replace("=", ":{") // 换掉
.replace("], ", "]}\n") // 保证不是最后一个
.replace(", ", "],[") // 逗号后面有空格
.replace(";", "")
fun getTraceTreeString(traceTreeStr: String, funcName: String): String {
val sb = StringBuilder("$funcName:\n")
traceTreeStr.split('\n').forEach {
sb.append(" ${it.trim()}\n")
}
return sb.toString()
}
fun getInvokeTraceTreeString(funcName: String, sourceFile: SourceFile, relations: Map<String, List<Relation>>): String {
val func = sourceFile.functions.find(funcName) ?: return "未找到 $funcName 函数"
val originPart = getTraceTreeString(func.getTraceTree().getStringRepr(), func.name)
val invokeTree = sourceFile.functions.getInvokeTree(funcName).getFuncRepr(funcName)
return originPart + "\n" + invokeTree
}