From 2480865a1622fc97682137f14445685746642f25 Mon Sep 17 00:00:00 2001 From: chief Date: Mon, 18 Apr 2022 15:37:26 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9result=E7=9A=84?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=9C=BA=E5=88=B6=EF=BC=88=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=9B=AE=E5=89=8D=E6=AD=A3=E5=9C=A8=E8=BF=9B=E8=A1=8C=E8=BF=BD?= =?UTF-8?q?=E8=B8=AA=E7=9A=84=E6=B6=88=E6=81=AF=E7=9A=84=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=EF=BC=89=E3=80=82=E6=8E=A5=E4=B8=8B=E6=9D=A5=E5=9C=A8LOC488?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E5=88=86=E6=9E=90=E6=96=B9=E6=B3=95=E4=B8=AD?= =?UTF-8?q?=E7=94=A8=E5=88=B0=E7=9A=84=E5=85=B6=E4=BB=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdtocode/mapper/CodeMessageTracer.java | 61 +++++++++++-------- .../com/hy/java/uct/util/sd/UMLObject.java | 1 - 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java index 37d42f9..73647f5 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java +++ b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java @@ -41,9 +41,14 @@ public class CodeMessageTracer { */ public static List trace(Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { List res = new ArrayList<>(); - // 逐条追踪。不用追踪返回消息,只用它作为对应正向消息的参考。追踪完正向消息后返回消息的“返回起点”自然就是正向消息的最后一个带返回值的函数。 List msgs_inSD = objs_in_SD.getRight(); - for (Message msg_inSD : msgs_inSD) { + int msg_num = msgs_inSD.size(); + for (int msg_index = 0; msg_index < msg_num; msg_index++) { + res.add(msgs_inSD.get(msg_index)); + } + // 逐条追踪。不用追踪返回消息,只用它作为对应正向消息的参考。追踪完正向消息后返回消息的“返回起点”自然就是正向消息的最后一个带返回值的函数。 + for (int msg_index = 0; msg_index < msg_num; msg_index++) { + Message msg_inSD = res.get(msg_index); // 只追踪正向消息,不追踪返回消息 if (!msg_inSD.is_return) { /* @@ -59,7 +64,7 @@ public class CodeMessageTracer { * * 2)①在支撑类中找该属性的相关操作,对比每个操作与消息的语义相似度。比如new操作可以对应消息内容run。②对属性类型对应的类,找其中与消息内容语义相似的方法。 */ - traceByAttri(msg_inSD, res, objs_in_SD, classFullName_javaFileDir_map); + traceByAttri(msg_inSD, msg_index, res, classFullName_javaFileDir_map); /* * 2、第二种追踪:针对对象和方法 * @@ -69,7 +74,7 @@ public class CodeMessageTracer { * * 3)①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 */ - traceByMethod(msg_inSD, res, objs_in_SD, classFullName_javaFileDir_map); + traceByMethod(msg_inSD, msg_index, res, objs_in_SD, classFullName_javaFileDir_map); /* * 3、第三种追踪:针对消息 * @@ -81,7 +86,7 @@ public class CodeMessageTracer { * 3)对比链条两端与消息两端的对象。如果存在支撑类之类的关系,则认为消息两端应该是支撑类;否则仍保留链条两端作为消息两端。 */ if (msg_is_complex) { - traceByMsg(msg_inSD, res, objs_in_SD, classFullName_javaFileDir_map); + traceByMsg(msg_inSD, msg_index, res, objs_in_SD, classFullName_javaFileDir_map); } System.out.println("================================================================="); } @@ -118,8 +123,9 @@ public class CodeMessageTracer { * 2)①在支撑类中找该属性的相关操作,对比每个操作与消息的语义相似度。比如new操作可以对应消息内容run。②对属性类型对应的类,找其中与消息内容语义相似的方法。 * * @param msg_inSD + * @param msg_index */ - private static void traceByAttri(Message msg_inSD, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { + private static void traceByAttri(Message msg_inSD, int msg_index, List res, Map classFullName_javaFileDir_map) { System.out.println("①对于" + msg_inSD.msg + ",开始针对消息两端对象和代码中的属性进行追踪"); // 解析出msg中的方法名 String method_in_msg = parseMethodInMsg(msg_inSD.msg); @@ -163,16 +169,17 @@ public class CodeMessageTracer { for (Pair attri_p : sim_attris) { FieldDeclaration sim_attri = attri_p.getLeft(); // ①在支撑类中找该属性的相关操作,对比每个操作与消息的语义相似度。比如new操作可以对应消息内容run。 - trace_attri_in_supportingClsCode(sim_attri, attri_p.getRight(), clsCode_unit, msg_inSD, method_in_msg, res, uo_mapped_file_dir); + trace_attri_in_supportingClsCode(sim_attri, attri_p.getRight(), clsCode_unit, msg_inSD, msg_index, method_in_msg, uo_mapped_file_dir); // ②对属性类型对应的类,找其中与消息内容语义相似的方法。 Pair attri_clsCode = getAttriClsCode(sim_attri.getElementType().asString(), uo_mapped_file, uo_mapped_file_dir, classFullName_javaFileDir_map); - trace_attri_in_typeClsCode(sim_attri, attri_p.getRight(), attri_clsCode, msg_inSD, method_in_msg, res, clsCode_unit); + trace_attri_in_typeClsCode(sim_attri, attri_p.getRight(), attri_clsCode, msg_inSD, msg_index, method_in_msg, clsCode_unit); } } } catch (FileNotFoundException e) { e.printStackTrace(); } } + res.set(msg_index, msg_inSD); System.out.println("对于" + msg_inSD.msg + ",完成针对对象和属性的追踪了"); } @@ -290,10 +297,12 @@ public class CodeMessageTracer { * 3、如果包含,则分析改行内的方法是否与消息msg_inSD相似。 * * @param msg_inSD + * @param msg_index * * @param uo_mapped_file_dir + * @return */ - private static void trace_attri_in_supportingClsCode(FieldDeclaration sim_attri, Double attri_name_similarity, ClassOrInterfaceDeclaration clsCode_unit, Message msg_inSD, String msg, List res, String uo_mapped_file_dir) { + private static void trace_attri_in_supportingClsCode(FieldDeclaration sim_attri, Double attri_name_similarity, ClassOrInterfaceDeclaration clsCode_unit, Message msg_inSD, int msg_index, String msg, String uo_mapped_file_dir) { String[] clsCode_plainText = clsCode_unit.toString().split("\n"); /* * 1、按行读取支撑类clsCode_unit的文件内容。 @@ -344,11 +353,6 @@ public class CodeMessageTracer { } } } - if (res.contains(msg_inSD)) { - res.set(res.indexOf(msg_inSD), msg_inSD); - } else { - res.add(msg_inSD); - } System.out.println("检查完支撑类" + clsCode_unit.getNameAsString() + "中所有包含属性" + sim_attri.getVariable(0).getNameAsString() + "的代码行与消息" + msg + "的相似度了"); } @@ -425,9 +429,11 @@ public class CodeMessageTracer { * ②对属性类型对应的类,找其中与消息内容语义相似的方法。 * * @param msg_inSD + * @param msg_index * @param clsCode_unit + * @return */ - private static void trace_attri_in_typeClsCode(FieldDeclaration sim_attri, Double attri_name_sim, Pair attri_clsCode, Message msg_inSD, String msg, List res, ClassOrInterfaceDeclaration clsCode_unit) { + private static void trace_attri_in_typeClsCode(FieldDeclaration sim_attri, Double attri_name_sim, Pair attri_clsCode, Message msg_inSD, int msg_index, String msg, ClassOrInterfaceDeclaration clsCode_unit) { List methods_in_attriClsCode = attri_clsCode.getRight().getMethods(); for (MethodDeclaration md : methods_in_attriClsCode) { String md_name = md.getNameAsString(); @@ -440,11 +446,6 @@ public class CodeMessageTracer { msg_inSD.traced_path_ls.add(trace_path); } } - if (res.contains(msg_inSD)) { - res.set(res.indexOf(msg_inSD), msg_inSD); - } else { - res.add(msg_inSD); - } System.out.println("检查完支撑类" + clsCode_unit.getNameAsString() + "中属性" + sim_attri.getVariable(0).getNameAsString() + "的类型实现类中所有方法与" + msg + "的相似度了"); } @@ -458,9 +459,10 @@ public class CodeMessageTracer { * 3)①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 * * @param msg_inSD + * @param msg_index */ - private static void traceByMethod(Message msg_inSD, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { - System.out.println("①对于" + msg_inSD.msg + ",开始针对消息两端对象和代码中的方法进行追踪"); + private static void traceByMethod(Message msg_inSD, int msg_index, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { + System.out.println("②对于" + msg_inSD.msg + ",开始针对消息两端对象和代码中的方法进行追踪"); // 解析出msg中的方法名 String method_in_msg = parseMethodInMsg(msg_inSD.msg); /* @@ -504,7 +506,9 @@ public class CodeMessageTracer { String[] codes = body.toString().split("\n"); for (String code_line : codes) { List methods_in_codeLine = parseMethodsInCL(code_line.trim()); - System.out.println(methods_in_codeLine.toString()); + if (!methods_in_codeLine.isEmpty()) { + System.out.println(methods_in_codeLine.toString()); + } } } } @@ -527,6 +531,7 @@ public class CodeMessageTracer { e.printStackTrace(); } } + res.set(msg_index, msg_inSD); System.out.println("对于" + msg_inSD.msg + ",完成针对对象和方法的追踪了"); } @@ -541,10 +546,16 @@ public class CodeMessageTracer { * 3)对比链条两端与消息两端的对象。如果存在支撑类之类的关系,则认为消息两端应该是支撑类;否则仍保留链条两端作为消息两端。 * * @param msg_inSD + * @param msg_index * @param res */ - private static void traceByMsg(Message msg_inSD, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { - // TODO Auto-generated method stub + private static void traceByMsg(Message msg_inSD, int msg_index, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { + System.out.println("③对于" + msg_inSD.msg + ",开始针对消息内容进行追踪"); + /* + * + */ + res.set(msg_index, msg_inSD); + System.out.println("对于" + msg_inSD.msg + ",完成针对消息内容的追踪了"); } /** diff --git a/src/main/java/com/hy/java/uct/util/sd/UMLObject.java b/src/main/java/com/hy/java/uct/util/sd/UMLObject.java index 5dcdf64..abd7171 100644 --- a/src/main/java/com/hy/java/uct/util/sd/UMLObject.java +++ b/src/main/java/com/hy/java/uct/util/sd/UMLObject.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; import com.hy.java.uct.umlrecog.util.Rectangle; -import com.hy.java.uct.util.cd.UMLClass; public class UMLObject { /** -- Gitee From 963c1f5cdc4316470ec08494c7e70162ebe0b1d7 Mon Sep 17 00:00:00 2001 From: chief Date: Tue, 19 Apr 2022 15:42:48 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E7=9B=AE=E5=89=8D=E5=9C=A8=E7=AC=AC?= =?UTF-8?q?=E4=BA=8C=E7=A7=8D=E8=BF=BD=E8=B8=AA=EF=BC=88=E9=92=88=E5=AF=B9?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E5=92=8C=E6=96=B9=E6=B3=95=EF=BC=89=E4=B8=AD?= =?UTF-8?q?=EF=BC=8C=E5=B7=B2=E6=89=BE=E5=88=B0=E6=89=80=E6=9C=89=E4=B8=8E?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=9B=B8=E4=BC=BC=E7=9A=84=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E3=80=82=E6=8E=A5=E4=B8=8B=E6=9D=A5=E5=BC=80=E5=A7=8B=EF=BC=9A?= =?UTF-8?q?=E2=91=A0=E6=89=BE=E8=AF=A5=E6=96=B9=E6=B3=95=E5=86=85=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E6=9C=89=E5=AF=B9=E6=B6=88=E6=81=AF=E5=8F=A6=E4=B8=80?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E8=B0=83=E7=94=A8=EF=BC=8C=E5=A6=82=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E3=80=81=E6=96=B9=E6=B3=95=E5=86=85=E7=9A=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E3=80=81=E8=AF=AD=E5=8F=A5=E7=AD=89=E3=80=82=E2=91=A1?= =?UTF-8?q?=E5=AF=B9=E4=B8=8E=E6=B6=88=E6=81=AF=E7=9B=B8=E4=BC=BC=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8C=E6=89=BE=E5=88=B0=E5=85=B6=E6=89=80?= =?UTF-8?q?=E5=B1=9E=E7=9A=84=E7=B1=BB=EF=BC=8C=E5=9C=A8=E8=BF=99=E4=B8=AA?= =?UTF-8?q?=E7=B1=BB=E9=87=8C=E7=9C=8B=E8=AF=A5=E6=96=B9=E6=B3=95=E7=9A=84?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B=E6=98=AF=E5=90=A6=E4=B8=8E?= =?UTF-8?q?=E5=8F=A6=E4=B8=80=E7=AB=AF=E7=9B=B8=E4=BC=BC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/cdtocode/RelationTypeXlsReader.java | 2 +- .../java/uct/cdtocode/reader/CodeReader.java | 2 +- .../sdtocode/mapper/CodeMessageTracer.java | 147 ++++++++++++++---- .../java/uct/sdtocode/reader/CodeReader.java | 2 +- .../uct/umlrecog/ClassDiagramRecognizer.java | 2 +- .../umlrecog/SequenceDiagramRecognizer.java | 2 +- 6 files changed, 119 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/hy/java/uct/cdtocode/RelationTypeXlsReader.java b/src/main/java/com/hy/java/uct/cdtocode/RelationTypeXlsReader.java index fccb53c..cbedf05 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/RelationTypeXlsReader.java +++ b/src/main/java/com/hy/java/uct/cdtocode/RelationTypeXlsReader.java @@ -17,7 +17,7 @@ public class RelationTypeXlsReader { private static final String doc_dir = System.getProperty("user.dir") + "\\src\\main\\resources\\cdtocode\\doc\\"; public static void main(String[] args) { - FileNode srcdoc_fn = Traverser.traverseDir(doc_dir); + FileNode srcdoc_fn = Traverser.traverseDir(doc_dir, false); CountGroup cg = new CountGroup(); for (FileNode proj_dir_fn : srcdoc_fn.children) { if (!proj_dir_fn.path.contains("jetty")) { diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java index 4a96ad4..2cf143c 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java @@ -23,7 +23,7 @@ public class CodeReader { // 读取配置文件 FileEditor code_path_file = new FileEditor(code_path_file_path); // 配置文件指定的代码根目录所对应的FileNode。遍历其children下的java文件即可 - FileNode code_files_root = Traverser.traverseDir(code_path_file.readFileToString()); + FileNode code_files_root = Traverser.traverseDir(code_path_file.readFileToString(), false); // 遍历 System.out.println("正在遍历" + code_files_root.path + "下的源码文件,请稍候..."); filterJavaFileFromFN(code_files_root, result); diff --git a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java index 73647f5..13c5f72 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java +++ b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java @@ -23,6 +23,8 @@ import com.hy.java.uct.sdtocode.util.TracedMessagePath; import com.hy.java.uct.util.sd.Message; import com.hy.java.uct.util.sd.UMLObject; import com.hy.java.utility.common.Pair; +import com.hy.java.utility.common.Traverser; +import com.hy.java.utility.common.Traverser.FileNode; import com.hy.java.utility.common.Triple; /** @@ -34,6 +36,8 @@ import com.hy.java.utility.common.Triple; * * 第三种※:1)解析消息中的内容。将每个标识符对应为一个类或者一个方法。比如第一个标识符必须是类;后面的标识符如果是小写开头,那认为它是某个类型的变量名,所以在前面的标识符所属的类中找具有该名称的变量其所属的类。最终在最后一个标识符那儿找方法名。※注意:存在一种情况,即“前面的标识符所属的类中找不到后面的标识符”。所以应该对每个标识符与其下一个标识符都进行单独的查找,然后记录所有“ * 能从上一个标识符找到下一个标识符”的链条片段。将所有片段连接起来,断开的部分就直接放上对应的原消息内容即可。2)将由标识符链接起来的链条作为消息的追踪。记录链条两端。3)对比链条两端与消息两端的对象。如果存在支撑类之类的关系,则认为消息两端应该是支撑类;否则仍保留链条两端作为消息两端。 + * + * 注:搜索“这个阈值可以再改”,可查找所有经验阈值 */ public class CodeMessageTracer { /** @@ -393,7 +397,7 @@ public class CodeMessageTracer { } } else { // 这是些奇奇怪怪的字符串,可能有方法、也可能没有。看它跟消息像不像吧 - res.add(method_strs[i]); + res.add(method_strs[i].replaceAll("\"", "").replaceAll("!", "").trim()); } i++; } while (i < method_strs.length - 1); @@ -483,40 +487,19 @@ public class CodeMessageTracer { // 记录支撑类中的方法 List methods = clsCode_unit.getMethods(); // 记录方法逻辑中用到的其他方法 - List> method_code_sim = new ArrayList<>(); - - /* - * 记录方法逻辑中用到的其他方法 - * - * 记录方法逻辑中用到的其他方法 - * - * 记录方法逻辑中用到的其他方法 - * - * 记录方法逻辑中用到的其他方法 - * - * 记录方法逻辑中用到的其他方法 - * - * 记录方法逻辑中用到的其他方法 - */ - for (MethodDeclaration _method : methods) { - - Optional o_body = _method.getBody(); - if (o_body.isPresent()) { - BlockStmt body = o_body.get(); - String[] codes = body.toString().split("\n"); - for (String code_line : codes) { - List methods_in_codeLine = parseMethodsInCL(code_line.trim()); - if (!methods_in_codeLine.isEmpty()) { - System.out.println(methods_in_codeLine.toString()); - } - } - } - } + // 查找方法:记录uo_mapped_file中import的类和uo_mapped_file_dir同包中的类的所有方法,然后对比代码行中的同名方法,记录MethodDeclaration + List methods_in_importAndPackage = getAllMethodsInImportsAndPackage(uo_mapped_file, uo_mapped_file_dir, classFullName_javaFileDir_map); + List methods_in_codeLine = getAllMethodsWithinCodeLine(methods); + List> method_code_sim = getAllMethodsUsedByUO(methods_in_codeLine, methods_in_importAndPackage); /* * 2)计算每个方法与消息内容的语义相似度。找到相似的方法。 */ - for (MethodDeclaration _method : methods) { - + for (Triple tri : method_code_sim) { + double sim = jaccard_similarity(tri.getLeft().getNameAsString(), method_in_msg); + // 这个阈值可以再改 + if (sim > 0.5) { + tri.setRight(sim); + } } /* * 3)①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。 @@ -524,7 +507,12 @@ public class CodeMessageTracer { * ②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 */ for (Triple tri : method_code_sim) { - + if (tri.getRight() > 0.5) { + // ①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。 + System.out.println("找方法" + tri.getLeft().getNameAsString() + "内是否有对消息另一端" + target_uo.getTitle() + "的调用,如参数、方法内的变量、语句等。"); + // ②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 + System.out.println("看方法" + tri.getLeft().getNameAsString() + "的返回类型是否与另一端" + target_uo.getTitle() + "相似。"); + } } } } catch (FileNotFoundException e) { @@ -535,6 +523,99 @@ public class CodeMessageTracer { System.out.println("对于" + msg_inSD.msg + ",完成针对对象和方法的追踪了"); } + /** + * 记录uo_mapped_file中import的类和uo_mapped_file_dir同包中的类的所有方法 + */ + private static List getAllMethodsInImportsAndPackage(CompilationUnit uo_mapped_file, String uo_mapped_file_dir, Map classFullName_javaFileDir_map) { + List res = new ArrayList<>(); + List cls_path_ls = new ArrayList<>(); + /* + * 获取import中的所有类和uo_mapped_file_dir同包中的类的路径 + */ + // 获取import的所有类的路径 + NodeList imports = uo_mapped_file.getImports(); + for (ImportDeclaration _import : imports) { + String import_name = _import.getNameAsString(); + // 在classFullName_javaFileDir_map中找java文件 + if (classFullName_javaFileDir_map.containsKey(import_name)) { + cls_path_ls.add(classFullName_javaFileDir_map.get(import_name)); + } + } + // 获取uo_mapped_file_dir同包中的类的路径 + String package_dir = uo_mapped_file_dir.substring(0, uo_mapped_file_dir.lastIndexOf("\\")); + FileNode fn = Traverser.traverseDir(package_dir, false); + for (FileNode child : fn.children) { + if (child.path.substring(0, child.path.lastIndexOf("\\")).equals(package_dir)) { + cls_path_ls.add(child.path); + } + } + /* + * 记录cls_path_ls中所有类的所有方法 + */ + for (String path : cls_path_ls) { + if (path.endsWith(".java")) { + String short_name = path.substring(path.lastIndexOf("\\") + 1, path.lastIndexOf(".")); + try { + Optional o_class = StaticJavaParser.parse(new File(path)).getClassByName(short_name); + if (o_class.isPresent()) { + ClassOrInterfaceDeclaration clsCode = o_class.get(); + res.addAll(clsCode.getMethods()); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + return res; + } + + /** + * 获取方法内部逻辑中用到的其他方法 + */ + private static List getAllMethodsWithinCodeLine(List methods) { + List res = new ArrayList<>(); + for (MethodDeclaration _method : methods) { + Optional o_body = _method.getBody(); + if (o_body.isPresent()) { + BlockStmt body = o_body.get(); + String[] codes = body.toString().split("\n"); + for (String code_line : codes) { + List methods_in_codeLine = parseMethodsInCL(code_line.trim()); + if (!methods_in_codeLine.isEmpty()) { + for (String _method_in_codeLine : methods_in_codeLine) { + if (!_method_in_codeLine.isBlank()) { + if (_method_in_codeLine.startsWith("new ")) { + _method_in_codeLine = _method_in_codeLine.substring(4); + } + res.add(_method_in_codeLine.trim()); + } + } + } + } + } + } + return res; + } + + /** + * 对比代码行中的同名方法,记录MethodDeclaration + */ + private static List> getAllMethodsUsedByUO(List methods_in_codeLine, List methods_in_importAndPackage) { + List> res = new ArrayList<>(); + for (String method_in_codeLine : methods_in_codeLine) { + for (MethodDeclaration method_in_importAndPackage : methods_in_importAndPackage) { + if (method_in_codeLine.equals(method_in_importAndPackage.getNameAsString())) { + Optional o_body = method_in_importAndPackage.getBody(); + if (o_body.isPresent()) { + BlockStmt body = o_body.get(); + res.add(Triple.createTriple(method_in_importAndPackage, body.toString(), 0.0)); + } + } + } + } + return res; + } + /** * 第三种追踪:针对消息 * diff --git a/src/main/java/com/hy/java/uct/sdtocode/reader/CodeReader.java b/src/main/java/com/hy/java/uct/sdtocode/reader/CodeReader.java index 05f5465..c74b33d 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/reader/CodeReader.java +++ b/src/main/java/com/hy/java/uct/sdtocode/reader/CodeReader.java @@ -23,7 +23,7 @@ public class CodeReader { // 读取配置文件 FileEditor code_path_file = new FileEditor(code_path_file_path); // 配置文件指定的代码根目录所对应的FileNode。遍历其children下的java文件即可 - FileNode code_files_root = Traverser.traverseDir(code_path_file.readFileToString()); + FileNode code_files_root = Traverser.traverseDir(code_path_file.readFileToString(), false); // 遍历 System.out.println("正在遍历" + code_files_root.path + "下的源码文件,请稍候..."); filterJavaFileFromFN(code_files_root, result); diff --git a/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java index 99f4ea8..9ab813e 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java @@ -190,7 +190,7 @@ public class ClassDiagramRecognizer { // 用repo_name去查找图片时所使用的字符串 String search_string = cd_dir + "cd-" + repo_name.replaceAll("/", "_"); // 遍历cd_dir下的文件 - List cd_dir_files = Traverser.traverseDir(cd_dir).children; + List cd_dir_files = Traverser.traverseDir(cd_dir, false).children; for (FileNode cd_dir_file : cd_dir_files) { // 过滤掉result.txt文件,只找图片 if (cd_dir_file.path.equals(cd_dir + "result.txt")) { diff --git a/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java index 959e493..6ee1207 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java @@ -84,7 +84,7 @@ public class SequenceDiagramRecognizer { // 用repo_name去查找图片时所使用的字符串 String search_string = sd_dir + "sd-" + repo_name.replaceAll("/", "_"); // 遍历cd_dir下的文件 - List sd_dir_files = Traverser.traverseDir(sd_dir).children; + List sd_dir_files = Traverser.traverseDir(sd_dir, false).children; for (FileNode sd_dir_file : sd_dir_files) { // 过滤掉result.txt文件,只找图片 if (sd_dir_file.path.equals(sd_dir + "result.txt")) { -- Gitee From 7e7685d524f1cac2c3ae1656f16b8e0d3ff6384b Mon Sep 17 00:00:00 2001 From: chief Date: Tue, 19 Apr 2022 17:06:04 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=89=BE=E5=88=B0=E4=BA=86=E6=89=80?= =?UTF-8?q?=E6=9C=89=E8=87=AA=E8=BA=AB=E6=96=B9=E6=B3=95=E3=80=81=E8=87=AA?= =?UTF-8?q?=E8=BA=AB=E6=96=B9=E6=B3=95=E5=86=85=E7=94=A8=E5=88=B0=E7=9A=84?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E6=96=B9=E6=B3=95=E3=80=81=E5=86=85=E9=83=A8?= =?UTF-8?q?=E7=B1=BB=E4=B8=AD=E7=9A=84=E6=96=B9=E6=B3=95=E3=80=82=E6=8E=A5?= =?UTF-8?q?=E4=B8=8B=E6=9D=A5=E4=BB=8ELOC511=E5=BC=80=E5=A7=8B=E8=BF=BD?= =?UTF-8?q?=E8=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdtocode/mapper/CodeMessageTracer.java | 102 +++++++++++------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java index 13c5f72..1a7abe4 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java +++ b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java @@ -486,11 +486,11 @@ public class CodeMessageTracer { ClassOrInterfaceDeclaration clsCode_unit = o_class.get(); // 记录支撑类中的方法 List methods = clsCode_unit.getMethods(); - // 记录方法逻辑中用到的其他方法 - // 查找方法:记录uo_mapped_file中import的类和uo_mapped_file_dir同包中的类的所有方法,然后对比代码行中的同名方法,记录MethodDeclaration - List methods_in_importAndPackage = getAllMethodsInImportsAndPackage(uo_mapped_file, uo_mapped_file_dir, classFullName_javaFileDir_map); - List methods_in_codeLine = getAllMethodsWithinCodeLine(methods); - List> method_code_sim = getAllMethodsUsedByUO(methods_in_codeLine, methods_in_importAndPackage); + // 解析方法逻辑中用到的方法;然后记录uo_mapped_file中import的类、uo_mapped_file_dir同包中的类、内部类中的所有方法。然后对比代码行中的同名方法,记录MethodDeclaration + List> methods_in_codeLine = getAllMethodsWithinCodeLine(methods); + List methods_in_ImportsPackageInnerCls = getAllMethodsInImportsAndPackage(uo_mapped_file, uo_mapped_file_dir, classFullName_javaFileDir_map); + // 对比代码行中的同名方法。顺便也把支撑类中的方法存进去 + List> method_code_sim = getAllMethodsUsedByUO(methods, methods_in_codeLine, methods_in_ImportsPackageInnerCls); /* * 2)计算每个方法与消息内容的语义相似度。找到相似的方法。 */ @@ -509,9 +509,9 @@ public class CodeMessageTracer { for (Triple tri : method_code_sim) { if (tri.getRight() > 0.5) { // ①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。 - System.out.println("找方法" + tri.getLeft().getNameAsString() + "内是否有对消息另一端" + target_uo.getTitle() + "的调用,如参数、方法内的变量、语句等。"); + System.out.println("找" + tri.getMid() + "中的方法" + tri.getLeft().getNameAsString() + "内是否有对消息另一端" + target_uo.getTitle() + "的调用,如参数、方法内的变量、语句等。"); // ②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 - System.out.println("看方法" + tri.getLeft().getNameAsString() + "的返回类型是否与另一端" + target_uo.getTitle() + "相似。"); + System.out.println("看" + tri.getMid() + "中的方法" + tri.getLeft().getNameAsString() + "的返回类型是否与另一端" + target_uo.getTitle() + "相似。"); } } } @@ -523,6 +523,36 @@ public class CodeMessageTracer { System.out.println("对于" + msg_inSD.msg + ",完成针对对象和方法的追踪了"); } + /** + * 获取方法内部逻辑中用到的其他方法 + * + * Pair<代码行,方法> + */ + private static List> getAllMethodsWithinCodeLine(List methods) { + List> res = new ArrayList<>(); + for (MethodDeclaration _method : methods) { + Optional o_body = _method.getBody(); + if (o_body.isPresent()) { + BlockStmt body = o_body.get(); + String[] codes = body.toString().split("\n"); + for (String code_line : codes) { + List methods_in_codeLine = parseMethodsInCL(code_line.trim()); + if (!methods_in_codeLine.isEmpty()) { + for (String _method_in_codeLine : methods_in_codeLine) { + if (!_method_in_codeLine.isBlank()) { + if (_method_in_codeLine.startsWith("new ")) { + _method_in_codeLine = _method_in_codeLine.substring(4); + } + res.add(Pair.createPair(code_line, _method_in_codeLine.trim())); + } + } + } + } + } + } + return res; + } + /** * 记录uo_mapped_file中import的类和uo_mapped_file_dir同包中的类的所有方法 */ @@ -566,30 +596,19 @@ public class CodeMessageTracer { } } } - return res; - } - - /** - * 获取方法内部逻辑中用到的其他方法 - */ - private static List getAllMethodsWithinCodeLine(List methods) { - List res = new ArrayList<>(); - for (MethodDeclaration _method : methods) { - Optional o_body = _method.getBody(); - if (o_body.isPresent()) { - BlockStmt body = o_body.get(); - String[] codes = body.toString().split("\n"); - for (String code_line : codes) { - List methods_in_codeLine = parseMethodsInCL(code_line.trim()); - if (!methods_in_codeLine.isEmpty()) { - for (String _method_in_codeLine : methods_in_codeLine) { - if (!_method_in_codeLine.isBlank()) { - if (_method_in_codeLine.startsWith("new ")) { - _method_in_codeLine = _method_in_codeLine.substring(4); - } - res.add(_method_in_codeLine.trim()); - } - } + /* + * ※额外可选:获取uo_mapped_file的内部类中的方法 + */ + String[] code_lines = uo_mapped_file.toString().split("\n"); + String uo_short_name = uo_mapped_file_dir.substring(uo_mapped_file_dir.lastIndexOf("\\") + 1, uo_mapped_file_dir.lastIndexOf(".")); + for (String code_line : code_lines) { + if (code_line.contains("class ")) { + String temp = code_line.substring(code_line.indexOf("class ") + 6); + String possible_innerCls_name = temp.substring(0, temp.indexOf(" ")); + if (!possible_innerCls_name.equals(uo_short_name)) { + List inner_class_declaration = uo_mapped_file.getLocalDeclarationFromClassname(possible_innerCls_name); + if (!inner_class_declaration.isEmpty()) { + res.addAll(inner_class_declaration.get(0).getMethods()); } } } @@ -599,17 +618,20 @@ public class CodeMessageTracer { /** * 对比代码行中的同名方法,记录MethodDeclaration + * + * Triple<方法,在uo中用到该方法的代码行,相似度> + * + * @param methods */ - private static List> getAllMethodsUsedByUO(List methods_in_codeLine, List methods_in_importAndPackage) { + private static List> getAllMethodsUsedByUO(List methods, List> methods_in_codeLine, List methods_in_importAndPackage) { List> res = new ArrayList<>(); - for (String method_in_codeLine : methods_in_codeLine) { + for (MethodDeclaration _method : methods) { + res.add(Triple.createTriple(_method, _method.getDeclarationAsString(), 0.0)); + } + for (Pair method_in_codeLine : methods_in_codeLine) { for (MethodDeclaration method_in_importAndPackage : methods_in_importAndPackage) { - if (method_in_codeLine.equals(method_in_importAndPackage.getNameAsString())) { - Optional o_body = method_in_importAndPackage.getBody(); - if (o_body.isPresent()) { - BlockStmt body = o_body.get(); - res.add(Triple.createTriple(method_in_importAndPackage, body.toString(), 0.0)); - } + if (method_in_codeLine.getRight().equals(method_in_importAndPackage.getNameAsString())) { + res.add(Triple.createTriple(method_in_importAndPackage, method_in_codeLine.getLeft(), 0.0)); } } } @@ -664,7 +686,7 @@ public class CodeMessageTracer { public static void save(List trace_msgs, String string) { for (Message msg : trace_msgs) { for (TracedMessagePath traced_path : msg.traced_path_ls) { - for (Triple tri : traced_path.path) { + for (Triple tri : traced_path.path) { System.out.println(msg.msg + "有" + tri.getRight() + "概率追踪到" + tri.getLeft() + "的代码段" + tri.getMid()); } } -- Gitee From 6ad80a2bb030493c85574e3670483622efe9a112 Mon Sep 17 00:00:00 2001 From: chief Date: Tue, 26 Apr 2022 10:50:22 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E5=B7=B2=E5=AE=8C=E6=88=90=E7=AC=AC?= =?UTF-8?q?=E4=BA=8C=E7=A7=8D=E8=BF=BD=E8=B8=AA=E3=80=82=E5=BC=80=E5=A7=8B?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E7=A7=8D=E8=BF=BD=E8=B8=AA=EF=BC=88LOC715?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdtocode/mapper/CodeMessageTracer.java | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java index 1a7abe4..e6f7445 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java +++ b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java @@ -18,6 +18,7 @@ import com.github.javaparser.ast.NodeList; 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.body.Parameter; import com.github.javaparser.ast.stmt.BlockStmt; import com.hy.java.uct.sdtocode.util.TracedMessagePath; import com.hy.java.uct.util.sd.Message; @@ -486,7 +487,7 @@ public class CodeMessageTracer { ClassOrInterfaceDeclaration clsCode_unit = o_class.get(); // 记录支撑类中的方法 List methods = clsCode_unit.getMethods(); - // 解析方法逻辑中用到的方法;然后记录uo_mapped_file中import的类、uo_mapped_file_dir同包中的类、内部类中的所有方法。然后对比代码行中的同名方法,记录MethodDeclaration + // 解析方法逻辑中用到的方法:uo_mapped_file中import的类、uo_mapped_file_dir同包中的类、内部类中的所有方法;对比代码行中的同名方法。记录MethodDeclaration List> methods_in_codeLine = getAllMethodsWithinCodeLine(methods); List methods_in_ImportsPackageInnerCls = getAllMethodsInImportsAndPackage(uo_mapped_file, uo_mapped_file_dir, classFullName_javaFileDir_map); // 对比代码行中的同名方法。顺便也把支撑类中的方法存进去 @@ -509,9 +510,9 @@ public class CodeMessageTracer { for (Triple tri : method_code_sim) { if (tri.getRight() > 0.5) { // ①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。 - System.out.println("找" + tri.getMid() + "中的方法" + tri.getLeft().getNameAsString() + "内是否有对消息另一端" + target_uo.getTitle() + "的调用,如参数、方法内的变量、语句等。"); + checkIfCall(tri, target_uo.getTitle(), msg_inSD, uo_mapped_file_dir); // ②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 - System.out.println("看" + tri.getMid() + "中的方法" + tri.getLeft().getNameAsString() + "的返回类型是否与另一端" + target_uo.getTitle() + "相似。"); + checkIfReturn(tri, target_uo.getTitle(), msg_inSD, uo_mapped_file_dir); } } } @@ -638,6 +639,63 @@ public class CodeMessageTracer { return res; } + /** + * ①找该方法内是否有对消息另一端的调用,如参数、方法内的变量、语句等。 + */ + private static void checkIfCall(Triple tri, String target_title, Message msg_inSD, String uo_mapped_file_dir) { + MethodDeclaration md = tri.getLeft(); + /* + * 找方法的参数是否有对消息另一端的调用 + */ + double parameter_sim = 0.0; + NodeList ps = md.getParameters(); + for (Parameter p : ps) { + double temp = jaccard_similarity(p.getTypeAsString(), target_title); + parameter_sim = temp > parameter_sim ? temp : parameter_sim; + temp = jaccard_similarity(p.getNameAsString(), target_title); + parameter_sim = temp > parameter_sim ? temp : parameter_sim; + } + /* + * 找方法中的语句、变量是否有对消息另一端的调用 + */ + double codeLine_sim = 0.0; + Optional o_body = md.getBody(); + if (o_body.isPresent()) { + BlockStmt body = o_body.get(); + String[] codes = body.toString().split("\n"); + for (String code_line : codes) { + if (code_line.contains(target_title)) { + codeLine_sim = 1.0; + break; + } + } + } + /* + * 根据相似度决定是否追踪到此方法 + */ + // 这个阈值可以再改 + if (parameter_sim > 0.3 || codeLine_sim > 0.3) { + TracedMessagePath trace_path = new TracedMessagePath(); + double max = parameter_sim > codeLine_sim ? parameter_sim : codeLine_sim; + trace_path.path.add(Triple.createTriple(uo_mapped_file_dir, tri.getMid().trim(), tri.getRight() * max)); + msg_inSD.traced_path_ls.add(trace_path); + } + } + + /** + * ②对与消息相似的方法,找到其所属的类,在这个类里看该方法的返回类型是否与另一端相似。 + */ + private static void checkIfReturn(Triple tri, String target_title, Message msg_inSD, String uo_mapped_file_dir) { + MethodDeclaration md = tri.getLeft(); + double returnType_sim = jaccard_similarity(md.getTypeAsString(), target_title); + // 这个阈值可以再改 + if (returnType_sim > 0.5) { + TracedMessagePath trace_path = new TracedMessagePath(); + trace_path.path.add(Triple.createTriple(uo_mapped_file_dir, tri.getMid().trim(), tri.getRight() * returnType_sim)); + msg_inSD.traced_path_ls.add(trace_path); + } + } + /** * 第三种追踪:针对消息 * @@ -655,8 +713,18 @@ public class CodeMessageTracer { private static void traceByMsg(Message msg_inSD, int msg_index, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { System.out.println("③对于" + msg_inSD.msg + ",开始针对消息内容进行追踪"); /* - * + * 1)解析消息中的内容。将每个标识符对应为一个类或者一个方法。比如第一个标识符必须是类;后面的标识符如果是小写开头,那认为它是某个类型的变量名,所以在前面的标识符所属的类中找具有该名称的变量其所属的类。最终在最后一个标识符那儿找方法名。※注意:存在一种情况,即“前面的标识符所属的类中找不到后面的标识符”。所以应该对每个标识符与其下一个标识符都进行单独的查找,然后记录所有“ + * 能从上一个标识符找到下一个标识符”的链条片段。将所有片段连接起来,断开的部分就直接放上对应的原消息内容即可。 + */ + System.out.println("☆☆☆☆☆☆☆\n对于" + msg_inSD.msg + ",解析消息中的内容"); + /* + * 2)将由标识符链接起来的链条作为消息的追踪。记录链条两端。 + */ + System.out.println("对于" + msg_inSD.msg + ",将由标识符链接起来的链条作为消息的追踪"); + /* + * 3)对比链条两端与消息两端的对象。如果存在支撑类之类的关系,则认为消息两端应该是支撑类;否则仍保留链条两端作为消息两端。 */ + System.out.println("对于" + msg_inSD.msg + ",对比链条两端与消息两端的对象\n☆☆☆☆☆☆☆"); res.set(msg_index, msg_inSD); System.out.println("对于" + msg_inSD.msg + ",完成针对消息内容的追踪了"); } -- Gitee From e22445d01002d3a4d4ccaa4500728e916963c91c Mon Sep 17 00:00:00 2001 From: chief Date: Sat, 7 May 2022 16:00:47 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E2=91=A0=E5=B7=B2=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E7=A7=8D=E8=BF=BD=E8=B8=AA=EF=BC=88=E9=92=88?= =?UTF-8?q?=E5=AF=B9=E5=B1=9E=E6=80=A7=EF=BC=89=E3=80=82=E2=91=A1=E5=B7=B2?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=AC=AC=E4=BA=8C=E7=A7=8D=E8=BF=BD=E8=B8=AA?= =?UTF-8?q?=EF=BC=88=E8=BF=99=E5=AF=B9=E6=96=B9=E6=B3=95=EF=BC=89=E3=80=82?= =?UTF-8?q?=E2=91=A2=E7=AC=AC=E4=B8=89=E7=A7=8D=E8=BF=BD=E8=B8=AA=EF=BC=88?= =?UTF-8?q?=E9=92=88=E5=AF=B9=E6=B6=88=E6=81=AF=EF=BC=89=EF=BC=9A=E9=92=88?= =?UTF-8?q?=E5=AF=B9=E6=AF=8F=E4=B8=AA=E6=A0=87=E8=AF=86=E7=AC=A6=EF=BC=8C?= =?UTF-8?q?=E5=B7=B2=E6=89=BE=E5=88=B0=E4=BB=A3=E7=A0=81=E4=B8=AD=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84java=E6=96=87=E4=BB=B6=E3=80=82=E6=8E=A5?= =?UTF-8?q?=E4=B8=8B=E6=9D=A5=E8=AE=B0=E5=BD=95=E6=B6=88=E6=81=AF=E4=B8=A4?= =?UTF-8?q?=E7=AB=AF=E4=BD=9C=E4=B8=BA=E8=BF=BD=E8=B8=AA=E3=80=81=E4=B8=AD?= =?UTF-8?q?=E9=97=B4=E9=93=BE=E6=9D=A1=E5=81=9A=E6=95=B4=E5=90=88=E5=8D=B3?= =?UTF-8?q?=E5=8F=AF=E3=80=82=E2=91=A3=E8=BF=98=E9=9C=80=E8=A6=81=E5=AF=B9?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=BB=93=E6=9E=9C=E5=81=9A=E6=95=B4=E5=90=88?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdtocode/mapper/CodeMessageTracer.java | 274 +++++++++++++++++- 1 file changed, 271 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java index e6f7445..c0ba0d5 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java +++ b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java @@ -713,22 +713,290 @@ public class CodeMessageTracer { private static void traceByMsg(Message msg_inSD, int msg_index, List res, Pair, List> objs_in_SD, Map classFullName_javaFileDir_map) { System.out.println("③对于" + msg_inSD.msg + ",开始针对消息内容进行追踪"); /* - * 1)解析消息中的内容。将每个标识符对应为一个类或者一个方法。比如第一个标识符必须是类;后面的标识符如果是小写开头,那认为它是某个类型的变量名,所以在前面的标识符所属的类中找具有该名称的变量其所属的类。最终在最后一个标识符那儿找方法名。※注意:存在一种情况,即“前面的标识符所属的类中找不到后面的标识符”。所以应该对每个标识符与其下一个标识符都进行单独的查找,然后记录所有“ + * 1)解析消息中的内容。将每个标识符对应为一个类或者一个方法。比如第一个标识符必须是类;后面的标识符如果是小写开头,那认为它是某个类型的属性名,所以在前面的标识符所属的类中找具有该名称的属性其所属的类。最终在最后一个标识符那儿找方法名。※注意:存在一种情况,即“前面的标识符所属的类中找不到后面的标识符”。所以应该对每个标识符与其下一个标识符都进行单独的查找,然后记录所有“ * 能从上一个标识符找到下一个标识符”的链条片段。将所有片段连接起来,断开的部分就直接放上对应的原消息内容即可。 */ - System.out.println("☆☆☆☆☆☆☆\n对于" + msg_inSD.msg + ",解析消息中的内容"); + System.out.println("※※※※※※※※※※\n对于" + msg_inSD.msg + ",解析消息中的内容"); + // 分隔消息中的每个标识符 + String[] identifiers = msg_inSD.msg.split("\\."); + // 保存每个标识符的<在消息中的位置,标识符(或与该标识符同名的属性)所属类的文件地址,标识符所属类的对象> + List> index_clsFilePath_ls = new ArrayList<>(); + // 专门按顺序保存每个标识符的追踪概率 + List possibilities = new ArrayList<>(); + // 将每个标识符对应为一个类或者一个方法 + int i = 0; + do { + Triple index_clsFilePath_clsObj = new Triple<>(i, null, null); + double possibility = 0.0; + // 第一个标识符必须是类。在classFullName_javaFileDir_map中找小写完全匹配的类(或msg.source的支撑类的内部类) + if (i == 0) { + Triple isExist_Dir_Obj = getClsFilePathForIdentifier(identifiers[i], classFullName_javaFileDir_map, msg_inSD.source); + if (isExist_Dir_Obj.getLeft()) { + index_clsFilePath_clsObj.setMid(isExist_Dir_Obj.getMid()); + index_clsFilePath_clsObj.setRight(isExist_Dir_Obj.getRight()); + possibility = 1.0; + } + } + // 后面的标识符如果是小写开头,那认为它是某个类型的属性名,所以在前面的标识符所属的类中找具有该名称的属性其所属的类 + // ※注意:如果再前面的标识符所属的类中找不到后面的标识符,则在classFullName_javaFileDir_map中找类 + else if (i < identifiers.length - 1) { + // 如果是小写开头,则从前面标识符的属性中找 + if (Character.isLowerCase(identifiers[i].charAt(0))) { + // 如果前面标识符有对应的类文件,则找属性 + if (index_clsFilePath_ls.get(i - 1).getRight() != null) { + ClassOrInterfaceDeclaration formerIdentifier_clsCode = index_clsFilePath_ls.get(i - 1).getRight(); + List attris_in_formerClsCode = formerIdentifier_clsCode.getFields(); + // 不管是属性名字相似、还是属性类型相似,都记录属性的类型 + for (FieldDeclaration attri : attris_in_formerClsCode) { + double sim_type = jaccard_similarity(identifiers[i], attri.getElementType().asString()); + double sim_var = jaccard_similarity(identifiers[i], attri.getVariable(0).getNameAsString()); + if (sim_type >= 0.8 || sim_var >= 0.8) { + // 找attri.getElementType()对应的类的文件地址(有可能是前面的类的内部类) + Pair attri_type_dir = getAttriTypeDir(attri.getElementType().asString(), classFullName_javaFileDir_map, index_clsFilePath_ls.get(i - 1).getMid()); + index_clsFilePath_clsObj.setMid(attri_type_dir.getLeft()); + index_clsFilePath_clsObj.setRight(attri_type_dir.getRight()); + possibility = Math.max(sim_type, sim_var); + } + } + } + // 如果前面标识符没有对应的类文件,则从全部文件的全名中找(或msg.source的支撑类的内部类) + else { + Triple isExist_Dir_Obj = getClsFilePathForIdentifier(identifiers[i], classFullName_javaFileDir_map, msg_inSD.source); + if (isExist_Dir_Obj.getLeft()) { + index_clsFilePath_clsObj.setMid(isExist_Dir_Obj.getMid()); + index_clsFilePath_clsObj.setRight(isExist_Dir_Obj.getRight()); + possibility = 1.0; + } + } + } + // 如果标识符是大写开头,则直接从全部文件的全名中找对应类(找不到的话再去找前面标识符的类的内部类) + else { + Triple isExist_Dir_Obj = new Triple<>(false, null, null); + if (index_clsFilePath_ls.get(i - 1).getRight() != null) { + isExist_Dir_Obj = getClsFilePathForIdentifierFromFormer(identifiers[i], classFullName_javaFileDir_map, index_clsFilePath_ls.get(i - 1).getMid()); + } else { + isExist_Dir_Obj = getClsFilePathForIdentifier(identifiers[i], classFullName_javaFileDir_map, msg_inSD.source); + } + if (isExist_Dir_Obj.getLeft()) { + index_clsFilePath_clsObj.setMid(isExist_Dir_Obj.getMid()); + index_clsFilePath_clsObj.setRight(isExist_Dir_Obj.getRight()); + possibility = 1.0; + } + } + } + // 最终在最后一个标识符那儿找方法名。该方法一定属于上一个标识符对应的类。如果上一个标识符没有对应类,则直接放上这个代表方法的字符串即可 + else { + if (index_clsFilePath_ls.get(i - 1).getRight() != null) { + ClassOrInterfaceDeclaration formerIdentifier_clsCode = index_clsFilePath_ls.get(i - 1).getRight(); + List methods_in_formerClsCode = formerIdentifier_clsCode.getMethods(); + boolean former_contains_md = false; + double sim = 0.0; + for (MethodDeclaration method_in_formerClsCode : methods_in_formerClsCode) { + sim = jaccard_similarity(identifiers[i], method_in_formerClsCode.getNameAsString()); + if (sim >= 0.5) { + former_contains_md = true; + break; + } + } + if (former_contains_md) { + index_clsFilePath_clsObj.setMid(index_clsFilePath_ls.get(i - 1).getMid()); + index_clsFilePath_clsObj.setRight(index_clsFilePath_ls.get(i - 1).getRight()); + possibility = sim; + } + } + } + // 断开的部分就直接放上对应的原消息内容即可 + if (index_clsFilePath_clsObj.getMid() == null) { + index_clsFilePath_clsObj.setMid(identifiers[i]); + } + index_clsFilePath_ls.add(index_clsFilePath_clsObj); + possibilities.add(possibility); + i++; + } while (i < identifiers.length); /* * 2)将由标识符链接起来的链条作为消息的追踪。记录链条两端。 */ System.out.println("对于" + msg_inSD.msg + ",将由标识符链接起来的链条作为消息的追踪"); + /* + * 写!!!!!! + * + * 写!!!!!! + * + * 写!!!!!! + * + * 写!!!!!! + * + * 写!!!!!! + * + * 写!!!!!! + * + * 写!!!!!! + */ + for (Triple tri : index_clsFilePath_ls) { + if (tri.getRight() != null) { + System.out.println("对于" + msg_inSD.msg + "的第" + (tri.getLeft() + 1) + "个标识符" + identifiers[tri.getLeft()] + ",其源代码文件有" + possibilities.get(tri.getLeft()) + "概率在" + tri.getMid() + "(用Javaparser解析可得对象" + tri.getRight().hashCode() + ")"); + } else { + System.out.println("对于" + msg_inSD.msg + "的第" + (tri.getLeft() + 1) + "个标识符" + identifiers[tri.getLeft()] + ",其源代码文件有" + possibilities.get(tri.getLeft()) + "概率在" + tri.getMid() + "(用Javaparser解析可得对象null)"); + } + } /* * 3)对比链条两端与消息两端的对象。如果存在支撑类之类的关系,则认为消息两端应该是支撑类;否则仍保留链条两端作为消息两端。 + * + * 这一步其实不用做,因为目前就是基于消息两端的支撑类做的追踪 */ - System.out.println("对于" + msg_inSD.msg + ",对比链条两端与消息两端的对象\n☆☆☆☆☆☆☆"); + System.out.println("对于" + msg_inSD.msg + ",对比链条两端与消息两端的对象\n※※※※※※※※※※"); res.set(msg_index, msg_inSD); System.out.println("对于" + msg_inSD.msg + ",完成针对消息内容的追踪了"); } + /** + * 根据标识符,在classFullName_javaFileDir_map中(或内部类中)找小写完全匹配的类 + * + * @param source + */ + private static Triple getClsFilePathForIdentifier(String identifier, Map classFullName_javaFileDir_map, UMLObject src_uo) { + Triple res = new Triple<>(false, null, null); + Set fullNames = classFullName_javaFileDir_map.keySet(); + for (String fullName : fullNames) { + String shortName = fullName.substring(fullName.lastIndexOf(".") + 1); + if (identifier.toLowerCase().equals(shortName.toLowerCase())) { + res.setLeft(true); + String clsFile_dir = classFullName_javaFileDir_map.get(fullName); + res.setMid(clsFile_dir); + try { + Optional o_clsFile = StaticJavaParser.parse(new File(clsFile_dir)).getClassByName(shortName); + if (o_clsFile.isPresent()) { + res.setRight(o_clsFile.get()); + } else { + o_clsFile = StaticJavaParser.parse(new File(clsFile_dir)).findFirst(ClassOrInterfaceDeclaration.class); + if (o_clsFile.isPresent()) { + res.setRight(o_clsFile.get()); + } + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + break; + } + } + // 有可能是支撑类的内部类 + if (res.getLeft() == false) { + for (String uo_mapped_file_dir : src_uo.mapped_file_dir_ls) { + // uo_mapped_file_dir是支撑类的文件地址。根据文件地址,用javaparser去解析文件 + try { + CompilationUnit uo_mapped_file = StaticJavaParser.parse(new File(uo_mapped_file_dir)); + if (Character.isLowerCase(identifier.charAt(0))) { + StringBuilder sb = new StringBuilder(identifier); + sb.setCharAt(0, Character.toUpperCase(identifier.charAt(0))); + identifier = sb.toString(); + } + List inner_class_declaration = uo_mapped_file.getLocalDeclarationFromClassname(identifier); + if (!inner_class_declaration.isEmpty()) { + res.setLeft(true); + res.setMid(uo_mapped_file_dir); + res.setRight(inner_class_declaration.get(0)); + break; + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + return res; + } + + private static Pair getAttriTypeDir(String attri_type, Map classFullName_javaFileDir_map, String former_dir) { + Pair res = new Pair<>(); + Set fullNames = classFullName_javaFileDir_map.keySet(); + for (String fullName : fullNames) { + String shortName = fullName.substring(fullName.lastIndexOf(".") + 1); + if (attri_type.equals(shortName)) { + String clsFile_dir = classFullName_javaFileDir_map.get(fullName); + res.setLeft(clsFile_dir); + try { + Optional o_clsFile = StaticJavaParser.parse(new File(clsFile_dir)).getClassByName(shortName); + if (o_clsFile.isPresent()) { + res.setRight(o_clsFile.get()); + } else { + o_clsFile = StaticJavaParser.parse(new File(clsFile_dir)).findFirst(ClassOrInterfaceDeclaration.class); + if (o_clsFile.isPresent()) { + res.setRight(o_clsFile.get()); + } + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + break; + } + } + // 有可能是前面标识符所属类的内部类 + if (res.getLeft() == null) { + try { + CompilationUnit former_clsFile = StaticJavaParser.parse(new File(former_dir)); + List inner_class_declaration = former_clsFile.getLocalDeclarationFromClassname(attri_type); + if (!inner_class_declaration.isEmpty()) { + res.setLeft(former_dir); + res.setRight(inner_class_declaration.get(0)); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + return res; + } + + /** + * 根据标识符,在classFullName_javaFileDir_map中(或内部类中)找小写完全匹配的类 + * + * @param source + */ + private static Triple getClsFilePathForIdentifierFromFormer(String identifier, Map classFullName_javaFileDir_map, String former_dir) { + Triple res = new Triple<>(false, null, null); + Set fullNames = classFullName_javaFileDir_map.keySet(); + for (String fullName : fullNames) { + String shortName = fullName.substring(fullName.lastIndexOf(".") + 1); + if (identifier.toLowerCase().equals(shortName.toLowerCase())) { + res.setLeft(true); + String clsFile_dir = classFullName_javaFileDir_map.get(fullName); + res.setMid(clsFile_dir); + try { + Optional o_clsFile = StaticJavaParser.parse(new File(clsFile_dir)).getClassByName(shortName); + if (o_clsFile.isPresent()) { + res.setRight(o_clsFile.get()); + } else { + o_clsFile = StaticJavaParser.parse(new File(clsFile_dir)).findFirst(ClassOrInterfaceDeclaration.class); + if (o_clsFile.isPresent()) { + res.setRight(o_clsFile.get()); + } + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + break; + } + } + // 有可能是前面标识符所属类的内部类 + if (res.getLeft() == false) { + try { + CompilationUnit former_clsFile = StaticJavaParser.parse(new File(former_dir)); + if (Character.isLowerCase(identifier.charAt(0))) { + StringBuilder sb = new StringBuilder(identifier); + sb.setCharAt(0, Character.toUpperCase(identifier.charAt(0))); + identifier = sb.toString(); + } + List inner_class_declaration = former_clsFile.getLocalDeclarationFromClassname(identifier); + if (!inner_class_declaration.isEmpty()) { + res.setLeft(true); + res.setMid(former_dir); + res.setRight(inner_class_declaration.get(0)); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + return res; + } + /** * 计算两个字符串的Jaccard相似度 */ -- Gitee From 906e03ec9b4dd1d405d27f44034a8d12d7ecbbdc Mon Sep 17 00:00:00 2001 From: chief Date: Thu, 12 May 2022 16:43:18 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E8=BF=BD=E8=B8=AA=E5=B7=B2=E5=81=9A?= =?UTF-8?q?=E5=AE=8C=EF=BC=8C=E5=BE=97=E5=8E=9F=E5=A7=8B=E8=BF=BD=E8=B8=AA?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E3=80=82=E6=8E=A5=E4=B8=8B=E6=9D=A5=E6=95=B4?= =?UTF-8?q?=E7=90=86=E3=80=81=E4=BF=9D=E5=AD=98=E8=BF=BD=E8=B8=AA=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=EF=BC=88LOC1065=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdtocode/mapper/CodeMessageTracer.java | 200 +++++++++++------- .../uct/sdtocode/util/TracedMessagePath.java | 4 +- 2 files changed, 127 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java index c0ba0d5..b3f3ea2 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java +++ b/src/main/java/com/hy/java/uct/sdtocode/mapper/CodeMessageTracer.java @@ -664,7 +664,7 @@ public class CodeMessageTracer { BlockStmt body = o_body.get(); String[] codes = body.toString().split("\n"); for (String code_line : codes) { - if (code_line.contains(target_title)) { + if (code_line.toLowerCase().contains(target_title.toLowerCase())) { codeLine_sim = 1.0; break; } @@ -719,22 +719,24 @@ public class CodeMessageTracer { System.out.println("※※※※※※※※※※\n对于" + msg_inSD.msg + ",解析消息中的内容"); // 分隔消息中的每个标识符 String[] identifiers = msg_inSD.msg.split("\\."); - // 保存每个标识符的<在消息中的位置,标识符(或与该标识符同名的属性)所属类的文件地址,标识符所属类的对象> - List> index_clsFilePath_ls = new ArrayList<>(); - // 专门按顺序保存每个标识符的追踪概率 - List possibilities = new ArrayList<>(); + // 保存每个标识符的<在消息中的位置,<标识符(或与该标识符同名的属性)所属类的文件地址,产生标识符的代码片段,追踪概率>,标识符所属类的对象> + List, ClassOrInterfaceDeclaration>>> index_clsFilePath_ls = new ArrayList<>(); // 将每个标识符对应为一个类或者一个方法 int i = 0; do { - Triple index_clsFilePath_clsObj = new Triple<>(i, null, null); - double possibility = 0.0; + // traced_files_for_current_identifier记录当前标识符所追踪到的所有文件(所以是List,里面记录的都是index_clsFilePath_clsObj) + List, ClassOrInterfaceDeclaration>> traced_files_for_current_identifier = new ArrayList<>(); // 第一个标识符必须是类。在classFullName_javaFileDir_map中找小写完全匹配的类(或msg.source的支撑类的内部类) if (i == 0) { + // 完全匹配,所以只追踪到一个index_clsFilePath_clsObj,即<标识符(或与该标识符同名的属性)所属类的文件地址,产生标识符的代码片段,追踪概率> + Triple, ClassOrInterfaceDeclaration> index_clsFilePath_clsObj = new Triple<>(i, null, null); Triple isExist_Dir_Obj = getClsFilePathForIdentifier(identifiers[i], classFullName_javaFileDir_map, msg_inSD.source); if (isExist_Dir_Obj.getLeft()) { - index_clsFilePath_clsObj.setMid(isExist_Dir_Obj.getMid()); + String code = isExist_Dir_Obj.getRight().getNameAsString(); + double possibility = 1.0; + index_clsFilePath_clsObj.setMid(Triple.createTriple(isExist_Dir_Obj.getMid(), code, possibility)); index_clsFilePath_clsObj.setRight(isExist_Dir_Obj.getRight()); - possibility = 1.0; + traced_files_for_current_identifier.add(index_clsFilePath_clsObj); } } // 后面的标识符如果是小写开头,那认为它是某个类型的属性名,所以在前面的标识符所属的类中找具有该名称的属性其所属的类 @@ -743,102 +745,143 @@ public class CodeMessageTracer { // 如果是小写开头,则从前面标识符的属性中找 if (Character.isLowerCase(identifiers[i].charAt(0))) { // 如果前面标识符有对应的类文件,则找属性 - if (index_clsFilePath_ls.get(i - 1).getRight() != null) { - ClassOrInterfaceDeclaration formerIdentifier_clsCode = index_clsFilePath_ls.get(i - 1).getRight(); - List attris_in_formerClsCode = formerIdentifier_clsCode.getFields(); - // 不管是属性名字相似、还是属性类型相似,都记录属性的类型 - for (FieldDeclaration attri : attris_in_formerClsCode) { - double sim_type = jaccard_similarity(identifiers[i], attri.getElementType().asString()); - double sim_var = jaccard_similarity(identifiers[i], attri.getVariable(0).getNameAsString()); - if (sim_type >= 0.8 || sim_var >= 0.8) { - // 找attri.getElementType()对应的类的文件地址(有可能是前面的类的内部类) - Pair attri_type_dir = getAttriTypeDir(attri.getElementType().asString(), classFullName_javaFileDir_map, index_clsFilePath_ls.get(i - 1).getMid()); - index_clsFilePath_clsObj.setMid(attri_type_dir.getLeft()); - index_clsFilePath_clsObj.setRight(attri_type_dir.getRight()); - possibility = Math.max(sim_type, sim_var); + List, ClassOrInterfaceDeclaration>> formerID_tracedFiles = index_clsFilePath_ls.get(i - 1); + boolean former_has_attri = false; + // 遍历前面标识符所追踪到的所有类文件,每个文件找一个最相似的属性 + for (Triple, ClassOrInterfaceDeclaration> formerID_tracedFile : formerID_tracedFiles) { + if (formerID_tracedFile.getRight() != null) { + Triple, ClassOrInterfaceDeclaration> index_clsFilePath_clsObj = new Triple<>(i, null, null); + ClassOrInterfaceDeclaration formerIdentifier_clsCode = formerID_tracedFile.getRight(); + List attris_in_formerClsCode = formerIdentifier_clsCode.getFields(); + // 不管是属性名字相似、还是属性类型相似,都记录属性的类型 + for (FieldDeclaration attri : attris_in_formerClsCode) { + double sim_type = jaccard_similarity(identifiers[i], attri.getElementType().asString()); + double sim_var = jaccard_similarity(identifiers[i], attri.getVariable(0).getNameAsString()); + if (sim_type >= 0.8 || sim_var >= 0.8) { + // 找attri.getElementType()对应的类的文件地址(有可能是前面的类的内部类) + Pair attri_type_dir = getAttriTypeDir(attri.getElementType().asString(), classFullName_javaFileDir_map, formerID_tracedFile.getMid().getLeft()); + index_clsFilePath_clsObj.setMid(Triple.createTriple(attri_type_dir.getLeft(), attri.toString(), Math.max(sim_type, sim_var))); + index_clsFilePath_clsObj.setRight(attri_type_dir.getRight()); + former_has_attri = true; + } } + traced_files_for_current_identifier.add(index_clsFilePath_clsObj); } } // 如果前面标识符没有对应的类文件,则从全部文件的全名中找(或msg.source的支撑类的内部类) - else { + if (!former_has_attri) { + Triple, ClassOrInterfaceDeclaration> index_clsFilePath_clsObj = new Triple<>(i, null, null); Triple isExist_Dir_Obj = getClsFilePathForIdentifier(identifiers[i], classFullName_javaFileDir_map, msg_inSD.source); if (isExist_Dir_Obj.getLeft()) { - index_clsFilePath_clsObj.setMid(isExist_Dir_Obj.getMid()); + String code = isExist_Dir_Obj.getRight().getNameAsString(); + double possibility = 1.0; + index_clsFilePath_clsObj.setMid(Triple.createTriple(isExist_Dir_Obj.getMid(), code, possibility)); index_clsFilePath_clsObj.setRight(isExist_Dir_Obj.getRight()); - possibility = 1.0; + traced_files_for_current_identifier.add(index_clsFilePath_clsObj); } } } - // 如果标识符是大写开头,则直接从全部文件的全名中找对应类(找不到的话再去找前面标识符的类的内部类) + // 如果标识符是大写开头,则去找前面标识符的类的内部类(找不到的话再直接从全部文件的全名中找对应类) else { + Triple, ClassOrInterfaceDeclaration> index_clsFilePath_clsObj = new Triple<>(i, null, null); Triple isExist_Dir_Obj = new Triple<>(false, null, null); - if (index_clsFilePath_ls.get(i - 1).getRight() != null) { - isExist_Dir_Obj = getClsFilePathForIdentifierFromFormer(identifiers[i], classFullName_javaFileDir_map, index_clsFilePath_ls.get(i - 1).getMid()); - } else { + List, ClassOrInterfaceDeclaration>> formerID_tracedFiles = index_clsFilePath_ls.get(i - 1); + // 去找前面标识符的类的内部类 + for (Triple, ClassOrInterfaceDeclaration> formerID_tracedFile : formerID_tracedFiles) { + if (formerID_tracedFile.getRight() != null) { + isExist_Dir_Obj = getClsFilePathForIdentifierFromFormer(identifiers[i], classFullName_javaFileDir_map, formerID_tracedFile.getMid().getLeft()); + } + } + // 找不到的话再直接从全部文件的全名中找对应类 + if (!isExist_Dir_Obj.getLeft()) { isExist_Dir_Obj = getClsFilePathForIdentifier(identifiers[i], classFullName_javaFileDir_map, msg_inSD.source); } if (isExist_Dir_Obj.getLeft()) { - index_clsFilePath_clsObj.setMid(isExist_Dir_Obj.getMid()); + String code = isExist_Dir_Obj.getRight().getNameAsString(); + double possibility = 1.0; + index_clsFilePath_clsObj.setMid(Triple.createTriple(isExist_Dir_Obj.getMid(), code, possibility)); index_clsFilePath_clsObj.setRight(isExist_Dir_Obj.getRight()); - possibility = 1.0; + traced_files_for_current_identifier.add(index_clsFilePath_clsObj); } } } // 最终在最后一个标识符那儿找方法名。该方法一定属于上一个标识符对应的类。如果上一个标识符没有对应类,则直接放上这个代表方法的字符串即可 else { - if (index_clsFilePath_ls.get(i - 1).getRight() != null) { - ClassOrInterfaceDeclaration formerIdentifier_clsCode = index_clsFilePath_ls.get(i - 1).getRight(); - List methods_in_formerClsCode = formerIdentifier_clsCode.getMethods(); - boolean former_contains_md = false; - double sim = 0.0; - for (MethodDeclaration method_in_formerClsCode : methods_in_formerClsCode) { - sim = jaccard_similarity(identifiers[i], method_in_formerClsCode.getNameAsString()); - if (sim >= 0.5) { - former_contains_md = true; - break; + List, ClassOrInterfaceDeclaration>> formerID_tracedFiles = index_clsFilePath_ls.get(i - 1); + for (Triple, ClassOrInterfaceDeclaration> formerID_tracedFile : formerID_tracedFiles) { + if (formerID_tracedFile.getRight() != null) { + Triple, ClassOrInterfaceDeclaration> index_clsFilePath_clsObj = new Triple<>(i, null, null); + ClassOrInterfaceDeclaration formerIdentifier_clsCode = formerID_tracedFile.getRight(); + List methods_in_formerClsCode = formerIdentifier_clsCode.getMethods(); + boolean former_contains_md = false; + String code = null; + double sim = 0.0; + double max = sim; + for (MethodDeclaration method_in_formerClsCode : methods_in_formerClsCode) { + sim = jaccard_similarity(identifiers[i], method_in_formerClsCode.getNameAsString()); + if (sim >= 0.5) { + former_contains_md = true; + if (sim > max) { + max = sim; + code = method_in_formerClsCode.getDeclarationAsString(); + } + } + } + if (former_contains_md) { + index_clsFilePath_clsObj.setMid(Triple.createTriple(formerID_tracedFile.getMid().getLeft(), code, sim)); + index_clsFilePath_clsObj.setRight(formerID_tracedFile.getRight()); + traced_files_for_current_identifier.add(index_clsFilePath_clsObj); } - } - if (former_contains_md) { - index_clsFilePath_clsObj.setMid(index_clsFilePath_ls.get(i - 1).getMid()); - index_clsFilePath_clsObj.setRight(index_clsFilePath_ls.get(i - 1).getRight()); - possibility = sim; } } } // 断开的部分就直接放上对应的原消息内容即可 - if (index_clsFilePath_clsObj.getMid() == null) { - index_clsFilePath_clsObj.setMid(identifiers[i]); + if (traced_files_for_current_identifier.size() <= 0) { + Triple, ClassOrInterfaceDeclaration> index_clsFilePath_clsObj = new Triple<>(i, null, null); + index_clsFilePath_clsObj.setMid(Triple.createTriple(null, identifiers[i], 0.0)); + traced_files_for_current_identifier.add(index_clsFilePath_clsObj); } - index_clsFilePath_ls.add(index_clsFilePath_clsObj); - possibilities.add(possibility); + index_clsFilePath_ls.add(traced_files_for_current_identifier); i++; } while (i < identifiers.length); /* * 2)将由标识符链接起来的链条作为消息的追踪。记录链条两端。 */ System.out.println("对于" + msg_inSD.msg + ",将由标识符链接起来的链条作为消息的追踪"); - /* - * 写!!!!!! - * - * 写!!!!!! - * - * 写!!!!!! - * - * 写!!!!!! - * - * 写!!!!!! - * - * 写!!!!!! - * - * 写!!!!!! - */ - for (Triple tri : index_clsFilePath_ls) { - if (tri.getRight() != null) { - System.out.println("对于" + msg_inSD.msg + "的第" + (tri.getLeft() + 1) + "个标识符" + identifiers[tri.getLeft()] + ",其源代码文件有" + possibilities.get(tri.getLeft()) + "概率在" + tri.getMid() + "(用Javaparser解析可得对象" + tri.getRight().hashCode() + ")"); - } else { - System.out.println("对于" + msg_inSD.msg + "的第" + (tri.getLeft() + 1) + "个标识符" + identifiers[tri.getLeft()] + ",其源代码文件有" + possibilities.get(tri.getLeft()) + "概率在" + tri.getMid() + "(用Javaparser解析可得对象null)"); + // 按照identifier的顺序保存多个traced_path + List temp_tracedPath_startingFromID = new ArrayList<>(); + int traced_identifiers_num = index_clsFilePath_ls.size(); + int id_index = 0; + do { + // 先将第一个标识符的所有追踪文件保存至TracedMessagePath,作为起点 + if (id_index == 0) { + List, ClassOrInterfaceDeclaration>> tracedFiles_for_firstIdentifier = index_clsFilePath_ls.get(id_index); + for (Triple, ClassOrInterfaceDeclaration> a_tracedFile_for_firstIdentifier : tracedFiles_for_firstIdentifier) { + TracedMessagePath traced_path = new TracedMessagePath(); + traced_path.path.add(a_tracedFile_for_firstIdentifier.getMid()); + temp_tracedPath_startingFromID.add(traced_path); + } } - } + // 后面标识符的每个追踪文件都得在前面的一个TracedMessagePath后出现一次 + else { + int temp_tracedPath_currentSize = temp_tracedPath_startingFromID.size(); + List tmp_record_tracedPath = new ArrayList<>(); + for (int j = 0; j < temp_tracedPath_currentSize; j++) { + TracedMessagePath Jth_tracedPath_till_formerID = temp_tracedPath_startingFromID.get(j); + List, ClassOrInterfaceDeclaration>> tracedFiles_for_currentIdentifier = index_clsFilePath_ls.get(id_index); + for (Triple, ClassOrInterfaceDeclaration> a_tracedFile_for_currentIdentifier : tracedFiles_for_currentIdentifier) { + TracedMessagePath new_ttp = new TracedMessagePath(); + new_ttp.path.addAll(Jth_tracedPath_till_formerID.path); + new_ttp.path.add(a_tracedFile_for_currentIdentifier.getMid()); + tmp_record_tracedPath.add(new_ttp); + } + } + temp_tracedPath_startingFromID.clear(); + temp_tracedPath_startingFromID.addAll(tmp_record_tracedPath); + } + id_index++; + } while (id_index < traced_identifiers_num); + msg_inSD.traced_path_ls.addAll(temp_tracedPath_startingFromID); /* * 3)对比链条两端与消息两端的对象。如果存在支撑类之类的关系,则认为消息两端应该是支撑类;否则仍保留链条两端作为消息两端。 * @@ -1017,13 +1060,18 @@ public class CodeMessageTracer { } /** - * 保存追踪结果 + * 整理、保存追踪结果 */ - public static void save(List trace_msgs, String string) { + public static void save(List trace_msgs, String res_dir) { for (Message msg : trace_msgs) { - for (TracedMessagePath traced_path : msg.traced_path_ls) { - for (Triple tri : traced_path.path) { - System.out.println(msg.msg + "有" + tri.getRight() + "概率追踪到" + tri.getLeft() + "的代码段" + tri.getMid()); + int tracing_ways = msg.traced_path_ls.size(); + for (int i = 0; i < tracing_ways; i++) { + TracedMessagePath tracing_way = msg.traced_path_ls.get(i); + System.out.println(msg.msg + "的第" + (i + 1) + "种追踪链:"); + int identifier_num = tracing_way.path.size(); + for (int j = 0; j < identifier_num; j++) { + Triple traced_file = tracing_way.path.get(j); + System.out.println("\t" + msg.msg + "的第" + (j + 1) + "个标识符有" + traced_file.getRight() + "概率追踪到文件" + traced_file.getLeft() + "的代码段" + traced_file.getMid()); } } } diff --git a/src/main/java/com/hy/java/uct/sdtocode/util/TracedMessagePath.java b/src/main/java/com/hy/java/uct/sdtocode/util/TracedMessagePath.java index 36d66ce..127b5e2 100644 --- a/src/main/java/com/hy/java/uct/sdtocode/util/TracedMessagePath.java +++ b/src/main/java/com/hy/java/uct/sdtocode/util/TracedMessagePath.java @@ -13,6 +13,8 @@ import com.hy.java.utility.common.Triple; * 每条链路有个总体的追踪概率 */ public class TracedMessagePath { - // 一条链路:由一系列组成的List + /** + * 一条链路:由一系列{@code }组成的List + */ public List> path = new ArrayList<>(); } -- Gitee