Skip to content

Focxt #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: branch-info
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang-tools-extra/focxt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
set(LLVM_LINK_COMPONENTS support)
set(CMAKE_BUILD_TYPE Debug)
# set(CMAKE_BUILD_TYPE Debug)

include(FetchContent)

Expand Down
131 changes: 66 additions & 65 deletions clang-tools-extra/focxt/Focxt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ void get_all_files(std::string path, std::vector<std::string> *file_paths) {
// &&
// directorty_entry.find("/test") == std::string::npos &&
// directorty_entry.find("/doc") == std::string::npos &&
// directorty_entry.find("/example") == std::string::npos &&
// directorty_entry.find("/go") == std::string::npos &&
// directorty_entry.find("/java") == std::string::npos &&
// directorty_entry.find("/js") == std::string::npos &&
// directorty_entry.find("/python") == std::string::npos &&
// directorty_entry.find("/research") == std::string::npos &&
// directorty_entry.find("/scripts") == std::string::npos
) {
// directorty_entry.find("/example") == std::string::npos
&& directorty_entry.find("/go") == std::string::npos &&
directorty_entry.find("/java") == std::string::npos &&
directorty_entry.find("/js") == std::string::npos &&
directorty_entry.find("/python") == std::string::npos &&
directorty_entry.find("/research") == std::string::npos &&
directorty_entry.find("/scripts") == std::string::npos &&
directorty_entry.find("/vendor") == std::string::npos) {
get_all_files(entry.path(), file_paths);
}
}
Expand Down Expand Up @@ -131,6 +131,7 @@ int main(int argc, const char **argv) {
// freopen(output_path.c_str(), "w", stdout);
// classes_and_functions.cout();
// freopen("/dev/tty", "w", stdout);
classes_and_functions.cout_nums();
GetFileContext get_file_context(RealProjectPath, RealBuildPath, file_paths,
FocxtCategory, classes_and_functions);
get_file_context.get_all_file_contexts();
Expand Down Expand Up @@ -175,63 +176,63 @@ int main(int argc, const char **argv) {
outFile << cout_j.dump(4);
outFile.close();
}
// else {
// std::string json_path = RealProjectPath;
// std::string class_function_name;
// if (RealClassName == "") {
// class_function_name = "class::" + RealFunctionName;
// json_path = json_path + "/" + "project_cxt" + ".json";
// } else {
// class_function_name = RealClassName + "::" + RealFunctionName;
// json_path = json_path + "/" + "project_cxt" + ".json ";
// }
// json cout_j = json::object();
// if (RealTestFlag) {
// cout_j[RealFilePath] = json::object();
// cout_j[RealFilePath][class_function_name] = json::object();
// cout_j[RealFilePath][class_function_name]["may_test"] = json::object();
// cout_j[RealFilePath][class_function_name]["may_test"] =
// j[RealFilePath][class_function_name]["may_test"];
// for (auto a_test : RealTestList) {
// std::vector<TestMacro> must_test = get_must_test(file_contexts,
// a_test); if (must_test.size() != 0) {
// std::pair<std::string, std::pair<std::string, std::string>>
// must_test_class_signature =
// all_context_paths->getTest(must_test[0].second_parameter);
// cout_j[RealFilePath][class_function_name]["must_test"] =
// json::object();
// SignatureContext must_test_signature_context =
// get_signature_context(
// file_contexts, must_test_class_signature.first,
// must_test_class_signature.second.first,
// must_test_class_signature.second.second);
// json must_test_signature_j = must_test_signature_context.get_j();
// for (auto [key, value] : must_test_signature_j.items()) {
// for (auto [key1, value1] : value.items()) {
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter] = json::object();
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter] = value1;
// }
// }
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter]["test_macro"] =
// json::object();
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter]["test_macro"] =
// must_test[0].test_mecro;
// }
// }
// }
// // cout_j["type"] = "function";
// cout_j[RealFilePath][class_function_name]["focal"] = json::object();
// cout_j[RealFilePath][class_function_name]["focal"] =
// j[RealFilePath][class_function_name]["focal"];
// std::ofstream outFile;
// outFile.open(json_path);
// outFile << cout_j.dump(4);
// outFile.close();
// }
else {
std::string json_path = RealProjectPath;
std::string class_function_name;
if (RealClassName == "") {
class_function_name = RealFunctionName;
json_path = json_path + "/" + "project_cxt" + ".json";
} else {
class_function_name = RealClassName + "::" + RealFunctionName;
json_path = json_path + "/" + "project_cxt" + ".json ";
}
json cout_j = json::object();
// if (RealTestFlag) {
// cout_j[RealFilePath] = json::object();
// cout_j[RealFilePath][class_function_name] = json::object();
// cout_j[RealFilePath][class_function_name]["may_test"] = json::object();
// cout_j[RealFilePath][class_function_name]["may_test"] =
// j[RealFilePath][class_function_name]["may_test"];
// for (auto a_test : RealTestList) {
// std::vector<TestMacro> must_test = get_must_test(file_contexts,
// a_test); if (must_test.size() != 0) {
// std::pair<std::string, std::pair<std::string, std::string>>
// must_test_class_signature =
// all_context_paths->getTest(must_test[0].second_parameter);
// cout_j[RealFilePath][class_function_name]["must_test"] =
// json::object();
// SignatureContext must_test_signature_context =
// get_signature_context(
// file_contexts, must_test_class_signature.first,
// must_test_class_signature.second.first,
// must_test_class_signature.second.second);
// json must_test_signature_j = must_test_signature_context.get_j();
// for (auto [key, value] : must_test_signature_j.items()) {
// for (auto [key1, value1] : value.items()) {
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter] = json::object();
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter] = value1;
// }
// }
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter]["test_macro"] =
// json::object();
// cout_j[RealFilePath][class_function_name]["must_test"]
// [must_test[0].second_parameter]["test_macro"] =
// must_test[0].test_mecro;
// }
// }
// }
// cout_j["type"] = "function";
cout_j[RealFilePath][class_function_name]["focal"] = json::object();
cout_j[RealFilePath][class_function_name]["focal"] =
j[RealFilePath][class_function_name]["focal"];
std::ofstream outFile;
outFile.open(json_path);
outFile << cout_j.dump(4);
outFile.close();
}

