diff --git a/migration-agent/.gitignore b/migration-agent/.gitignore index 10b8bdb4e5451a99458f095108b29691e5b62c64..3154e03329fc436a4361a33fd061f2591a8a640f 100644 --- a/migration-agent/.gitignore +++ b/migration-agent/.gitignore @@ -12,6 +12,6 @@ tmp*/ build/ dist/ bishengai.spec - +run_test_cases.sh diff --git a/migration-agent/README.md b/migration-agent/README.md index 5c6719a9dd91e2d55480f24f6c9afede8da5b529..6b6840eb175e8562106573c681a0737bb636baf6 100644 --- a/migration-agent/README.md +++ b/migration-agent/README.md @@ -3,10 +3,16 @@ LLM for code migration project #Steps to use compiler_driver.py -## 1. Build the executable binary but running +## 1. environment +```./insatll_environment.sh``` + +## 2. run llama.cpp +```./run_llama_cpp.sh``` + +## 3. Build the executable binary but running ```source setup_compiler_driver.sh``` -## 2. Evaluate on the test cases +## 4. Evaluate on the test cases Go to test_examples set into the folder of each test case then run diff --git a/migration-agent/download_models.py b/migration-agent/download_models.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c9ad6668dee363247b00f28da1b2ef2baa27b0 --- /dev/null +++ b/migration-agent/download_models.py @@ -0,0 +1,34 @@ +from modelscope.hub.file_download import model_file_download +import os + +# 目标保存目录 +save_base_dir = "./model" +os.makedirs(save_base_dir, exist_ok=True) + +# 定义需要下载的模型仓库和对应文件 +model_files = [ + + { + "repo_id": "unsloth/Qwen3-14B-GGUF", + "file_name": "Qwen3-14B-Q4_K_M.gguf" # 请替换为实际存在的文件名 + } + +] + +# 批量下载指定文件 +for item in model_files: + repo_id = item["repo_id"] + file_name = item["file_name"] + save_path = os.path.join(save_base_dir, file_name) + + print(f"开始下载: {repo_id}/{file_name}") + try: + # 下载文件并指定保存路径 + downloaded_path = model_file_download( + model_id=repo_id, + file_path=file_name, + local_dir=save_base_dir, + ) + print(f"成功下载到: {downloaded_path}\n") + except Exception as e: + print(f"下载失败: {str(e)}\n") diff --git a/migration-agent/install_environment.sh b/migration-agent/install_environment.sh new file mode 100755 index 0000000000000000000000000000000000000000..70d8ea3f62afffc83b5ed43d32c250815d97652f --- /dev/null +++ b/migration-agent/install_environment.sh @@ -0,0 +1,73 @@ +#!/bin/bash +set -euo pipefail + +# 项目目录设置 (当前目录) +PROJECT_DIR=$(pwd) +THIRDPARTY_DIR="${PROJECT_DIR}/thirdparty" +LLAMACPP_DIR="${THIRDPARTY_DIR}/llama.cpp" +INCLUDE_DIR="${PROJECT_DIR}/include" +LIB_DIR="${PROJECT_DIR}/lib" + +check_dependency() { + if ! command -v "$1" &> /dev/null; then + echo "错误: 未找到依赖工具 $1,请先安装并确保其在PATH中" + exit 1 + fi +} +check_dependency make +# 添加Python3依赖检查 +check_dependency python3 + +# ... 现有代码 ... + +# 返回项目目录 +cd "${PROJECT_DIR}" +echo "llamacpp库下载编译完成!头文件在${INCLUDE_DIR},库文件在${LIB_DIR}" + +# 创建model目录 +echo "创建model目录..." +mkdir -p "${PROJECT_DIR}/model" + +# 后台执行downmodel.py +if [ -f "download_models.py" ]; then + echo "使用nohup后台执行downmodel.py..." + nohup python3 download_models.py > download_models.log 2>&1 & + echo "下载脚本已后台启动,日志输出到download_models.log" +else + echo "警告: 未找到download_models.py文件,跳过执行" +fi +# 创建必要目录 +mkdir -p "${THIRDPARTY_DIR}" "${INCLUDE_DIR}" "${LIB_DIR}" + + + +check_dependency git +check_dependency cmake +check_dependency make + +# 克隆llamacpp仓库 +if [ ! -d "${LLAMACPP_DIR}" ]; then + echo "克隆llamacpp仓库..." + git clone https://github.com/ggerganov/llama.cpp.git "${LLAMACPP_DIR}" +else + echo "llamacpp已存在,跳过克隆" +fi + +# 编译llamacpp (静态库) +echo "开始编译llamacpp..." +cd "${LLAMACPP_DIR}" +mkdir -p build && cd build + +# CMake配置 (默认生成Makefile,编译静态库) +cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DLLAMA_BUILD_TESTS=OFF +make -j$(nproc) + +# # 复制头文件和库文件到项目目录 +# echo "复制文件到项目目录..." +# cp "${LLAMACPP_DIR}/include/llama.h" "${INCLUDE_DIR}/" +# cp "${LLAMACPP_DIR}/build/libllama.a" "${LIB_DIR}/" + +# # 返回项目目录 +# cd "${PROJECT_DIR}" +# echo "llamacpp库下载编译完成!头文件在${INCLUDE_DIR},库文件在${LIB_DIR}" + diff --git a/migration-agent/run_llama_cpp.sh b/migration-agent/run_llama_cpp.sh new file mode 100755 index 0000000000000000000000000000000000000000..3e46bc63bc3bf6ba8e057e2bf9031724fc1d93fe --- /dev/null +++ b/migration-agent/run_llama_cpp.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# 修改模型路径为当前目录下的model目录 +MODEL_PATH="./model/Qwen3-14B-Q4_K_M.gguf" +# 调整前缀提取规则以匹配新路径 +MODEL_VAR="${MODEL_PATH#./model/}" +MODEL_VAR="${MODEL_VAR%.gguf}" +LOG_FILE="${MODEL_VAR}_$(date +%m%d%H%M%S).log" + +nohup ./thirdparty/llama.cpp/build/bin/llama-server \ + -m "$MODEL_PATH" \ + > "$LOG_FILE" 2>&1 & \ No newline at end of file diff --git a/migration-agent/run_test_cases.py b/migration-agent/run_test_cases.py new file mode 100644 index 0000000000000000000000000000000000000000..3dacf3a8a216483950717d794df1c0eba8ec58b5 --- /dev/null +++ b/migration-agent/run_test_cases.py @@ -0,0 +1,132 @@ +import os +import sys +import shutil +import tempfile +import subprocess +from pathlib import Path +from src.global_config import * +import colorama + + +# ANSI escape codes for colors +GREEN = "\033[92m" +RED = "\033[91m" +RESET = "\033[0m" # Reset color +colorama.init() + + +def copy_to_tempdir(src): + """Copy the source directory to a temporary directory and return its path.""" + dest = tempfile.mkdtemp() + shutil.copytree(src, dest, dirs_exist_ok=True) + return dest + + +# def run_build_script(script_path): +# """Source the build script and capture its environment variables.""" +# command = f"source {script_path}" + +# os.system(command) + + +def init(): + """Initialize the environment and print build status.""" + print("Building BiSheng AI... \t\t\t", end="", flush=True) + # run_build_script("setup_compiler_driver.sh") + print("Done") + + print(f"CC={os.environ.get('CC')}") + print(f"CXX={os.environ.get('CXX')}") + + os.environ["AUTO_ACCEPT"] = "1" + os.environ["LLM_SILENT"] = "1" + # os.environ["LLM_RETRY_TIMES"] = "1" + os.environ["LLM_DEVELOPMENT"] = "0" + + +def run_make_command(test_case, command): + """Run the make command in the given directory and return the result.""" + # 让输出直接打到终端 + result = subprocess.run( + command, + shell=True, + cwd=test_case, + # stdout=None, # subprocess.PIPE, + # stderr=None, # subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + # print(result.returncode) # 只打印退出码 + return result + +def run_one_test_case(test_case, work_dir): + """Compile and check the result of a single test case.""" + print(f"Compile {test_case.relative_to(work_dir)} ...\t\t\t\t", end="", flush=True) + + # Clean and make + run_make_command(test_case, "make clean") + result = run_make_command(test_case, "make") + + if result.returncode == 0: + print(f" [{GREEN}PASS{RESET}]") + else: + print(f" [{RED}FAILED{RESET}]") + + return result.returncode + + +def collect_test_folders(work_dir): + """Collect all subfolders (test cases) within the given directory.""" + folder_path = Path(work_dir) + test_folders = [ + subfolder for subfolder in folder_path.iterdir() if subfolder.is_dir() + ] + return test_folders + + +def print_test_summary(num_test_cases, num_pass, num_failed): + """Print the summary of the test results.""" + pass_rate = (num_pass / num_test_cases) * 100 if num_test_cases > 0 else 0 + print( + f"Tested {num_test_cases} test cases, passed {num_pass}, failed {num_failed}, pass rate: {pass_rate:.2f}%" + ) + + +def run_test(test_sample_path): + """Run all tests in the provided sample path.""" + work_dir = copy_to_tempdir(test_sample_path) + print(f"Running tests using {get_model_id()} as the LLM.") + + test_folders = collect_test_folders(work_dir) + + num_test_cases = 0 + num_pass = 0 + num_failed = 0 + + for category in test_folders: + test_category_folders = collect_test_folders(category) + for folder in test_category_folders: + ret = run_one_test_case(folder, work_dir) + num_test_cases += 1 + if ret == 0: + num_pass += 1 + else: + num_failed += 1 + + print_test_summary(num_test_cases, num_pass, num_failed) + + # Clean up the temporary working directory + try: + shutil.rmtree(work_dir) + except Exception as e: + print(f"Failed to clean up temp directory: {e}") + + +if __name__ == "__main__": + test_sample_path = "test_examples" + if len(sys.argv) > 1: + test_sample_path = sys.argv[1] + + init() + run_test(test_sample_path) diff --git a/migration-agent/setup_compiler_driver.sh b/migration-agent/setup_compiler_driver.sh index 07c9469ee343d6b84bc5b75dfadd280a67a577bb..6f8c35217171f851badadb63c07bb4df2bbed368 100644 --- a/migration-agent/setup_compiler_driver.sh +++ b/migration-agent/setup_compiler_driver.sh @@ -2,20 +2,29 @@ pip install pyinstaller rm -rf build/ rm -rf dist/ -rm bishengai.spec +rm -f bishengai.spec TARGET="bishengai" SOURCE="src/compiler_driver.py" pyinstaller --onefile $SOURCE --name $TARGET export CC=`pwd`/dist/$TARGET export CXX=$CC -export LLM_DEVELOPMENT=1 +export LLM_DEVELOPMENT=0 # export COMPILER_CHOICE="clang++" # "clang" for c; "clang++"" for c++ export LLM_DEBUG=1 export AUTO_ACCEPT=1 # not export-interactive window; export-automatically change -export LLM_API_TOKEN= # add your api token here -~ -~ -~ -~ -~ + +# 1:流式 0:非流式 +export ENABLE_STREAM=0 + +# openai +# export LLM_MODEL_TYPE=openai +# export LLM_API_TOKEN=xxxxxxxxxxxxxx +# # export LLM_MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-14B +# export LLM_MODEL=Qwen/Qwen3-14B +# export LLM_URL=https://api.siliconflow.cn/v1/chat/completions + + +export LLM_MODEL_TYPE=openai +export LLM_MODEL=./model/Qwen3-14B-Q4_K_M.gguf +export LLM_URL=http://127.0.0.1:8080/v1/chat/completions \ No newline at end of file diff --git a/migration-agent/src/compiler_driver.py b/migration-agent/src/compiler_driver.py index 1c10dff73aff20558c40ad590d67ae2604a803d3..dcf008e1b905e0c11c561190dd35ccbc263ffc0f 100644 --- a/migration-agent/src/compiler_driver.py +++ b/migration-agent/src/compiler_driver.py @@ -91,6 +91,7 @@ class CompilerErrorHandler: self.new_folders = [] def compile_and_repair(self, compile_targets_options): + logging.info(f"max_attempts: {self.max_attempts}") """Attempt to compile and repair errors.""" if self.compiler not in compile_targets_options: command = [self.compiler] + compile_targets_options @@ -107,6 +108,7 @@ class CompilerErrorHandler: while self.attempts < self.max_attempts: self.attempts += 1 + logging.info(f"Attempt {self.attempts} to repair the error.") command, repair_prompt_template = self.repair( command, compiler_output, prompt_template ) @@ -115,6 +117,7 @@ class CompilerErrorHandler: self.compiler_outputs.append(compiler_output) if success: logging.info("Successfully fixed the error.") + self.return_code = 0 # Reset return code to 0 on success break pe = PromptEngine(repair_prompt_template) @@ -130,15 +133,16 @@ class CompilerErrorHandler: FileManager.restore_files( source_paths=self.source_paths, backup_path=self.backup_path ) + # self.return_code = 1 def compile(self, command): """Call the compiler and handle errors.""" try: result = subprocess.run(command, capture_output=True, text=True, check=True) - print(result.stdout) + # print("compiler output:", result.stdout) return result.stdout, True except Exception as e: - print(e.stderr, file=sys.stderr) + # print("compiler error:", e.stderr, file=sys.stderr) if not self.return_code: self.return_code = e.returncode return e.stderr, False @@ -313,8 +317,9 @@ def main(): logging.error(f"Error occurred: {e}") finally: error_handler.clean_up() + # logging.info("return code: %s", error_handler.return_code) if error_handler.return_code: - return error_handler.return_code + sys.exit(error_handler.return_code) else: return 0 diff --git a/migration-agent/src/global_config.py b/migration-agent/src/global_config.py index 53e029b5f274367cd1a01c097981b3b28465d734..9bdb30948a93d1d097b3e4d38614ad9d4119ff34 100644 --- a/migration-agent/src/global_config.py +++ b/migration-agent/src/global_config.py @@ -3,12 +3,17 @@ This defines the global configurations for the compiler driver """ import logging +from enum import Enum import os from termcolor import colored # Global Constants LOG_FILE = "llm4compiler.log" -llm_url = "https://api.siliconflow.cn/v1/chat/completions" + +class ModelType(str, Enum): + LOCAL_OLLAMA = "local_ollama" # 本地Ollama部署 + OPENAI = "openai" # OpenAI API + LLAMA_CPP_CPU = "llama_cpp_cpu" # llama.cpp CPU部署 # Function to get the api token for siliconflow @@ -17,6 +22,22 @@ def get_llm_api_token() -> str: return os.getenv("LLM_API_TOKEN", "") llm_api_token = get_llm_api_token() +def get_model_type() -> ModelType: + """Return the LLM model type""" + return ModelType(os.getenv("LLM_MODEL_TYPE", ModelType.OPENAI)) + +def get_enable_stream() -> bool: + value = os.getenv("ENABLE_STREAM", "0") + mapping = { + "1": True, + "0": False + } + return mapping.get(value, False) + +def get_llm_url() -> str: + """Return the LLM url""" + return os.getenv("LLM_URL", "") + # Function to check if automatic acceptance of LLM code changes is enabled def is_auto_accept_code_change() -> bool: @@ -27,8 +48,8 @@ def is_auto_accept_code_change() -> bool: # Function to check if the compiler driver is running in development mode def is_development_mode() -> bool: """Return True if running in development mode.""" - return bool(os.getenv("LLM_DEVELOPMENT", True)) # Default to True if not set - + # return bool(os.getenv("LLM_DEVELOPMENT", True)) # Default to True if not set + return False # Return the LLM model ID, default to a preconfigured model def get_model_id() -> str: @@ -47,6 +68,7 @@ def get_llm_retry_times() -> int: """Return the number of retry attempts for LLM. Default is 5, max 10.""" try: retry_times = int(os.getenv("LLM_RETRY_TIMES", 5)) + logging.info(f"LLM retry times: {retry_times}") return min(max(retry_times, 1), 10) # Ensure retry times is between 1 and 10 except ValueError: return 5 @@ -114,3 +136,7 @@ def configure_logging(): # Initialize logging configure_logging() + +def get_llamacpp_model_path(): + """获取 LlamaCPP 模型路径""" + return os.environ.get("LLAMACPP_MODEL_PATH", "/path/to/default/model.gguf") diff --git a/migration-agent/src/inference.py b/migration-agent/src/inference.py index 5ddef41c8f1e7405d178aaf3f9d2b0b6fb7f148e..a8caeb39dfacc96ad5022ad57905b928bb656b4d 100644 --- a/migration-agent/src/inference.py +++ b/migration-agent/src/inference.py @@ -11,39 +11,77 @@ from utilities.llms import LLM from utilities.utilities import pretty_print_code, pretty_print_dialog from global_config import * import re +import os class LLMRepair: def __init__(self): self.llm = LLM() + + # 定义JSON Schema + self.json_schema = { + "type": "object", + "required": ["code_changes", "compiler_options", "reasoning"], + "properties": { + "code_changes": { + "type": "object", + "description": "修改后的源代码,键为文件路径,值为完整代码" + }, + "compiler_options": { + "type": "string", + "description": "编译选项,可以是字符串或字符串数组" + }, + "reasoning": { + "type": "string", + "description": "修改原因的简要说明" + } + }, + "additionalProperties": False + } + + # 改进的修复提示模板 + # Improved repair prompt template with strict format enforcement + self.repair_prompt_template = ( - "Given the following LLVM/Clang compilation errors, compiler command, and source code, provide a solution to fix the error. " - "If this can be fixed by modifying the code, provide the revised code (as a whole) and reasoning in a JSON object. " - "If this can be fixed by changing the compiler options, place the new compiler command in the 'compiler_options' field along with reasoning. " - 'Organise the code change per file. A json output example could be json {"code_changes":{"path to the source file": "code"}, "compiler_options", "compiler_options", "reasoning", "reasoning"} ' - "Ensure that strings (especially multiline strings) are properly escaped, but do not just escape space. " - "Do not produce text other than the JSON object. Keep the reasoning text concise." + "You are a senior C/C++ compilation error repair expert. Return the solution STRICTLY in the following JSON format:\n\n" + f"JSON SCHEMA: {json.dumps(self.json_schema, indent=2)}\n\n" + "CRITICAL REQUIREMENTS:\n" + "1. Return ONLY a single valid JSON object - NO preliminary text, explanations, or trailing content\n" + "2. JSON must start with '{' and end with '}' with NO leading/trailing whitespace\n" + "3. Escape all special characters in strings (e.g., use \\\" for internal quotes)\n" + "4. For code fixes: Provide COMPLETE modified source code (not snippets) in 'code_changes'\n" + "5. For compiler option fixes: Provide the FULL corrected command in 'compiler_options'\n" + "6. Omit all diagnostic/thinking processes - output ONLY the JSON payload\n\n" + # "7. STRICTLY PROHIBITED: Any form of delimiters (e.g., ```, ===, ) or markers around the JSON\n" + # "8. OUTPUT MUST CONTAIN ONLY JSON - ANY NON-JSON CONTENT WILL RESULT IN TOTAL REJECTION\n" + "Based on the following compilation error, compiler command, and source code, provide the definitive repair solution:" ) - - self.template_code_suffix = "The code from [SOURCE_FILE] is: ``` [CODE] ```, " + + self.template_code_suffix = "The complete code from [SOURCE_FILE] is as follows: ``` [CODE] ```, " self.repair_prompt_template_suffix = ( - "the compiler command is: ``` [COMMAND] ```, " - "the compilation error is: ``` [ERROR] ```" + "The exact compiler command used is: ``` [COMMAND] ```\n" + "The complete compilation error output is: ``` [ERROR] ```" ) + + # Improved source file extraction prompt with technical specificity self.extract_prompt_template = ( - "I want you to act as an expert programmer to help me fix a compilation error. " - "Given the following compilation error message and content of the relevant file, determine if there is additional source file you " - "need to see to diagnose the issue." - "Respond in JSON format with two fields: " - "source_file: The name of the source file you need to see. If the issue can be " - "resolved without viewing any source file, return None. " - "reasoning: A brief explanation of why this file is needed or why no file is required." - "Do not show your reasoning process, only return the JSON response and ensure valid JSON escapes." + "As a compiler diagnostics expert, analyze the compilation error to determine if additional source files must be examined.\n" + "Return STRICTLY a JSON object in THIS format (NO explanations outside JSON):\n\n" + "{\n" + ' "source_file": "filename to inspect (or null if no additional files needed)",\n' + ' "reasoning": "concise technical justification (max 50 words) for needing or excluding the file"\n' + "}\n\n" + "JUSTIFICATION GUIDELINES:\n" + "- Reference specific error tokens/line numbers when possible\n" + "- Explain dependency relationships (e.g., 'error references type defined in header')\n" + "- Use 'null' ONLY when error is fully contained in provided files" ) + + self.extract_prompt_template_suffix = ( - "the compiler command is: ``` [COMMAND] ```, " - "the compilation error is: ``` [ERROR] ```, " + "The compiler command executed was: ``` [COMMAND] ```\n" + "The complete error output from compilation is: ``` [ERROR] ```, " ) # Get prompt template @@ -55,7 +93,7 @@ class LLMRepair: return self.llm.get_model_id() def extract_json_objects(self, text, decoder=JSONDecoder()): - """Extracts JSON objects from text.""" + """提取文本中的JSON对象""" pos = 0 while True: match = text.find("{", pos) @@ -69,10 +107,13 @@ class LLMRepair: pos = match + 1 def _extract_code_changes(self, code_changes): - """Extract and log code changes from LLM response.""" + """从LLM响应中提取并记录代码更改""" code = {} if code_changes: for source, code_text in code_changes.items(): + # 将列表转换为字符串(按行拼接) + if isinstance(code_text, list): + code_text = '\n'.join(map(str, code_text)) code[source] = code_text logging.debug( pretty_print_code(f"LLM Generated Code for {source}", code_text) @@ -80,48 +121,89 @@ class LLMRepair: return code def _extract_compiler_options(self, data): - """Extract compiler options from LLM response.""" + """从LLM响应中提取编译选项""" compiler_options = data.get("compiler_options") if compiler_options: + # 处理数组类型的编译选项 + if isinstance(compiler_options, list): + compiler_options = " ".join(str(option) for option in compiler_options) + logging.warning("编译选项返回为数组类型,已自动转换为字符串") + logging.debug( pretty_print_dialog("LLM suggested options", compiler_options) ) return compiler_options def _extract_reasoning(self, data, reasoning_content): - """Extract reasoning from LLM response.""" + """从LLM响应中提取推理说明""" reasoning = data.get("reasoning") return reasoning if reasoning else reasoning_content def _extract_source_target(self, data): - """Extract the source file required from LLM response.""" + """从LLM响应中提取所需的源文件""" return data.get("source_file") - def process_response(self, message_content, reasoning_content): - # Remove redundant texts before ``json { - def remove_redundant_text(input_string): - # Use regular expression to remove everything before the `json{...}` part - cleaned_string = re.sub( - r".*```json\s*{", "```json {", input_string, flags=re.DOTALL - ) - return cleaned_string - - logging.debug(pretty_print_dialog("LLM inference raw data", message_content)) - # if reasoning_content: - # logging.debug(pretty_print_dialog("CoT raw data", reasoning_content)) - - message_content = remove_redundant_text(message_content) - message_content = message_content.replace("```json", "").replace("```", "") + def process_response(self, message_content, reasoning_content, max_retries=2): + """处理LLM响应,确保有效的JSON格式""" + # 记录原始响应用于调试 + logging.debug(f"\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" + f"+ LLM inference raw data +\n+ {message_content} +\n" + f"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n") + + # 清理响应内容 + def clean_json_content(content): + # 移除Markdown代码块标记 + content = re.sub(r'.*?', '', content, flags=re.DOTALL) + content = re.sub(r'```(?:json)?\s*|\s*```', '', content, flags=re.DOTALL) + + # 查找第一个 { 和最后一个 } 之间的内容 + start_idx = content.find('{') + end_idx = content.rfind('}') + + if start_idx != -1 and end_idx > start_idx: + return content[start_idx:end_idx+1] + return content + + # 清理消息内容 + cleaned_content = clean_json_content(message_content) + logging.debug(f"Cleaned JSON content: {cleaned_content}") + try: - # logging.debug(f"RAW JSON DATA {message_content}") - data = demjson3.decode(message_content) + # 尝试解析JSON + data = demjson3.decode(cleaned_content) + except Exception as e: - logging.debug(f"Failed to parse json data {message_content} {e}") - return {} - # data = next(self.extract_json_objects(message_content)) + logging.debug(f"Failed to parse json data {cleaned_content} {str(e)}") + + # 检查重试次数 + if max_retries <= 0: + logging.warning("Max retries reached for JSON correction") + return {} + + # 准备重试提示 + retry_prompt = ( + f"你的上一个JSON响应无效,解析错误: {str(e)}\n" + f"问题内容开头: {cleaned_content[:50]}...\n\n" + "请提供一个严格有效的JSON对象,必须满足以下要求:\n" + "1. JSON必须以'{'开始,以'}'结束\n" + "2. 不能有任何前导字符或注释\n" + "3. 所有字符串必须正确转义(例如: 使用\\\"表示内部引号)\n" + "4. 不要在JSON外包含任何文本\n" + "5. 不要输出任何思考过程\n\n" + f"JSON SCHEMA: {json.dumps(self.json_schema, indent=2)}\n\n" + "仅返回修正后的JSON,不要有任何额外内容。" + ) + + # 递归调用减少重试次数 + return self.inference( + prompt=retry_prompt, + task_msg="to correct invalid JSON", + max_retries=max_retries - 1 + ) + # 提取并返回结果 res = { - "code": self._extract_code_changes(data.get("code_changes")), + "code": self._extract_code_changes(data.get("code_changes", {})), "compiler_options": self._extract_compiler_options(data), "reasoning": self._extract_reasoning(data, reasoning_content), "source_file": self._extract_source_target(data), @@ -130,10 +212,11 @@ class LLMRepair: return res def populate_prompt_template(self, template: str, command: str, error: str) -> str: - """Populate the prompt template with command and error.""" + """填充提示模板中的命令和错误信息""" return template.replace("[COMMAND]", command).replace("[ERROR]", error) def populate_code_to_prompt(self, prompt, code: dict): + """将代码添加到提示中""" if code: for file, c in code.items(): prompt += self.template_code_suffix.replace( @@ -141,52 +224,65 @@ class LLMRepair: ).replace("[CODE]", c) return prompt - def query_llm_for_fix( - self, code: dict, command, error, prompt_template=None, model_id=None - ): - """Query LLM for fix based on code, command, and error.""" + def query_llm_for_fix(self, code: dict, command, error, prompt_template=None, model_id=None): + """Query LLM for error repair solution based on code, command and error""" prompt = prompt_template or self.repair_prompt_template prompt = self.populate_code_to_prompt(prompt=prompt, code=code) prompt += self.repair_prompt_template_suffix + + # Add final format enforcement + prompt += "\n\nFINAL VALIDATION: Your response must parse as valid JSON using standard JSON parsers. Any deviation will be rejected." + return self.inference( prompt=self.populate_prompt_template(prompt, command, error), model_id=model_id, - task_msg="to repair errors.", + task_msg="to repair compilation errors.", ) - def query_llm_for_source_file( self, code: dict, command, error, prompt_template=None, model_id=None ): - """Query LLM for the source file required to fix the issue.""" + """查询LLM确定解决问题所需的源文件""" prompt = prompt_template or self.extract_prompt_template prompt += self.extract_prompt_template_suffix prompt = self.populate_code_to_prompt(prompt=prompt, code=code) + + # 添加强调不要输出思考过程的指令 + prompt += "\n\n重要说明: 只返回JSON结果,不要输出思考过程。" + return self.inference( prompt=self.populate_prompt_template(prompt, command, error), model_id=model_id, task_msg="to locate relevant source files.", ) - def inference(self, prompt, model_id=None, task_msg=""): - """Perform inference by querying the LLM.""" + def inference(self, prompt, model_id=None, task_msg="", max_retries=2): + """通过查询LLM执行推理""" prev_model = self.llm.get_model_id() if model_id: self.llm.set_model_id(model_id) else: model_id = self.llm.get_model_id() + # 添加格式控制指令 + format_instruction = ( + "\n\nNON-NEGOTIABLE FORMAT REQUIREMENTS:\n" + "1. Output contains EXACTLY ONE JSON object\n" + "2. JSON must validate against RFC 8259 standards\n" + "3. No comments, markdown, or explanatory text\n" + "4. String values must use proper escape sequences\n" + "5. Ensure trailing braces are present and properly placed" + ) + enhanced_prompt = prompt + format_instruction + logging.info(f"Calling {model_id} {task_msg}") - # logging.debug(f"prompt={prompt}") - response = self.llm.inference(prompt) + response = self.llm.inference(enhanced_prompt) if response: - data = json.loads(response.text) - message_content = data.get("choices")[0].get("message").get("content") - reasoning_content = ( - data.get("choices")[0].get("message").get("reasoning_content") - ) + message_content = response.get("content", "") + reasoning_content = response.get("reasoning_content", "") self.llm.set_model_id(prev_model) - return self.process_response(message_content, reasoning_content) + return self.process_response(message_content, reasoning_content, max_retries=max_retries) logging.error("Failed in getting the inference response") self.llm.set_model_id(prev_model) + return {} \ No newline at end of file diff --git a/migration-agent/src/utilities/llms.py b/migration-agent/src/utilities/llms.py index 0f512e26e4484d0ed27b6e75aa7734e8229b7a96..85419f08a544a6a5c520f271ebb386cd95ee2e05 100644 --- a/migration-agent/src/utilities/llms.py +++ b/migration-agent/src/utilities/llms.py @@ -1,8 +1,10 @@ """ This defines LLM related utility functions """ +import json import requests import logging from global_config import * +# from llama_cpp import Llama # Suppress all warnings for cleaner output import warnings @@ -10,6 +12,12 @@ import warnings warnings.filterwarnings("ignore") +# class ModelType: +# OPENAI = "openai" +# LOCAL_OLLAMA = "local_ollama" +# LLAMA_CPP_CPU = "llama_cpp_cpu" # llama.cpp CPU部署 + + class LLM: def __init__(self): """Initialize LLM instance with the model ID and API headers.""" @@ -32,6 +40,18 @@ class LLM: self.model_id = model_id def inference(self, prompt): + model_type = get_model_type() + if model_type == ModelType.OPENAI: + return self.openapi_inference(prompt) + elif model_type == ModelType.LOCAL_OLLAMA: + return self.local_ollama_inference(prompt) + # elif model_type == ModelType.LLAMA_CPP_CPU: + # return self.local_llamacpp_inference(prompt) + else: + logging.error(f"Unsupported model type: {model_type}") + return {"content": "", "reasoning_content": ""} + + def openapi_inference(self, prompt): payload = { "model": self.model_id, "messages": [ @@ -41,17 +61,374 @@ class LLM: } ], "temperature": 0.3, + "stream": get_enable_stream(), } - response = requests.request( - "POST", - llm_url, - json=payload, - headers=self.headers, - verify=False, - ) - # Successfully getting the inference response - if response.status_code == 200: - return response - else: - return None + try: + response = requests.post( + get_llm_url(), + json=payload, + headers=self.headers, + verify=False, + stream=get_enable_stream() + ) + response.raise_for_status() + + if get_enable_stream(): + content, reasoning_content = self._process_openai_stream(response) + else: + content, reasoning_content = self._process_openai_non_stream(response) + return {"content": content, "reasoning_content": reasoning_content} + except requests.exceptions.RequestException as e: + logging.error(f"OpenAI request failed: {e}") + return {"content": "", "reasoning_content": ""} + + def _process_openai_stream(self, response): + full_content = "" + reasoning_content = "" + + for line in response.iter_lines(): + if not line: + continue + + # 解码并清理响应行,移除 'data: ' 前缀 + decoded_line = line.decode('utf-8').replace("data: ", "") + + # 判断是否为流式响应的结束标记 + if decoded_line == "[DONE]": + break + + try: + data = json.loads(decoded_line) + content_part = "" + reasoning_part = "" + # 从 JSON 数据中提取 content 和 reasoning_content + if 'choices' in data and data['choices']: + delta = data['choices'][0].get('delta', {}) + content_part = delta.get('content', '') + if content_part is None: + content_part = "" + reasoning_part = delta.get('reasoning_content') + if reasoning_part is None: + reasoning_part = "" + full_content += content_part + reasoning_content += reasoning_part + except json.JSONDecodeError: + logging.debug("Failed to decode JSON line in stream response") + continue + + return full_content, reasoning_content + + def _process_openai_non_stream(self, response): + content = "" + reasoning_content = "" + try: + data = response.json() + if 'choices' in data and data['choices']: + content = data['choices'][0]['message']['content'] + reasoning_content = data['choices'][0]['message'].get('reasoning_content', '') + except (KeyError, IndexError, ValueError): + logging.error("Failed to parse OpenAI response JSON") + return content, reasoning_content + + def local_ollama_inference(self, prompt): + payload = { + "model": self.model_id, + "prompt": prompt, + "options": { + "temperature": 0.3 + }, + "stream": get_enable_stream() + } + + try: + response = requests.post( + get_llm_url(), + json=payload, + headers=self.headers, + verify=False, + stream=get_enable_stream(), + timeout=30 + ) + response.raise_for_status() + + if get_enable_stream(): + content, reasoning_content = self._process_ollama_stream(response) + else: + content, reasoning_content = self._process_ollama_non_stream(response) + return {"content": content, "reasoning_content": reasoning_content} + except requests.exceptions.RequestException as e: + logging.error(f"Ollama request failed: {e}") + return {"content": "", "reasoning_content": ""} + + def _process_ollama_stream(self, response): + full_content = "" + reasoning_content = "" + for line in response.iter_lines(): + if line: + try: + line_decoded = line.decode('utf-8') + data = json.loads(line_decoded) + response_text = data.get('response', '') + if response_text is None: + response_text = "" + full_content += response_text + reasoning_delta = data.get('reasoning_content', '') + if reasoning_delta is None: + reasoning_delta = "" + reasoning_content += reasoning_delta + + if data.get('done'): + break + except json.JSONDecodeError as e: + logging.debug(f"Failed to decode JSON: {e}") + continue + + # 处理完整内容,移除 ... 部分 + import re + think_pattern = re.compile(r'.*?', re.DOTALL) + full_content = think_pattern.sub('', full_content).strip() + + # 记录清理后的内容供调试 + logging.debug(f"Processed content: {full_content[:200]}...") + + return full_content, reasoning_content + + def _process_ollama_non_stream(self, response): + content = "" + reasoning_content = "" + try: + # 检查 response 是否已经是字典 + if isinstance(response, dict): + data = response + else: + data = response.json() + + # 获取响应内容 + content = data.get('response', '') or data.get('content', '') + + # 移除 ... 部分 + import re + think_pattern = re.compile(r'.*?', re.DOTALL) + content = think_pattern.sub('', content).strip() + + # 获取推理内容 + reasoning_content = data.get('reasoning_content', '') + except Exception as e: + logging.error(f"Failed to parse Ollama response JSON: {str(e)}") + return content, reasoning_content + + # def local_llamacpp_inference(self, prompt): + # """使用本地 LlamaCPP 模型进行推理""" + # try: + + + # # 从环境变量获取模型路径 + # model_path = get_llamacpp_model_path() + + # # 硬编码三个参数 + # n_ctx = 4096 # 上下文窗口大小硬编码为4096 + # n_threads = 4 # 线程数硬编码为4 + # n_batch = 512 # 批处理大小硬编码为512 + + # logging.info(f"使用 LlamaCPP 模型: {model_path}") + + # # 如果模型尚未加载,则加载模型 + # if not hasattr(self, 'llamacpp_model') or self.llamacpp_model is None: + # logging.info(f"加载 LlamaCPP 模型中...") + # self.llamacpp_model = Llama( + # model_path=model_path, + # n_ctx=n_ctx, + # n_threads=n_threads, + # n_batch=n_batch + # ) + # logging.info("LlamaCPP 模型加载完成") + + # # 进行推理 + # logging.debug(f"开始 LlamaCPP 推理,提示词前100字符: {prompt[:100]}...") + + # # 是否使用流式推理 + # if get_enable_stream(): + # content, reasoning_content = self._process_llamacpp_stream(prompt) + # else: + # content, reasoning_content = self._process_llamacpp_non_stream(prompt) + + # return {"content": content, "reasoning_content": reasoning_content} + + # except ImportError: + # logging.error("未安装 llama-cpp-python 库,请执行: pip install llama-cpp-python") + # return {"content": "", "reasoning_content": ""} + # except Exception as e: + # logging.error(f"LlamaCPP 推理失败: {str(e)}") + # return {"content": "", "reasoning_content": ""} + + # def _process_llamacpp_stream(self, prompt): + # """处理 LlamaCPP 流式输出""" + # full_content = "" + # reasoning_content = "" + + # try: + # # 硬编码最大生成token数 + # max_tokens = 2048 + + # # 使用 LlamaCPP 的流式生成功能 + # for output in self.llamacpp_model.create_completion( + # prompt, + # max_tokens=max_tokens, + # temperature=0.3, + # stream=True + # ): + # if "choices" in output and output["choices"]: + # chunk = output["choices"][0].get("text", "") + # full_content += chunk + # logging.debug(f"接收流式数据: {len(chunk)} 字符") + + # # 处理完整内容,移除 ... 部分 + # import re + # think_pattern = re.compile(r'.*?', re.DOTALL) + # full_content = think_pattern.sub('', full_content).strip() + + # # 记录清理后的内容供调试 + # logging.debug(f"处理后的内容前200字符: {full_content[:200]}...") + + # except Exception as e: + # logging.error(f"流式处理失败: {str(e)}") + + # return full_content, reasoning_content + + # def _process_llamacpp_non_stream(self, prompt): + # """处理 LlamaCPP 非流式输出""" + # content = "" + # reasoning_content = "" + + # try: + # # 硬编码最大生成token数 + # max_tokens = 2048 + + # # 执行推理 + # output = self.llamacpp_model.create_completion( + # prompt, + # max_tokens=max_tokens, + # temperature=0.3, + # stream=False + # ) + + # if "choices" in output and output["choices"]: + # content = output["choices"][0].get("text", "") + + # # 移除 ... 部分 + # import re + # think_pattern = re.compile(r'.*?', re.DOTALL) + # content = think_pattern.sub('', content).strip() + + # # 记录清理后的内容供调试 + # logging.debug(f"处理后的内容前200字符: {content[:200]}...") + + # except Exception as e: + # logging.error(f"非流式处理失败: {str(e)}") + + # return content, reasoning_content + +# """ This defines LLM related utility functions """ + +# import requests +# import logging +# from global_config import * + +# # Suppress all warnings for cleaner output +# import warnings + +# warnings.filterwarnings("ignore") + + +# class LLM: +# def __init__(self, local_mode=False, ollama_url="http://localhost:11434"): +# """Initialize LLM instance with the model ID and API headers.""" +# self.local_mode = local_mode +# self.ollama_url = ollama_url +# if not local_mode: +# self.headers = { +# "Authorization": self.get_api_token(), +# "Content-Type": "application/json", +# } +# else: +# self.headers = { +# "Content-Type": "application/json", +# } +# self.model_id = get_model_id() + +# def get_api_token(self) -> str: +# """Return the API token required for authorization.""" +# return f"Bearer {llm_api_token}" + +# def get_model_id(self): +# """Return the current LLM model ID.""" +# return self.model_id + +# def set_model_id(self, model_id: str): +# """Set the model ID for the LLM.""" +# self.model_id = model_id + +# def inference(self, prompt): +# if self.local_mode: +# return self._ollama_inference(prompt) +# else: +# return self._cloud_inference(prompt) + +# def _cloud_inference(self, prompt): +# payload = { +# "model": self.model_id, +# "messages": [ +# { +# "role": "user", +# "content": prompt, +# } +# ], +# "temperature": 0.3, +# } + +# response = requests.request( +# "POST", +# llm_url, +# json=payload, +# headers=self.headers, +# verify=False, +# ) +# # Successfully getting the inference response +# if response.status_code == 200: +# return response +# else: +# return None + +# def _ollama_inference(self, prompt): +# """Use Ollama local service for inference""" +# payload = { +# "model": self.model_id, +# "prompt": prompt, +# "options": { +# "temperature": 0.3 +# } +# } + +# try: +# # 添加调试日志 +# logging.debug(f"Sending request to Ollama at {self.ollama_url}") +# logging.debug(f"Payload: {payload}") + +# response = requests.post( +# f"{self.ollama_url}/api/generate", +# json=payload, +# headers=self.headers, +# verify=False, +# timeout=30 # 添加超时 +# ) + +# # 添加响应日志 +# logging.debug(f"Ollama response status: {response.status_code}") +# if response.status_code == 200: +# logging.debug(f"Response content: {response.text[:200]}...") # 截取部分内容 +# return response.json() +# return None +# except requests.exceptions.RequestException as e: +# logging.error(f"Ollama request failed: {e}") +# return None diff --git a/migration-agent/test_examples/assembly_errors/test1/makefile b/migration-agent/test_examples/assembly_errors/test1/makefile new file mode 100644 index 0000000000000000000000000000000000000000..72ba0795f1a85283dd2b9d61e4f5152fbdddab77 --- /dev/null +++ b/migration-agent/test_examples/assembly_errors/test1/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifndef CXX + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/assembly_errors/test1/test.cpp b/migration-agent/test_examples/assembly_errors/test1/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21eb8d2b5574ab590b1e4f02390a3d985940ab75 --- /dev/null +++ b/migration-agent/test_examples/assembly_errors/test1/test.cpp @@ -0,0 +1,22 @@ +typedef unsigned long long __attribute__((aligned((8)))) u64a; +typedef signed char __int8_t; +typedef __int8_t int8_t; +typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t; + +typedef union { + int8x16_t vect_s8; + +} __m128i; + +typedef __m128i m128; + + +static inline __attribute__ ((always_inline, unused)) m128 load_m128_from_u64a(const u64a *p) { + m128 result; + __asm__ __volatile__("ldr %d0, %1 \n\t" + : "=w"(result) + : "Utv"(*p) + : + ); + return result; +} diff --git a/migration-agent/test_examples/compiler_options/test1/makefile b/migration-agent/test_examples/compiler_options/test1/makefile new file mode 100644 index 0000000000000000000000000000000000000000..27edfc2c0a51341b8984c8a455cf8204d0b76ec3 --- /dev/null +++ b/migration-agent/test_examples/compiler_options/test1/makefile @@ -0,0 +1,37 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -fanalyzer -std=c++11 + +# Output executable name +TARGET = test + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: $(TARGET) +# all: +# $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Rule to create the executable +$(TARGET): $(OBJ) + $(CXX) $(OBJ) -o $(TARGET) + +# Rule to compile .cpp files into .o files +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean up object and executable files +clean: + rm -f $(OBJ) $(TARGET) + +.PHONY: all clean diff --git a/migration-agent/test_examples/compiler_options/test1/test.cpp b/migration-agent/test_examples/compiler_options/test1/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e575ad17d78d126c50d657925bcbe5c3913c180a --- /dev/null +++ b/migration-agent/test_examples/compiler_options/test1/test.cpp @@ -0,0 +1,8 @@ +#include + +using namespace std; + +int main() { + cout << "Hello World\n" << endl; + return 0; +} diff --git a/migration-agent/test_examples/link_errors/test1/makefile b/migration-agent/test_examples/link_errors/test1/makefile new file mode 100644 index 0000000000000000000000000000000000000000..83eea5e3b94eabe8caa6522af79eaddb00daa1a8 --- /dev/null +++ b/migration-agent/test_examples/link_errors/test1/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CC),) + CC = clang +endif + + +# Compiler flags, -nostdinc -iwithprefix include差异 +CFLAGS = -nostdinc -iwithprefix include -Wall + +# Source files +SRC = test.c + +# Object files +OBJ = $(SRC:.c=.o) + +# Default rule +all: + $(CC) $(CFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/link_errors/test1/test.c b/migration-agent/test_examples/link_errors/test1/test.c new file mode 100644 index 0000000000000000000000000000000000000000..5e16703d2fa13b2544c8c8b6a13ffb97a9da2a06 --- /dev/null +++ b/migration-agent/test_examples/link_errors/test1/test.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + return 0; +} \ No newline at end of file diff --git a/migration-agent/test_examples/llvm_related_errors/test1/makefile b/migration-agent/test_examples/llvm_related_errors/test1/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dce36e93d859f09f7e3331f5c3fc32864980b320 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test1/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags, Wnonnull告警差异 +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test1/test.cpp b/migration-agent/test_examples/llvm_related_errors/test1/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b2eae410f4f5ba446cdb0987852d3f8c2540045 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test1/test.cpp @@ -0,0 +1,12 @@ +template +class C +{ +public: + void mf1() const {} + void mf2() const {} + +private: + T t; +}; +template void C::mf1() const; +template class C; \ No newline at end of file diff --git a/migration-agent/test_examples/llvm_related_errors/test2/makefile b/migration-agent/test_examples/llvm_related_errors/test2/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test2/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test2/test.cpp b/migration-agent/test_examples/llvm_related_errors/test2/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47f7d7c7bc462858459a943d7f74532d3dc96213 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test2/test.cpp @@ -0,0 +1,18 @@ +#include + +class A { +public: + virtual ~A() {std::cout << "executed ~A()\n";} +}; + +class B : public A { +public: + virtual ~B() {std::cout << "executed ~B()\n";} +}; + +int main() { + std::cout << "starting\n"; + B b; + b.~A(); //子类直接调用父类析构函数 + std::cout << "done\n"; +} diff --git a/migration-agent/test_examples/llvm_related_errors/test3/makefile b/migration-agent/test_examples/llvm_related_errors/test3/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test3/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test3/test.cpp b/migration-agent/test_examples/llvm_related_errors/test3/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25a0bd71951df6a086fd2418b837bbc4f5058927 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test3/test.cpp @@ -0,0 +1,7 @@ +struct A +{ + template A(T) = delete; +}; +template<> A::A(int) {} // error +//template<> A::A(int) {} // no error +//A a(0); diff --git a/migration-agent/test_examples/llvm_related_errors/test4/makefile b/migration-agent/test_examples/llvm_related_errors/test4/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dce36e93d859f09f7e3331f5c3fc32864980b320 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test4/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags, Wnonnull告警差异 +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test4/test.cpp b/migration-agent/test_examples/llvm_related_errors/test4/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6499b195ae4609a9542612c21a0a63200023aac9 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test4/test.cpp @@ -0,0 +1,13 @@ +#ifndef __PRAGMA_REDEFINE_EXTNAME +#error +#endif +namespace somewhere { + extern "C" int whiz(void); + int whiz(int); +} +#pragma redefine_extname whiz bang +int (*s)() = somewhere::whiz; +namespace elsewhere { + extern "C" int whiz(void); +} +int (*t)() = elsewhere::whiz; diff --git a/migration-agent/test_examples/llvm_related_errors/test5/makefile b/migration-agent/test_examples/llvm_related_errors/test5/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dce36e93d859f09f7e3331f5c3fc32864980b320 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test5/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags, Wnonnull告警差异 +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test5/test.cpp b/migration-agent/test_examples/llvm_related_errors/test5/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..807072ed30fb59f580d55514b0b3433a5a9b7b92 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test5/test.cpp @@ -0,0 +1,29 @@ +#include +#include +int test, failed; +int main (void); +void +eh1 (void *p, int x) +{ + printf("eh1\n"); + void *q = __builtin_alloca (x); + __builtin_eh_return (0, p); +} +void fail (void) +{ + printf ("failed\n"); + abort (); +} +void continuation (void) +{ + printf ("continuation\n"); + test++; + main(); +} +int main (void) +{ + printf("main\n"); + if(test==0) eh1 (continuation, 100); + printf("exit\n"); + exit (0); +} diff --git a/migration-agent/test_examples/llvm_related_errors/test6/makefile b/migration-agent/test_examples/llvm_related_errors/test6/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dce36e93d859f09f7e3331f5c3fc32864980b320 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test6/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags, Wnonnull告警差异 +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test6/test.cpp b/migration-agent/test_examples/llvm_related_errors/test6/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c41d6f5cebd3c99a3c95e9614421de05afc52da --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test6/test.cpp @@ -0,0 +1,20 @@ +#include +#include + +struct NonPod { + NonPod() {} + ~NonPod() {} +}; + +void sum(int count, ...) { + va_list args; + va_start(args, count); + for (int i = 0; i < count; ++i) { + NonPod obj = va_arg(args, NonPod); + } + va_end(args); +} + +int main() { + sum(2, 1, 2); +} diff --git a/migration-agent/test_examples/llvm_related_errors/test7/makefile b/migration-agent/test_examples/llvm_related_errors/test7/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dce36e93d859f09f7e3331f5c3fc32864980b320 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test7/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags, Wnonnull告警差异 +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test7/test.cpp b/migration-agent/test_examples/llvm_related_errors/test7/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67e4d7ab73dc9f43a12d53035b8175951ffb860f --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test7/test.cpp @@ -0,0 +1,6 @@ +int test(const char* a) { + if (a > 0) { + return 0; + } + return 1; +} diff --git a/migration-agent/test_examples/llvm_related_errors/test8/makefile b/migration-agent/test_examples/llvm_related_errors/test8/makefile new file mode 100644 index 0000000000000000000000000000000000000000..224c7edcc5aca34d10e812795c9b88112e0464a0 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test8/makefile @@ -0,0 +1,24 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test8/test.cpp b/migration-agent/test_examples/llvm_related_errors/test8/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71309dacc35f8304bb5f443b2b3f76275da12c8c --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test8/test.cpp @@ -0,0 +1,14 @@ +class A { +public: + template void As(); + static A *FromWebContents(); + A *FromWebContents2(); +}; +template class B : A { + void FromWebContents() { + auto guest = A::FromWebContents(); + guest ? guest->As() : nullptr; + auto guest2 = A::FromWebContents2(); + guest2 ? guest2->As() : nullptr; + } +} diff --git a/migration-agent/test_examples/llvm_related_errors/test9/makefile b/migration-agent/test_examples/llvm_related_errors/test9/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dce36e93d859f09f7e3331f5c3fc32864980b320 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test9/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags, Wnonnull告警差异 +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/llvm_related_errors/test9/test.cpp b/migration-agent/test_examples/llvm_related_errors/test9/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65a7dfd6085f20e16f49b42eb96e060aa83a59c4 --- /dev/null +++ b/migration-agent/test_examples/llvm_related_errors/test9/test.cpp @@ -0,0 +1,4 @@ +void test(char *MemoryOrderIn, int strlen1) { + char *MemoryOrder; + memcpy(MemoryOrder,MemoryOrderIn,strlen1); +} diff --git a/migration-agent/test_examples/run_test_cases.py b/migration-agent/test_examples/run_test_cases.py new file mode 100644 index 0000000000000000000000000000000000000000..3dacf3a8a216483950717d794df1c0eba8ec58b5 --- /dev/null +++ b/migration-agent/test_examples/run_test_cases.py @@ -0,0 +1,132 @@ +import os +import sys +import shutil +import tempfile +import subprocess +from pathlib import Path +from src.global_config import * +import colorama + + +# ANSI escape codes for colors +GREEN = "\033[92m" +RED = "\033[91m" +RESET = "\033[0m" # Reset color +colorama.init() + + +def copy_to_tempdir(src): + """Copy the source directory to a temporary directory and return its path.""" + dest = tempfile.mkdtemp() + shutil.copytree(src, dest, dirs_exist_ok=True) + return dest + + +# def run_build_script(script_path): +# """Source the build script and capture its environment variables.""" +# command = f"source {script_path}" + +# os.system(command) + + +def init(): + """Initialize the environment and print build status.""" + print("Building BiSheng AI... \t\t\t", end="", flush=True) + # run_build_script("setup_compiler_driver.sh") + print("Done") + + print(f"CC={os.environ.get('CC')}") + print(f"CXX={os.environ.get('CXX')}") + + os.environ["AUTO_ACCEPT"] = "1" + os.environ["LLM_SILENT"] = "1" + # os.environ["LLM_RETRY_TIMES"] = "1" + os.environ["LLM_DEVELOPMENT"] = "0" + + +def run_make_command(test_case, command): + """Run the make command in the given directory and return the result.""" + # 让输出直接打到终端 + result = subprocess.run( + command, + shell=True, + cwd=test_case, + # stdout=None, # subprocess.PIPE, + # stderr=None, # subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + # print(result.returncode) # 只打印退出码 + return result + +def run_one_test_case(test_case, work_dir): + """Compile and check the result of a single test case.""" + print(f"Compile {test_case.relative_to(work_dir)} ...\t\t\t\t", end="", flush=True) + + # Clean and make + run_make_command(test_case, "make clean") + result = run_make_command(test_case, "make") + + if result.returncode == 0: + print(f" [{GREEN}PASS{RESET}]") + else: + print(f" [{RED}FAILED{RESET}]") + + return result.returncode + + +def collect_test_folders(work_dir): + """Collect all subfolders (test cases) within the given directory.""" + folder_path = Path(work_dir) + test_folders = [ + subfolder for subfolder in folder_path.iterdir() if subfolder.is_dir() + ] + return test_folders + + +def print_test_summary(num_test_cases, num_pass, num_failed): + """Print the summary of the test results.""" + pass_rate = (num_pass / num_test_cases) * 100 if num_test_cases > 0 else 0 + print( + f"Tested {num_test_cases} test cases, passed {num_pass}, failed {num_failed}, pass rate: {pass_rate:.2f}%" + ) + + +def run_test(test_sample_path): + """Run all tests in the provided sample path.""" + work_dir = copy_to_tempdir(test_sample_path) + print(f"Running tests using {get_model_id()} as the LLM.") + + test_folders = collect_test_folders(work_dir) + + num_test_cases = 0 + num_pass = 0 + num_failed = 0 + + for category in test_folders: + test_category_folders = collect_test_folders(category) + for folder in test_category_folders: + ret = run_one_test_case(folder, work_dir) + num_test_cases += 1 + if ret == 0: + num_pass += 1 + else: + num_failed += 1 + + print_test_summary(num_test_cases, num_pass, num_failed) + + # Clean up the temporary working directory + try: + shutil.rmtree(work_dir) + except Exception as e: + print(f"Failed to clean up temp directory: {e}") + + +if __name__ == "__main__": + test_sample_path = "test_examples" + if len(sys.argv) > 1: + test_sample_path = sys.argv[1] + + init() + run_test(test_sample_path) diff --git a/migration-agent/test_examples/source_code_errors/test1/makefile b/migration-agent/test_examples/source_code_errors/test1/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test1/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test1/test.cpp b/migration-agent/test_examples/source_code_errors/test1/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff4fa32abf27fa46813cc8f71479753ca1a097de --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test1/test.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "test.h" + +opc_status SyncDBOpc::GetRightStatus(std::string str_status) +{ + opc_status status; + switch (stoi(str_status)) + { + case 0: + status = OPC_STATUS_OK; + break; + case 1: + status = OPC_STATUS_WARNING; + break; + case 2: + status = OPC_STATUS_ERROR; + break; + default: + status = OPC_STATUS_UNKNOWN; + break; + } +} diff --git a/migration-agent/test_examples/source_code_errors/test1/test.h b/migration-agent/test_examples/source_code_errors/test1/test.h new file mode 100644 index 0000000000000000000000000000000000000000..fe29f78a6c746d41446902723f3f80868739d4b3 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test1/test.h @@ -0,0 +1,8 @@ +#ifndef TEST_H +#define TEST_H + +class SyncDBOpc{ +public: +opc_status SyncDBOpc::GetRightStatus(std::string str_status); +} +#endif diff --git a/migration-agent/test_examples/source_code_errors/test10/makefile b/migration-agent/test_examples/source_code_errors/test10/makefile new file mode 100644 index 0000000000000000000000000000000000000000..ee8aeb0a67103093d197cad85a79edd5ee62e4ae --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test10/makefile @@ -0,0 +1,37 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Output executable name +TARGET = test + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +# all: $(TARGET) +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Rule to create the executable +$(TARGET): $(OBJ) + $(CXX) $(OBJ) -o $(TARGET) + +# Rule to compile .cpp files into .o files +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean up object and executable files +clean: + rm -f $(OBJ) $(TARGET) + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test10/test.cpp b/migration-agent/test_examples/source_code_errors/test10/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93fca75802d1f34f7483b1c94a5d7a7bf14867ec --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test10/test.cpp @@ -0,0 +1,3 @@ +void test() { + return 1; +} diff --git a/migration-agent/test_examples/source_code_errors/test11/makefile b/migration-agent/test_examples/source_code_errors/test11/makefile new file mode 100644 index 0000000000000000000000000000000000000000..b31d4dd0f3e9fbef69fee4b34a10bbc99aceb0c0 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test11/makefile @@ -0,0 +1,37 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Output executable name +TARGET = test + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +# all: $(TARGET) +all: + $(CC) $(CFLAGS) -c $(SRC) -o $(OBJ) + +# # Rule to create the executable +# $(TARGET): $(OBJ) +# $(CXX) $(OBJ) -o $(TARGET) + +# # Rule to compile .cpp files into .o files +# %.o: %.cpp +# $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean up object and executable files +clean: + rm -f $(OBJ) $(TARGET) + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test11/test.cpp b/migration-agent/test_examples/source_code_errors/test11/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fa2430125b674fffacc9ca1a52c86d6a01d3dc1 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test11/test.cpp @@ -0,0 +1,18 @@ +#include +#include +template +class Base { +public: + void foo() { + std::cout << "Base::foo()\n"; + } +}; + +template +class Derived : public Base { + +public: + void bar() { + foo(); + } +}; diff --git a/migration-agent/test_examples/source_code_errors/test12/makefile b/migration-agent/test_examples/source_code_errors/test12/makefile new file mode 100644 index 0000000000000000000000000000000000000000..ee8aeb0a67103093d197cad85a79edd5ee62e4ae --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test12/makefile @@ -0,0 +1,37 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Output executable name +TARGET = test + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +# all: $(TARGET) +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Rule to create the executable +$(TARGET): $(OBJ) + $(CXX) $(OBJ) -o $(TARGET) + +# Rule to compile .cpp files into .o files +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean up object and executable files +clean: + rm -f $(OBJ) $(TARGET) + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test12/test.cpp b/migration-agent/test_examples/source_code_errors/test12/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edae46c6a818cc1dfc32b6e19e712a8d72c23652 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test12/test.cpp @@ -0,0 +1,11 @@ +// Order of invocation is undefined in this context according to the C++ standard. +// It's possible to leak a Foo or a Bar depending on the order of evaluation if one +// of the new statements throws an exception before their auto_ptrs can "own" it +accept_two_ptrs(std::auto_ptr(new Foo), std::auto_ptr(new Bar)); + +void MyClass::InvokeCallback(CallbackType cb) +{ + Foo* resource = new Foo; + cb(resource); // If cb throws an exception, resource leaks + delete resource; +} diff --git a/migration-agent/test_examples/source_code_errors/test13/makefile b/migration-agent/test_examples/source_code_errors/test13/makefile new file mode 100644 index 0000000000000000000000000000000000000000..ecbaffc455a9cf917ee67fb05eb25c229791abc5 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test13/makefile @@ -0,0 +1,35 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Output executable name +TARGET = test + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: $(TARGET) + +# Rule to create the executable +$(TARGET): $(OBJ) + $(CXX) $(OBJ) -o $(TARGET) + +# Rule to compile .cpp files into .o files +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean up object and executable files +clean: + rm -f $(OBJ) $(TARGET) + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test13/test.cpp b/migration-agent/test_examples/source_code_errors/test13/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9d3bfdfe631f74b5f968b222ed6eaa1c854b726 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test13/test.cpp @@ -0,0 +1,3 @@ +while( !cin.eof() ) { + getline(cin, input); +} diff --git a/migration-agent/test_examples/source_code_errors/test14/main.cpp b/migration-agent/test_examples/source_code_errors/test14/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d662f1267fda410005c721c95f1e89a553f5d70 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test14/main.cpp @@ -0,0 +1,6 @@ +#include "wrapper.h" +int main() { + Wrapper x(10); + x.print(); + return 0; +} diff --git a/migration-agent/test_examples/source_code_errors/test14/makefile b/migration-agent/test_examples/source_code_errors/test14/makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad75933271d9d2832782e62d2f54ed0a2c8ed265 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test14/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = wrapper.cpp main.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) $(SRC) + +# Clean up object and executable files +clean: + rm -f $(OBJ) a.out *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test14/wrapper.cpp b/migration-agent/test_examples/source_code_errors/test14/wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb6418c53b0589d739b9cb1c862a46af7f51d156 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test14/wrapper.cpp @@ -0,0 +1,5 @@ +#include "wrapper.h" +#include +template void Wrapper::print() { + std::cout << x << std::endl; +} diff --git a/migration-agent/test_examples/source_code_errors/test14/wrapper.h b/migration-agent/test_examples/source_code_errors/test14/wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..a239e59d3c829f513a04923bc3b06d521e0739dc --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test14/wrapper.h @@ -0,0 +1,12 @@ +#ifndef WRAPPER_H +#define WRAPPER_H +template class Wrapper { + public: + Wrapper() = default; + Wrapper(const T &t) : x(t) {} + void print(); + private: + T x; +}; +template class Wrapper; +#endif diff --git a/migration-agent/test_examples/source_code_errors/test15/makefile b/migration-agent/test_examples/source_code_errors/test15/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test15/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test15/test.cpp b/migration-agent/test_examples/source_code_errors/test15/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2623c358f5af487f0112a8a4b9bb8dc47a5c4763 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test15/test.cpp @@ -0,0 +1,15 @@ +#include +#include +struct S { + static constexpr int Dim = 3; +}; +void func(const S &s) { + std::array a; + std::cout << s.Dim << std::endl; + std::cout << a.size() << std::endl; +} +int main() { + S s; + func(s); + return 0; +} diff --git a/migration-agent/test_examples/source_code_errors/test16/func.cpp b/migration-agent/test_examples/source_code_errors/test16/func.cpp new file mode 100644 index 0000000000000000000000000000000000000000..678fd29b443ddc3e268215f78dd4d9fe82673562 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test16/func.cpp @@ -0,0 +1,6 @@ +#include "pi.h" +#include +void func() { + double d = pi::value; + std::cout << "func: " << d << std::endl; +} diff --git a/migration-agent/test_examples/source_code_errors/test16/main.cpp b/migration-agent/test_examples/source_code_errors/test16/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25adb482e6b53ed21219d9e34a07eb8378416eb3 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test16/main.cpp @@ -0,0 +1,10 @@ +#include +#include "pi.h" +void func(); +int main() { + double d = pi::value; + std::cout << "main: " << d << std::endl; + func(); + return 0; +} + diff --git a/migration-agent/test_examples/source_code_errors/test16/makefile b/migration-agent/test_examples/source_code_errors/test16/makefile new file mode 100644 index 0000000000000000000000000000000000000000..1000d8691070a4a07f296836e0484f8ca6edeb6d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test16/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++14 + +# Source files +SRC = func.cpp main.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) $(SRC) + +# Clean up object and executable files +clean: + rm -f $(OBJ) a.out *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test16/pi.cpp b/migration-agent/test_examples/source_code_errors/test16/pi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb687d5995ce8ddcf34e0a459bac0e200448d63f --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test16/pi.cpp @@ -0,0 +1,5 @@ +#include "pi.h" +template +T pi::value = 3.14159265358979323846264338327950288419716939937510; +template +T pi::value; \ No newline at end of file diff --git a/migration-agent/test_examples/source_code_errors/test16/pi.h b/migration-agent/test_examples/source_code_errors/test16/pi.h new file mode 100644 index 0000000000000000000000000000000000000000..b076027beb40f95931c9c0056493d208c4c794f8 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test16/pi.h @@ -0,0 +1,8 @@ +#ifndef PI_H +#define PI_H +namespace pi { +template +constexpr T value() { return T(3.14159265358979323846264338327950288419716939937510); +} +} +#endif \ No newline at end of file diff --git a/migration-agent/test_examples/source_code_errors/test17/makefile b/migration-agent/test_examples/source_code_errors/test17/makefile new file mode 100644 index 0000000000000000000000000000000000000000..054e9650af4451f733a754e6785a1e1b3d1a5745 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test17/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CC),) + CC = clang +endif + + +# Compiler flags +CCFLAGS = -Wall + +# Source files +SRC = test.c + +# Object files +OBJ = $(SRC:.c=.o) + +# Default rule +all: + $(CC) $(CCFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test17/test.c b/migration-agent/test_examples/source_code_errors/test17/test.c new file mode 100644 index 0000000000000000000000000000000000000000..67ca0e04e66833076a6fb4e9bf81d689f65a2ef5 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test17/test.c @@ -0,0 +1,5 @@ +int foo (double a, double b) +{ + double square (double z){ return z * z; } + return square (a) + square (b); +} diff --git a/migration-agent/test_examples/source_code_errors/test18/makefile b/migration-agent/test_examples/source_code_errors/test18/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test18/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test18/test.cpp b/migration-agent/test_examples/source_code_errors/test18/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e2db58c314277fa13975213bb6a70e21d6af109 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test18/test.cpp @@ -0,0 +1,19 @@ +#include + class CommonName { + int x; +}; + namespace ns::CommonName { +class C { +public: + void print() { + std::cout << "Hello, world" << std::endl; + } +}; +} // namespace ns::CommonName + using namespace ns; + int main() { + // ns::CommonName::C c; + CommonName::C c; + c.print(); + return 0; +} diff --git a/migration-agent/test_examples/source_code_errors/test19/makefile b/migration-agent/test_examples/source_code_errors/test19/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test19/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test19/test.cpp b/migration-agent/test_examples/source_code_errors/test19/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1704b331122d514ffe1e6015a575c7afcef88985 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test19/test.cpp @@ -0,0 +1,17 @@ +template +void f (T* p) +{ + p->~auto(); +} + +int d; +struct A { ~A() { ++d; } }; + +int main() +{ + f(new int(42)); + f(new A); + if (d != 1) + throw; + return 0; +} diff --git a/migration-agent/test_examples/source_code_errors/test2/makefile b/migration-agent/test_examples/source_code_errors/test2/makefile new file mode 100644 index 0000000000000000000000000000000000000000..ecbaffc455a9cf917ee67fb05eb25c229791abc5 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test2/makefile @@ -0,0 +1,35 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Output executable name +TARGET = test + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: $(TARGET) + +# Rule to create the executable +$(TARGET): $(OBJ) + $(CXX) $(OBJ) -o $(TARGET) + +# Rule to compile .cpp files into .o files +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean up object and executable files +clean: + rm -f $(OBJ) $(TARGET) + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test2/test.cpp b/migration-agent/test_examples/source_code_errors/test2/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a46798cba321b82d2c319be807ad5d66b3df539 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test2/test.cpp @@ -0,0 +1,12 @@ +#include + +struct E __final {}; + +void foo(){ + printf("Hello world\n"); +} + +int main() +{ + return 0; +} diff --git a/migration-agent/test_examples/source_code_errors/test20/makefile b/migration-agent/test_examples/source_code_errors/test20/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test20/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test20/test.cpp b/migration-agent/test_examples/source_code_errors/test20/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca3e2e58e01197add12b18414089fd1a8cd66174 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test20/test.cpp @@ -0,0 +1,3 @@ +void test(int n){ + char num[n]={0}; +} diff --git a/migration-agent/test_examples/source_code_errors/test21/makefile b/migration-agent/test_examples/source_code_errors/test21/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test21/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test21/test.cpp b/migration-agent/test_examples/source_code_errors/test21/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8bd5ae7d65dbfdfa20ad7cd16191bc6de827501 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test21/test.cpp @@ -0,0 +1,4 @@ +void func() { +  double y = 2.0; +  int z {y}; +} diff --git a/migration-agent/test_examples/source_code_errors/test23/makefile b/migration-agent/test_examples/source_code_errors/test23/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test23/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test23/test.cpp b/migration-agent/test_examples/source_code_errors/test23/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..080d324aed6207ce9da19c300de4bdc78db0f640 --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test23/test.cpp @@ -0,0 +1,2 @@ +template static void func() {} +template static void func(); diff --git a/migration-agent/test_examples/source_code_errors/test24/makefile b/migration-agent/test_examples/source_code_errors/test24/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b09ca26eb439616ff895efeca272b3eadcaac7d --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test24/makefile @@ -0,0 +1,25 @@ +# Compiler + +ifeq ($(CXX),) + CXX = clang++ +endif + + +# Compiler flags +CXXFLAGS = -Wall -std=c++11 + +# Source files +SRC = test.cpp + +# Object files +OBJ = $(SRC:.cpp=.o) + +# Default rule +all: + $(CXX) $(CXXFLAGS) -c $(SRC) -o $(OBJ) + +# Clean up object and executable files +clean: + rm -f $(OBJ) *.log + +.PHONY: all clean diff --git a/migration-agent/test_examples/source_code_errors/test24/test.cpp b/migration-agent/test_examples/source_code_errors/test24/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7883167e28d0354196db97403bcf48efe97344f --- /dev/null +++ b/migration-agent/test_examples/source_code_errors/test24/test.cpp @@ -0,0 +1,11 @@ +#include +#include +template