Compare commits

...

4 commits

Author SHA1 Message Date
2fd68e991f feat: Qodana check 2024-10-31 23:54:39 +08:00
3b9bb4df88 feat: Qodana check 2024-10-31 23:54:07 +08:00
8402dc68b9 chore: doc 2024-10-31 23:48:39 +08:00
dfc9815e83 chore: fix style 2024-10-31 23:39:59 +08:00
6 changed files with 94 additions and 25 deletions

View file

@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration"> <component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" /> <file type="web" url="file://$PROJECT_DIR$" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" default="true" project-jdk-name="openjdk-22" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-22" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

31
qodana.yaml Normal file
View file

@ -0,0 +1,31 @@
#-------------------------------------------------------------------------------#
# Qodana analysis is configured by qodana.yaml file #
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
#-------------------------------------------------------------------------------#
version: "1.0"
#Specify inspection profile for code analysis
profile:
name: qodana.starter
#Enable inspections
#include:
# - name: <SomeEnabledInspectionId>
#Disable inspections
#exclude:
# - name: <SomeDisabledInspectionId>
# paths:
# - <path/where/not/run/inspection>
projectJDK: 23 #(Applied in CI/CD pipeline)
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
#bootstrap: sh ./prepare-qodana.sh
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
#plugins:
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
linter: jetbrains/qodana-jvm:latest

View file

