From 5303918a15a5300f3d6cde1d4d6e8553fc2e14fc Mon Sep 17 00:00:00 2001 From: zhangzhiyong Date: Tue, 27 Aug 2024 14:44:44 +0800 Subject: [PATCH] Code Map Update Test --- .../java/run/mone/neo4j/MoneCodeParser.java | 171 ++++++++++++++++-- .../mone/neo4j/test/MoneCodeParserTest.java | 2 + .../java/run/mone/neo4j/test/anno/Test.java | 8 + .../run/mone/neo4j/test/m/PersonService.java | 12 +- .../mone/neo4j/test/m/PersonServiceTest.java | 22 +++ .../neo4j/test/m/{ => cat}/CatService.java | 10 +- 6 files changed, 209 insertions(+), 16 deletions(-) create mode 100644 jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/anno/Test.java create mode 100644 jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonServiceTest.java rename jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/{ => cat}/CatService.java (60%) diff --git a/jcommon/ai/neo4j/src/main/java/run/mone/neo4j/MoneCodeParser.java b/jcommon/ai/neo4j/src/main/java/run/mone/neo4j/MoneCodeParser.java index aa83443de..df1647094 100644 --- a/jcommon/ai/neo4j/src/main/java/run/mone/neo4j/MoneCodeParser.java +++ b/jcommon/ai/neo4j/src/main/java/run/mone/neo4j/MoneCodeParser.java @@ -2,13 +2,16 @@ import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.comments.Comment; import com.github.javaparser.ast.comments.JavadocComment; -import com.github.javaparser.ast.expr.AnnotationExpr; +import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.nodeTypes.NodeWithName; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -326,11 +329,11 @@ private static void createProjectNode(Session session, String projectName) { /** * 查找具有指定注解的类 * - * @param session 数据库会话 + * @param session 数据库会话 * @param annotationToFind 要查找的注解 * @return 具有指定注解的类的列表,每个类以Map形式表示 */ - public List> findClassesWithAnnotation(Session session, String annotationToFind) { + public List> findClassesWithAnnotation(Session session, String annotationToFind) { Map params = new HashMap<>(); params.put("annotation", annotationToFind); Result result = session.run( @@ -339,7 +342,7 @@ public List> findClassesWithAnnotation(Session session, Stri "RETURN c", params ); - List> list = new ArrayList<>(); + List> list = new ArrayList<>(); while (result.hasNext()) { Record record = result.next(); System.out.println(record.get("c").asMap()); @@ -406,8 +409,6 @@ public void visit(ClassOrInterfaceDeclaration n, Void arg) { //注解 classParams.put("annotations", annoList); - System.out.println(classParams); - session.run( "MERGE (c:Class {name: $name}) " + "ON CREATE SET c.full_name = $fullName, c.type = $type, c.code = $code, c.anno = $annotations " + @@ -454,13 +455,135 @@ public void visit(ClassOrInterfaceDeclaration n, Void arg) { } + + private String getFullMethodName(MethodDeclaration method) { + String packageName = method.findCompilationUnit() + .flatMap(cu -> cu.getPackageDeclaration()) + .map(pd -> pd.getNameAsString()) + .orElse(""); + String className = method.findAncestor(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration.class) + .map(c -> c.getNameAsString()) + .orElse(""); + String methodName = method.getNameAsString(); + return packageName + "." + className + "." + methodName; + } + + /** + * 获取方法调用的完整路径,包括包名、类名和方法名 + * + * @param methodCall 方法调用表达式 + * @return 方法调用的完整路径 + */ + public String getFullMethodPath(MethodCallExpr methodCall) { + StringBuilder fullPath = new StringBuilder(); + + // 获取包名 + Optional cu = methodCall.findCompilationUnit(); + if (cu.isPresent()) { + cu.get().getPackageDeclaration().ifPresent(pkg -> + fullPath.append(pkg.getNameAsString()).append(".") + ); + } + + // 获取类名 + String className = methodCall.findAncestor(ClassOrInterfaceDeclaration.class) + .map(ClassOrInterfaceDeclaration::getNameAsString) + .orElse(""); + + // 获取方法调用的对象 + String objectName = methodCall.getScope() + .map(scope -> scope.toString()) + .orElse(""); + + + //静态调用 + if (methodCall.getScope().isPresent() && methodCall.getScope().get() instanceof FieldAccessExpr) { + return objectName + "." + methodCall.getNameAsString(); + } + + //lombok 的log + if (isLogCall(methodCall)) { + return objectName + "." + methodCall.getNameAsString(); + } + + // 如果对象名不为空,尝试找到它的类型 + if (!objectName.isEmpty()) { + Optional field = methodCall.findAncestor(ClassOrInterfaceDeclaration.class) + .flatMap(classDecl -> classDecl.getFieldByName(objectName)); + + if (field.isPresent()) { + ClassOrInterfaceType type = field.get().getVariable(0).getType().asClassOrInterfaceType(); + String v = resolveTypePath(type); + return v + "." + methodCall.getNameAsString(); + } + } + + + // 构建完整路径 + fullPath.append(className).append("."); + fullPath.append(methodCall.getNameAsString()); + + return fullPath.toString(); + } + + public static String resolveTypePath(ClassOrInterfaceType type) { + String typeName = type.getNameAsString(); + + Optional cu = type.findAncestor(CompilationUnit.class); + if (cu.isPresent()) { + // 尝试从导入声明中查找匹配 + Optional importedPath = findMatchingImport(cu.get(), typeName); + if (importedPath.isPresent()) { + return importedPath.get(); + } + + // 如果没有找到匹配的导入,检查是否在同一包中 + Optional currentPackage = getCurrentPackage(cu.get()); + if (currentPackage.isPresent()) { + return currentPackage.get() + "." + typeName; + } + } + + // 如果无法解析,返回原始类型名称 + return typeName; + } + + private static Optional findMatchingImport(CompilationUnit cu, String typeName) { + return cu.getImports().stream() + .filter(importDecl -> !importDecl.isAsterisk() && importDecl.getNameAsString().endsWith("." + typeName)) + .map(ImportDeclaration::getNameAsString) + .findFirst(); + } + + private static Optional getCurrentPackage(CompilationUnit cu) { + return cu.getPackageDeclaration().map(pd -> pd.getNameAsString()); + } + + /** + * 判断方法调用是否为日志调用 + * + * @param n 方法调用表达式 + * @return 如果方法调用是日志调用则返回true,否则返回false + */ + private boolean isLogCall(MethodCallExpr n) { + if (!n.getScope().isPresent()) { + return false; + } + String scope = n.getScope().get().toString(); + String method = n.getNameAsString(); + return scope.equals("log") && + (method.equals("trace") || method.equals("debug") || method.equals("info") || + method.equals("warn") || method.equals("error")); + } + + @Override public void visit(MethodDeclaration n, Void arg) { super.visit(n, arg); // 创建 Method 节点 Map methodParams = new HashMap<>(); - methodParams.put("name", n.getNameAsString()); + methodParams.put("name", getFullMethodName(n)); methodParams.put("signature", n.getSignature().asString()); methodParams.put("code_vector", new float[]{}); // 替换为实际的代码向量 @@ -474,7 +597,7 @@ public void visit(MethodDeclaration n, Void arg) { } declaresParams.put("className", n.findAncestor(ClassOrInterfaceDeclaration.class).get().getNameAsString()); - declaresParams.put("methodName", n.getNameAsString()); + declaresParams.put("methodName", getFullMethodName(n)); session.run("MATCH (c:Class {name: $className}) " + "MATCH (m:Method {name: $methodName}) " + @@ -482,6 +605,34 @@ public void visit(MethodDeclaration n, Void arg) { declaresParams); // 处理注释 + processComments(n); + + // 处理方法调用 + processMethodCalls(n); + + } + + // 处理方法调用 + private void processMethodCalls(MethodDeclaration n) { + n.findAll(MethodCallExpr.class).forEach(methodCall -> { + Map callParams = new HashMap<>(); + callParams.put("callerName", getFullMethodName(n)); + callParams.put("calleeName", getFullMethodPath(methodCall)); + + // 创建目标方法节点(如果不存在) + session.run("MERGE (callee:Method {name: $calleeName})", callParams); + + // 创建 CALLS 关系 + session.run("MATCH (caller:Method {name: $callerName}) " + + "MATCH (callee:Method {name: $calleeName}) " + + "MERGE (caller)-[:CALLS]->(callee)", + callParams); + }); + } + + + // 处理注释 + private void processComments(MethodDeclaration n) { for (Comment comment : n.getAllContainedComments()) { createCommentNode(comment, n); } @@ -495,7 +646,6 @@ public void visit(MethodDeclaration n, Void arg) { if (commentOptional.isPresent()) { createCommentNode(commentOptional.get(), n); } - } private void createCommentNode(Comment comment, MethodDeclaration n) { @@ -508,7 +658,7 @@ private void createCommentNode(Comment comment, MethodDeclaration n) { // 创建 DOCUMENTS 关系 (Comment -[:DOCUMENTS]-> Method) Map documentsParams = new HashMap<>(); documentsParams.put("commentText", comment.getContent()); - documentsParams.put("methodName", n.getNameAsString()); + documentsParams.put("methodName", getFullMethodName(n)); documentsParams.put("methodSignature", n.getSignature().asString()); session.run("MATCH (comment:Comment {text: $commentText}) " + "MATCH (m:Method {name: $methodName, signature: $methodSignature}) " + @@ -545,5 +695,4 @@ public String readResourceFileContent(String fileName) { } - } diff --git a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/MoneCodeParserTest.java b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/MoneCodeParserTest.java index 64577800a..440a1be06 100644 --- a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/MoneCodeParserTest.java +++ b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/MoneCodeParserTest.java @@ -43,6 +43,8 @@ public void testWriteCatServiceToNeo4j() { // MoneCodeParser.writeJavaFilesToNeo4j("/Users/zhangzhiyong/IdeaProjects/ai/m78/m78-service/src/main/java/run/mone/m78/service/database/SqlParseUtil.java"); // new MoneCodeParser().writeJavaFilesToNeo4j("/Users/zhangzhiyong/IdeaProjects/goodjava/mone/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/A.java"); new MoneCodeParser().setPassword(System.getenv("password")).writeJavaFilesToNeo4j("/Users/zhangzhiyong/IdeaProjects/goodjava/mone/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m"); +// new MoneCodeParser().setPassword(System.getenv("password")).writeJavaFilesToNeo4j("/Users/zhangzhiyong/IdeaProjects/goodjava/mone/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/CatService.java"); +// new MoneCodeParser().setPassword(System.getenv("password")).writeJavaFilesToNeo4j("/Users/zhangzhiyong/IdeaProjects/goodjava/mone/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonService.java"); } @Test diff --git a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/anno/Test.java b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/anno/Test.java new file mode 100644 index 000000000..a28757ccb --- /dev/null +++ b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/anno/Test.java @@ -0,0 +1,8 @@ +package run.mone.neo4j.test.anno; + +/** + * @author goodjava@qq.com + * @date 2024/8/21 16:06 + */ +public @interface Test { +} diff --git a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonService.java b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonService.java index a94ae0dfa..3201894ad 100644 --- a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonService.java +++ b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonService.java @@ -1,14 +1,16 @@ package run.mone.neo4j.test.m; +import lombok.extern.slf4j.Slf4j; import run.mone.neo4j.test.anno.Resource; -import run.mone.neo4j.test.anno.RestController; import run.mone.neo4j.test.anno.Service; +import run.mone.neo4j.test.m.cat.CatService; /** * @author goodjava@qq.com * @date 2024/8/16 10:16 */ @Service +@Slf4j public class PersonService { @@ -16,6 +18,14 @@ public class PersonService { private CatService catService; + //获取猫的数量 + public int getCatCount() { + log.info("info"); + System.out.println("abc"); + return catService.getCatCount(); + } + + /** * 计算两数之和 * diff --git a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonServiceTest.java b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonServiceTest.java new file mode 100644 index 000000000..a1ebd24a3 --- /dev/null +++ b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/PersonServiceTest.java @@ -0,0 +1,22 @@ +package run.mone.neo4j.test.m; + +import run.mone.neo4j.test.anno.Resource; +import run.mone.neo4j.test.anno.Service; +import run.mone.neo4j.test.anno.Test; + +/** + * @author goodjava@qq.com + * @date 2024/8/26 18:23 + */ +@Service +public class PersonServiceTest { + + @Resource + private PersonService personService; + + @Test + public void test1() { + int res = personService.getCatCount(); + System.out.println(res); + } +} diff --git a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/CatService.java b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/cat/CatService.java similarity index 60% rename from jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/CatService.java rename to jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/cat/CatService.java index 623cf6578..494c6776c 100644 --- a/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/CatService.java +++ b/jcommon/ai/neo4j/src/test/java/run/mone/neo4j/test/m/cat/CatService.java @@ -1,24 +1,26 @@ -package run.mone.neo4j.test.m; +package run.mone.neo4j.test.m.cat; -import run.mone.neo4j.test.anno.RestController; +import lombok.extern.slf4j.Slf4j; import run.mone.neo4j.test.anno.Service; import java.util.HashMap; -import java.util.Map; /** * @author goodjava@qq.com * @date 2024/8/19 18:21 */ @Service +@Slf4j public class CatService { - private Map data = new HashMap<>(); + private HashMap data = new HashMap<>(); //获取小猫的数量 //获取小猫的数量 public int getCatCount() { + log.info("abc"); + System.out.println("123"); return data.size(); }