ArKanjo 0.5.1
A tool for find code duplicated functions in codebases
diff_method.cpp
Go to the documentation of this file.
7
9
10DiffMethod::DiffMethod(const fs::path& base_path_, double similarity_) {
11 base_path = base_path_;
12 similarity = similarity_;
13
14 if (similarity < 0) {
15 std::cerr << "SIMILARITY SHOULD BE GREATER OR EQUAL 0 TO USE DUPLICATION FINDER BY DIFF COMMAND";
16 }
17}
18
19std::vector<std::string> DiffMethod::find_files(const fs::path& folder_path) {
20 std::vector<std::string> file_paths;
21 for (const auto& dirEntry : std::filesystem::recursive_directory_iterator(folder_path)) {
22 fs::path file_path = dirEntry.path();
23 if (std::filesystem::exists(file_path) && std::filesystem::is_regular_file(file_path)) {
24 file_paths.push_back(file_path.string());
25 }
26 }
27 return file_paths;
28}
29
30bool DiffMethod::is_empty_line(std::string line) {
31 size_t line_size = line.size();
32 bool is_empty = true;
33 for (size_t i = 1; i < line_size; i++) {
34 is_empty &= Utils::is_empty_char(line[i]);
35 }
36 return is_empty;
37}
38
39std::vector<std::string> DiffMethod::remove_blank_lines(std::vector<std::string> content) {
40 std::vector<std::string> ret;
41 for (auto line : content) {
42 if (!is_empty_line(line)) {
43 ret.push_back(line);
44 }
45 }
46 return ret;
47}
48
49bool DiffMethod::is_equal_files(std::vector<std::string> content1, std::vector<std::string> content2) {
50 if (content1.size() != content2.size()) {
51 return false;
52 }
53 size_t sz = content1.size();
54 for (size_t i = 0; i < sz; i++) {
55 if (content1[i] != content2[i]) {
56 return false;
57 }
58 }
59 return true;
60}
61
62double DiffMethod::find_similarity(std::string path1, std::string path2) {
63 std::vector<std::string> content1 = Utils::read_file_with_vector(path1);
64 std::vector<std::string> content2 = Utils::read_file_with_vector(path2);
65
66 content1 = remove_blank_lines(content1);
67 content2 = remove_blank_lines(content2);
68
69 if (is_equal_files(content1, content2)) {
70 return 100;
71 }
72
73 // execute diff command to extract the differences
74 fs::path output_file = base_path / "diff.txt";
75
76 //-c is to print in the desired format
77 // 2>&1 is to also send standard error to the output_file
78 std::string command = "diff " + path1 + " " + path2 + " -c > " + output_file.string() + " 2>&1";
79 system(command.c_str());
80
81 std::vector<std::string> content = Utils::read_file_with_vector(output_file);
82
83 size_t number_lines = content.size();
84
85 int different_lines = 0;
86
87 for (size_t i = 4; i < number_lines; i++) {
88 auto& line = content[i];
89 if (is_empty_line(line)) {
90 continue;
91 }
92 if (line[0] == '!' || line[0] == '-' || line[0] == '+') {
93 different_lines += 1;
94 }
95 }
96
97 int equal_lines = (int)content1.size() + (int)content2.size();
98 equal_lines -= different_lines;
99
100 if (different_lines + equal_lines == 0) {
101 return -1;
102 }
103
104 double db_equal_lines = equal_lines;
105 double db_different_lines = different_lines;
106 double similarity_metric = db_equal_lines / (db_different_lines + db_equal_lines);
107 similarity_metric *= 100;
108 return similarity_metric;
109}
110
111std::vector<DuplicationEntry> DiffMethod::find_similar_pairs(std::vector<std::string>& file_paths) {
112 size_t number_files = file_paths.size();
113 std::vector<DuplicationEntry> ret;
114 for (size_t i = 0; i < number_files; i++) {
115 for (size_t j = 0; j < number_files; j++)
116 if (i != j) {
117 std::string file_path1 = file_paths[i];
118 std::string file_path2 = file_paths[j];
119 double similarity_metric = find_similarity(file_path1, file_path2);
120 if (similarity_metric >= similarity) {
121 ret.push_back({similarity_metric, file_path1, file_path2});
122 }
123 }
124 }
125 sort(ret.rbegin(), ret.rend());
126 return ret;
127}
128
129void DiffMethod::save_duplications(std::vector<DuplicationEntry>& file_duplication_pairs) {
130 fs::path output_file_path = FunctionStorage{}.build_similarity_path();
131
132 auto fout = std::ofstream(output_file_path.string());
133
134 fout << file_duplication_pairs.size() << '\n';
135 for (const auto& [similarity, path1, path2] : file_duplication_pairs) {
136 fout << path1 << ' ' << path2 << ' ';
137 fout << std::fixed << std::setprecision(2) << similarity << '\n';
138 }
139
140 fout.close();
141}
142
144 fs::path base = base_path / source_feature_path;
145
146 auto source = fd.get_feature<SourceFeature>();
147 if (!source)
148 return;
149
150 fs::path relative(fd.path);
151 std::string filename = fd.function_name + relative.extension().string();
152 fs::path path = base / relative / filename;
153 Utils::write_file(path, source->code + "\n");
154}
155
157 fs::path base = base_path / source_feature_path;
158
159 std::vector<std::string> file_paths = find_files(base);
160
161 std::vector<DuplicationEntry> file_duplication_pairs = find_similar_pairs(file_paths);
162
163 for (auto& [sim, path1, path2] : file_duplication_pairs) {
164 path1 = fs::relative(path1, base).string();
165 path2 = fs::relative(path2, base).string();
166 }
167
168 fm::write(SAVING_MESSAGE);
169
170 save_duplications(file_duplication_pairs);
171}
void on_function(const FunctionData &fd) override
void execute() override
Executes the preprocessing pipeline.
DiffMethod(const fs::path &base_path_, double similarity_)
Constructs preprocessor with configuration.
Definition: diff_method.cpp:10
static void write(const std::string &template_str, const std::vector< T > &data, enum Format effective=Format::AUTO, RowColorFn color_fn=nullptr, std::ostream &out=std::cout)
std::string function_name
Name of the function.
std::string path
std::shared_ptr< T > get_feature() const
fs::path build_similarity_path() const
Builds similarity file path.
Configuration management interface.
Code duplication preprocessing system.
Provides access to function storage locations.
void write_file(const fs::path &path, const std::string &content)
Writes content to a file at specified path.
Definition: utils.cpp:19
std::vector< std::string > read_file_with_vector(const fs::path &path)
Reads a file line by line into a vector of strings.
Definition: utils.cpp:26
bool is_empty_char(char c)
Checks if a character is considered empty/whitespace.
Definition: utils.cpp:69
fs::path source_feature_path
Defines utility functions used across all files.