@ -173,7 +173,7 @@ fun App() {
traceTree = traceTreeStr.toString() traceTree = traceTreeStr.toString()
funcTraceTree = funcTraceTree =
getInvokeTraceTreeString(sf,relations) getInvokeTraceTreeString(sf)
ttGraph = generateGraph(relations) ttGraph = generateGraph(relations)
ivGraph = sf.functions.getInvokeGraph() ivGraph = sf.functions.getInvokeGraph()

View file

@ -1,5 +1,3 @@
@file:Suppress("unused")
package core package core
import java.io.File import java.io.File
@ -11,6 +9,15 @@ class SourceFile {
companion object { companion object {
val function_define_regex = """\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*\{""".toRegex() // main(){ 匹配函数名 val function_define_regex = """\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*\{""".toRegex() // main(){ 匹配函数名
/**
* C文件预处理器
* 处理内容
* 删除注释;
* 处理 #define;
* 处理连续创建变量;
* 格式化代码
* @return 处理好的C源代码
*/
fun formatSource(src: String): String { fun formatSource(src: String): String {
// 去掉注释 // 去掉注释
val noComment = src.lines() val noComment = src.lines()
@ -21,7 +28,7 @@ class SourceFile {
} }
// 处理 DEFINE, 支持如下 // 处理 DEFINE, 支持如下
// #define SOMETHING ANOTHERTHING 这样的 // #define SOMETHING ANOTHER 这样的
// #define ADD(a, b) a + b // #define ADD(a, b) a + b
val noFuncInDefine = StringBuilder() val noFuncInDefine = StringBuilder()
// 获取 define 的内容 // 获取 define 的内容
@ -30,7 +37,7 @@ class SourceFile {
if (line.trim().startsWith("#define")) { if (line.trim().startsWith("#define")) {
val args = line.trim().split(" ") val args = line.trim().split(" ")
if (args.size >= 3) { if (args.size >= 3) {
if (args[1].contains("(")){ // Define Function if (args[1].contains("(")) { // Define Function
val defFuncName = args[1].split('(').first().trim() val defFuncName = args[1].split('(').first().trim()
val defineFuncArgs = args[1] val defineFuncArgs = args[1]
.split('(').last() .split('(').last()
@ -44,31 +51,31 @@ class SourceFile {
val prev = line.split("$defFuncName(") // 应该是调用之前的内容 val prev = line.split("$defFuncName(") // 应该是调用之前的内容
val later = prev.last().split(')') // 应该是调用之后的内容 val later = prev.last().split(')') // 应该是调用之后的内容
val callArgs = later.first().split(',').map { it.trim() } // 和上面一样的 val callArgs = later.first().split(',').map { it.trim() } // 和上面一样的
if (callArgs.size <= defineFuncArgs.size){ if (callArgs.size <= defineFuncArgs.size) {
var newFunction = defineFunc var newFunction = defineFunc
for (i in callArgs.indices){ // 参数不够不管了 for (i in callArgs.indices) { // 参数不够不管了
newFunction = newFunction.replace(defineFuncArgs[i],callArgs[i]) newFunction = newFunction.replace(defineFuncArgs[i], callArgs[i])
} }
//改回去 //改回去
noFuncInDefine.append(prev.first() + newFunction + later.last()) noFuncInDefine.append(prev.first() + newFunction + later.last())
noFuncInDefine.append('\n') noFuncInDefine.append('\n')
}else{ // 参数多了我有啥办法 } else { // 参数多了我有啥办法
noFuncInDefine.append(line) noFuncInDefine.append(line)
noFuncInDefine.append('\n') noFuncInDefine.append('\n')
} }
}else if (!line.startsWith('#')) { } else if (!line.startsWith('#')) {
noFuncInDefine.append(line) noFuncInDefine.append(line)
noFuncInDefine.append('\n') noFuncInDefine.append('\n')
} }
} }
}else { // #define SOMETHING ANOTHER 这样的 } else { // #define SOMETHING ANOTHER 这样的
simpleDefineList[args[1]] = args[2] simpleDefineList[args[1]] = args[2]
} }
} }
} }
} }
// 可能上面代码因为没define没执行这里保证下 // 可能上面代码因为没define没执行这里保证下
if (noFuncInDefine.isEmpty()){ if (noFuncInDefine.isEmpty()) {
noFuncInDefine.append(noComment) noFuncInDefine.append(noComment)
} }
@ -84,7 +91,7 @@ class SourceFile {
noDefine.append('\n') noDefine.append('\n')
} }
} }
}else{ } else {
noDefine.append(noFuncInDefine) noDefine.append(noFuncInDefine)
} }
@ -142,10 +149,14 @@ class SourceFile {
} }
constructor(content: String) { constructor(content: String) {
this.content = formatSource(content.trim()) this.content = formatSource(content)
} }
fun parseFunction(): List<CFunction> { // 找所有的函数定义 /**
* 找所有的函数定义
* @return 所有定义的函数
*/
fun parseFunction(): List<CFunction> {
val result = mutableListOf<CFunction>() val result = mutableListOf<CFunction>()
function_define_regex.findAll(content).forEach { function_define_regex.findAll(content).forEach {
if (it.groups.size >= 2 && it.groups[1] != null) { if (it.groups.size >= 2 && it.groups[1] != null) {
@ -156,7 +167,12 @@ class SourceFile {
return result return result
} }
fun getDef(): Map<String, List<String>> { // 获取所有的定义 /**
* 找所有的变量定义
* @return Map of<函数名称 to List<定义的变量>>
* @see utils.getDefineList
*/
fun getDef(): Map<String, List<String>> {
val result = mutableMapOf<String, List<String>>() val result = mutableMapOf<String, List<String>>()
functions.forEach { functions.forEach {
result[it.name] = it.cParser.defineList result[it.name] = it.cParser.defineList
@ -164,6 +180,11 @@ class SourceFile {
return result return result
} }
/**
* 任务1获取使用的值的情况
* @return Map of<函数 to List<使用值的情况>>
* @see utils.getUseList 获取要求的格式
*/
fun getUse(): Map<String, List<String>> { fun getUse(): Map<String, List<String>> {
val globalResult = mutableMapOf<String, List<String>>() val globalResult = mutableMapOf<String, List<String>>()
functions.forEach { functions.forEach {
@ -201,7 +222,7 @@ class SourceFile {
useCache.append("${sentence.left}-def") useCache.append("${sentence.left}-def")
} }
DEFINE_VALUE_PARAM, CHANGE_VALUE_PARAM -> { DEFINE_VALUE_PARAM, CHANGE_VALUE_PARAM -> { // 作为参数出现的
useCache.append(";${sentence.right}-use") useCache.append(";${sentence.right}-use")
} }
@ -217,17 +238,17 @@ class SourceFile {
} }
} }
fun main() { fun main() { // 测试用, NoGUI
val sourceFile = SourceFile(File("src/main/CTests/test.c")) val sourceFile = SourceFile(File("src/main/CTests/test.c"))
val funcs = sourceFile.parseFunction() val functions = sourceFile.parseFunction()
val relations = mutableMapOf<String, List<Relation>>() val relations = mutableMapOf<String, List<Relation>>()
funcs.forEach { functions.forEach {
relations.putAll(parseRelation(it.name, it.getTraceTree().getStringRepr())) relations.putAll(parseRelation(it.name, it.getTraceTree().getStringRepr()))
} }
for (function in funcs) { for (function in functions) {
println(funcs.getInvokeTree(function.name).getFuncRepr(function.name)) println(functions.getInvokeTree(function.name).getFuncRepr(function.name))
} }
println(generateGraph(relations)) println(generateGraph(relations))
println(funcs.getInvokeGraph()) println(functions.getInvokeGraph())
} }

View file

@ -1,6 +1,13 @@
package utils package utils
/**
* UI页面的默认代码
*/
@Suppress("EqualsOrHashCode")
object DefaultCode { object DefaultCode {
/**
* @return 默认代码
*/
override fun toString(): String { override fun toString(): String {
return """ return """
int main(){ int main(){
@ -19,7 +26,17 @@ object DefaultCode {
""".trimIndent() """.trimIndent()
} }
/**
* 我们借来测试行数
* @return 默认代码行数
*/
override fun hashCode(): Int { override fun hashCode(): Int {
return this.toString().count { it == '\n' } + 1 return this.toString().count { it == '\n' } + 1
} }
/**
* Fix:
* Qodana `Reports classes that override equals() but do not override hashCode(), or vice versa.`
*/
override fun equals(other: Any?) = false
} }

View file

@ -31,7 +31,7 @@ fun getTraceTreeString(traceTreeStr: String, funcName: String): String {
return sb.toString() return sb.toString()
} }
fun getInvokeTraceTreeString(sourceFile: SourceFile, relations: Map<String, List<Relation>>): String { fun getInvokeTraceTreeString(sourceFile: SourceFile): String {
val tree = StringBuilder() val tree = StringBuilder()
for (function in sourceFile.functions) { for (function in sourceFile.functions) {
val chain = sourceFile.functions.getInvokeTree(function.name).getFuncRepr(function.name) val chain = sourceFile.functions.getInvokeTree(function.name).getFuncRepr(function.name)