ArKanjo 0.5.1
A tool for find code duplicated functions in codebases
git_diff_function.cpp
Go to the documentation of this file.
2
3#include <iostream>
4#include <sstream>
5
11
13 : similarity_table(_similarity_table) {}
14
16 if (options.extra_args.size() != 2) {
17 throw CLIError("Git diff command expects two function name patterns.");
18 return false;
19 }
20 return true;
21}
22
23bool GitDiffFunction::run(const ParsedOptions& options) {
24 // Make a copy of the patterns to format them for searching in the similarity table
25 const std::string first_pattern = format_pattern(options.extra_args[0]);
26 const std::string second_pattern = format_pattern(options.extra_args[1]);
27
28 std::vector<Path> first_candidates = find_matching_paths(first_pattern);
29 std::vector<Path> second_candidates = find_matching_paths(second_pattern);
30
31 Path first_path = choose_single_path(first_candidates, options.extra_args[0]);
32 Path second_path = choose_single_path(second_candidates, options.extra_args[1]);
33
34 if (!similarity_table->is_similar(first_path, second_path)) {
35 auto similarity =similarity_table->get_threshold_similarity();
36
37 std::ostringstream ss;
38 ss << std::fixed << std::setprecision(2) << similarity;
39
40 throw CLIError("The selected functions are not flagged as duplicates in the similarity table (similarity: " + ss.str() + ").");
41 return false;
42 }
43
44 return diff_functions(first_path, second_path);
45}
46
47std::vector<Path> GitDiffFunction::find_matching_paths(const std::string& pattern) const {
48 std::vector<Path> matches;
49 FunctionLoader loader;
50 for (const auto& path : similarity_table->get_path_list()) {
51 auto function = loader.load_metadata(path);
52
53 if (function.contains_given_pattern(pattern))
54 matches.push_back(path);
55 }
56 return matches;
57}
58
59const std::string GitDiffFunction::format_pattern(const std::string& pattern) const {
60 std::string result = pattern;
61
62 size_t pos = 0;
63 while ((pos = result.find("::", pos)) != std::string::npos) {
64 result.replace(pos, 2, "/");
65 pos += 1;
66 }
67
68 return result;
69}
70
71Path GitDiffFunction::choose_single_path(const std::vector<Path>& candidates, const std::string& pattern) const {
72 if (candidates.empty()) {
73 throw CLIError("No function found matching pattern: " + pattern);
74 }
75 if (candidates.size() > 1) {
76 std::ostringstream message;
77 message << "Multiple functions match the pattern '" << pattern << "':\n";
78 FunctionLoader loader;
79 for (const auto& path : candidates) {
80 auto function = loader.load_metadata(path);
81 message << " - " << FunctionPrinter::format_path_message_in_pair(function) << "\n";
82 }
83 message << "Please use a more specific function name pattern.";
84 throw CLIError(message.str());
85 }
86 return candidates.front();
87}
88
89std::string GitDiffFunction::build_text_from_lines(const std::vector<std::string>& lines) {
90 std::string output;
91 output.reserve(lines.size() * 80);
92 for (const auto& line : lines) {
93 output += line;
94 output.push_back('\n');
95 }
96 return output;
97}
98
99bool GitDiffFunction::diff_functions(const Path& first, const Path& second) const {
100 FunctionLoader loader;
101 auto first_function = loader.load(first);
102 auto second_function = loader.load(second);
103
104 std::string first_text = build_text_from_lines(first_function.build_all_content());
105 std::string second_text = build_text_from_lines(second_function.build_all_content());
106
107 auto result = GitTextDiff::compare(
108 first_text,
109 first_function.name(),
110 second_text,
111 second_function.name(),
112 std::cout
113 );
114
115 if (result.error != 0) {
116 std::cerr << "Failed to compute diff between functions. libgit2 error code: " << result.error << "\n";
117 return false;
118 }
119
120 if (!result.has_difference) {
121 std::cout << "No differences found between the selected functions.\n";
122 }
123
124 return true;
125}
Base class for CLI-related errors.
Definition: cli_error.hpp:10
const CliOption * options() const final
Function load(const Path &path)
Loads a function from a path.
Function load_metadata(const Path &path)
Loads function metadata from a path.
static std::string format_path_message_in_pair(const Function &function)
Formats path for display.
bool validate(const ParsedOptions &options) override
Validate the arguments already analyzed.
GitDiffFunction(Similarity_Table *_similarity_table)
bool run(const ParsedOptions &options) override
Executes the main logic of the command.
static DiffResult compare(std::string_view first_text, std::string_view first_name, std::string_view second_text, std::string_view second_name, std::ostream &output)
Definition: text_diff.cpp:89
Represents a logical path to a function in the codebase.
Definition: path.hpp:26
Represents a similarity graph between functions (paths).
const std::vector< Path > & get_path_list() const
Gets list of all known paths.
bool is_similar(const Path &path1, const Path &path2)
Checks if two paths are similar.
double get_threshold_similarity() const
Gets the similarity threshold.
Provides functionality to load Function objects from external sources.
Provides utilities for printing function information and source code.