delete file_paths;
return 0;
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/focxt/GetAllContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,13 @@ json FileContext::get_j(bool test_flag) {
json j;
json file_j = get_file_j();
j[file_path] = json::object();
std::cout << file_path << std::endl;
for (auto function : functions) {
// if (function.function_name == "main") {
// std::cout << std::endl;
// }
// std::cout << function.class_name << "\t" << function.function_name
// << std::endl;
std::string class_function;
if (function.class_name != "class") {
class_function = function.class_name + "::" + function.function_name;
Expand Down Expand Up @@ -924,6 +927,7 @@ void FileContexts::push_back(FileContext file_context) {
}

json FileContexts::get_j(bool test_flag) {
std::cout << "generate json" << std::endl;
json j;
for (auto file_context : file_contexts) {
j.merge_patch(file_context.get_j(test_flag));
Expand Down Expand Up @@ -1178,6 +1182,7 @@ void GetFileContext::get_all_file_contexts() {
::gac_project_path = project_path;
::gac_classes_and_functions = classes_and_functions;
for (auto file_path : *file_paths) {
std::cout << file_path << std::endl;
std::vector<const char *> args{"file_context", "-p",
compilation_database_path.c_str(),
file_path.c_str()};
Expand Down
8 changes: 7 additions & 1 deletion clang-tools-extra/focxt/GetAllDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,11 @@ void ClassesAndFunctions::cout() {
// }
}

void ClassesAndFunctions::cout_nums() {
std::cout << "there are " << classes.size() << " classes" << std::endl;
std::cout << "there are " << functions.size() << " functions" << std::endl;
}

std::vector<std::string>
ClassesAndFunctions::get_application_classes(std::string type) {
std::vector<std::string> application_classes;
Expand Down Expand Up @@ -532,6 +537,7 @@ void update_applications(std::vector<Application> &applications) {
}

void ClassesAndFunctions::update_all_applications() {
std::cout << "update all applications" << std::endl;
for (auto &a_class : classes) {
update_applications(a_class.applications);
for (auto &constructor : a_class.constructors) {
Expand Down Expand Up @@ -4586,7 +4592,7 @@ class FindClassesAndFunctionsAction : public clang::ASTFrontendAction {
void GetClassesAndFunctions::get_definitions() {
gad_project_path = project_path;
for (auto file_path : *file_paths) {
// std::cout << file_path << std::endl;
std::cout << file_path << std::endl;
std::vector<const char *> args{"context_path", "-p",
compilation_database_path.c_str(),
file_path.c_str()};
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/focxt/GetAllDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ class ClassesAndFunctions {
void push_back_destructor(std::string class_name, Destructor destructor);
void push_back_method(std::string class_name, Method method);
void cout();
void cout_nums();
void update_all_applications();
std::vector<Application> get_applications(std::string class_name,
std::string signature);
Expand Down
66 changes: 30 additions & 36 deletions clang-tools-extra/focxt/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
##### Focxt
# Focxt

该工具用于分析c++源代码每个函数的上下文信息。
该工具用于分析 c++源代码每个函数的上下文信息。

##### 前提
## 前提

使用该工具首先需要被分析项目具有类似compile_commands.json的编译数据库
使用该工具首先需要被分析项目具有类似 compile_commands.json 的编译数据库

如果被分析项目本身使用CMake管理构建,可以通过在配置CMake时添加-DCMAKE_EXPORT_COMPILE_COMMANDS=ON来生成
如果被分析项目本身使用 CMake 管理构建,可以通过在配置 CMake 时添加-DCMAKE_EXPORT_COMPILE_COMMANDS=ON 来生成

如果项目本身不使用CMake管理构建,可以考虑使用Bear来生成
如果项目本身不使用 CMake 管理构建,可以考虑使用 Bear 来生成

##### 使用
## 使用

```shell
/usr/local/bin/focxt --help
Expand Down Expand Up @@ -42,55 +42,49 @@ focxt options:
--class=<string> - Specify the class to analyze
--file=<string> - Specify the file to analyze
--function=<string> - Specify the function to analyze
--may-test - Specify get may test
--must-test=<string> - Specify must test second parameters
--project=<string> - Specify the projrct path
```

##### 用法
## 用法

###### 分析整个项目
### 分析整个项目

```
./focxt --project path/to/project --build path/to/build/directory {--may-test}
./focxt --project path/to/project --build path/to/build/directory
```

​ 其中--may-test是一个开关,搜索可能的测试函数,由于TEST(TestSuiteName, TestName) { }会被展开为class TestSuiteName_TestName_Test,所以会搜索项目中TestName包含函数名的TEST宏和宏展开后的类。

###### 分析整个文件
### 分析整个文件

```
./focxt --project path/to/project --build path/to/build/directory --file path/to/source_file {--may-test}
./focxt --project path/to/project --build path/to/build/directory --file path/to/source_file
```

###### 分析某个函数或方法
### 分析某个函数或方法

```
./focxt --project path/to/project --build path/to/build/directory --file path/to/source_file --class class_name --function function_name {--may-test {--must-test TEST_second_parameter} {--must-test TEST_second_parameter} ..}
./focxt --project path/to/project --build path/to/build/directory --file path/to/source_file --class class_name --function function_name
```

​ 其中--must-test需要输入的是TEST宏的第二个参数,开启--may-test后,才能够通过--must-test手动指定测试函数。

最终结果以*_cxt.json存储在path/to/project目录中。

##### 构建

###### 安装依赖,包括:
分析类的方法时需要传入 class_name 和 function_name;分析函数时不用传入 class_name,只用传入 function_name 就可以。

```C/C++编译工具,如gcc或clang
CMake
Ninja```
## 构建

###### 克隆并进入该项目
1. 安装依赖,包括:

```git clone https://github.com/cppbear/llvm-project.git && cd llvm-project```
1. C/C++编译工具,如`gcc`或`clang`
2. `CMake`
3. `Ninja`

###### 配置CMake
2. 配置 CMake

```cmake -S llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_ENABLE_DUMP=ON```
```
cmake -S llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_ENABLE_DUMP=ON
```

###### 构建并安装
3. 构建并安装

```cmake --build build --target focxt```
```cmake --install build --component focxt```
```cmake --install build --component clang-resource-headers```
```
cmake --build build --target focxt
cmake --install build --component focxt
cmake --install build --component clang-resource-headers
```