feat(clang): add claude suggestion
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
# 基於 Google 風格但較寬鬆,適合舊代碼
|
||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
ColumnLimit: 100
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
IndentCaseLabels: true
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
Standard: Cpp03 # 針對舊代碼
|
26
.clang-tidy
26
.clang-tidy
@@ -0,0 +1,26 @@
|
|||||||
|
# 階段一:只檢查最關鍵的錯誤,適合舊代碼
|
||||||
|
Checks: '-*,
|
||||||
|
clang-analyzer-core.NullDereference,
|
||||||
|
clang-analyzer-core.DivideZero,
|
||||||
|
clang-analyzer-core.UndefinedBinaryOperatorResult,
|
||||||
|
bugprone-argument-comment,
|
||||||
|
bugprone-bool-pointer-implicit-conversion,
|
||||||
|
bugprone-dangling-handle,
|
||||||
|
bugprone-use-after-move,
|
||||||
|
readability-braces-around-statements,
|
||||||
|
readability-container-size-empty'
|
||||||
|
|
||||||
|
# 不將警告視為錯誤(階段一)
|
||||||
|
WarningsAsErrors: ''
|
||||||
|
|
||||||
|
# 包含所有標頭檔
|
||||||
|
HeaderFilterRegex: '.*'
|
||||||
|
|
||||||
|
# 分析設定
|
||||||
|
AnalyzeTemporaryDtors: false
|
||||||
|
FormatStyle: none
|
||||||
|
|
||||||
|
# 檢查參數
|
||||||
|
CheckOptions:
|
||||||
|
- key: readability-braces-around-statements.ShortStatementLines
|
||||||
|
value: '2'
|
@@ -0,0 +1,39 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(CppLinterTemplate)
|
||||||
|
|
||||||
|
# 設定 C++ 標準(針對舊代碼)
|
||||||
|
set(CMAKE_CXX_STANDARD 98)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# 編譯選項
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||||
|
|
||||||
|
# 尋找 clang-tidy
|
||||||
|
find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
|
||||||
|
if(CLANG_TIDY_EXE)
|
||||||
|
message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
|
||||||
|
option(ENABLE_CLANG_TIDY "Enable clang-tidy checks" OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# 原始碼
|
||||||
|
add_executable(main
|
||||||
|
src/main.cpp
|
||||||
|
src/utils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(main PRIVATE src)
|
||||||
|
|
||||||
|
# 如果啟用 clang-tidy
|
||||||
|
if(CLANG_TIDY_EXE AND ENABLE_CLANG_TIDY)
|
||||||
|
set_target_properties(main PROPERTIES
|
||||||
|
CXX_CLANG_TIDY "${CLANG_TIDY_EXE};--config-file=${CMAKE_SOURCE_DIR}/.clang-tidy"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# 測試執行檔
|
||||||
|
add_executable(tests
|
||||||
|
tests/test_main.cpp
|
||||||
|
src/utils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(tests PRIVATE src)
|
75
README.md
75
README.md
@@ -1,4 +1,77 @@
|
|||||||
# cpp-linter-template
|
# C++ Linter Template
|
||||||
|
|
||||||
|
這是一個展示如何在 C++ 專案中整合 linter 工具的模板專案。
|
||||||
|
|
||||||
|
## 目的
|
||||||
|
- 展示 clang-tidy 在舊 C++ 代碼中的應用
|
||||||
|
- 提供漸進式導入 linter 的範例
|
||||||
|
- Azure DevOps CI/CD 整合範例
|
||||||
|
|
||||||
|
## 快速開始
|
||||||
|
|
||||||
|
### 1. 本地開發環境設定
|
||||||
|
```bash
|
||||||
|
# 安裝相依套件 (Ubuntu/Debian)
|
||||||
|
sudo apt install clang-tidy clang-format cmake build-essential
|
||||||
|
|
||||||
|
# 安裝相依套件 (macOS)
|
||||||
|
brew install llvm cmake
|
||||||
|
|
||||||
|
# 克隆專案
|
||||||
|
git clone <your-repo-url>
|
||||||
|
cd cpp-linter-template
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 執行 Linter
|
||||||
|
```bash
|
||||||
|
# 使用提供的腳本
|
||||||
|
./scripts/run-linter.sh
|
||||||
|
|
||||||
|
# 或手動執行
|
||||||
|
clang-tidy src/*.cpp src/*.h tests/*.cpp --config-file=.clang-tidy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 建構專案
|
||||||
|
```bash
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
./main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Linter 配置說明
|
||||||
|
### 當前採用階段一設定:
|
||||||
|
- 只檢查最關鍵的錯誤
|
||||||
|
- 不會因 linter 警告而中斷 CI
|
||||||
|
- 適合舊代碼逐步改進
|
||||||
|
|
||||||
|
### 後續階段計劃
|
||||||
|
- 階段二:增加記憶體和資源管理檢查
|
||||||
|
- 階段三:加入可讀性和現代化建議
|
||||||
|
- 階段四:強制執行,警告視為錯誤
|
||||||
|
|
||||||
|
## 在 Azure DevOps 中使用
|
||||||
|
1. 將此專案推送到 Azure DevOps
|
||||||
|
2. 設定 Pipeline 使用 azure-pipelines.yml
|
||||||
|
3. 建立 Pull Request 時會自動執行 linter
|
||||||
|
|
||||||
|
## 自定義配置
|
||||||
|
編輯 .clang-tidy 檔案來調整檢查規則:
|
||||||
|
```yaml
|
||||||
|
# 增加更多檢查
|
||||||
|
Checks: '-*,clang-analyzer-*,bugprone-*,readability-*'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 檔案說明
|
||||||
|
`.clang-tidy:` Linter 配置檔
|
||||||
|
`.clang-format`: 程式碼格式化配置
|
||||||
|
`azure-pipelines.yml`: Azure DevOps CI/CD 配置
|
||||||
|
`scripts/run-linter.sh`: 本地執行 linter 腳本
|
||||||
|
|
||||||
|
## 注意事項
|
||||||
|
- 此模板使用 C++98 標準,適合舊代碼
|
||||||
|
- Linter 設定較為寬鬆,適合逐步導入
|
||||||
|
- 可以根據團隊需求調整檢查規則
|
||||||
|
|
||||||
## 專案結構
|
## 專案結構
|
||||||
cpp-linter-template/
|
cpp-linter-template/
|
||||||
|
@@ -0,0 +1,106 @@
|
|||||||
|
# Azure DevOps Pipeline for C++ Linter Template
|
||||||
|
trigger:
|
||||||
|
branches:
|
||||||
|
include:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
|
||||||
|
pr:
|
||||||
|
branches:
|
||||||
|
include:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
|
||||||
|
variables:
|
||||||
|
buildConfiguration: 'Debug'
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- stage: LintAndBuild
|
||||||
|
displayName: 'Lint and Build'
|
||||||
|
jobs:
|
||||||
|
- job: StaticAnalysis
|
||||||
|
displayName: 'Static Analysis with clang-tidy'
|
||||||
|
steps:
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Install Dependencies'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y clang-tidy clang-format cmake build-essential
|
||||||
|
clang-tidy --version
|
||||||
|
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Check Code Format'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
echo "Checking code format..."
|
||||||
|
find src tests -name "*.cpp" -o -name "*.h" | xargs clang-format --dry-run --Werror
|
||||||
|
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Run clang-tidy on all files'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
echo "Running clang-tidy..."
|
||||||
|
find src tests -name "*.cpp" -o -name "*.h" | xargs clang-tidy --config-file=.clang-tidy
|
||||||
|
|
||||||
|
# 階段一:只顯示警告,不中斷 CI
|
||||||
|
echo "Linter completed. Review warnings above."
|
||||||
|
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Build Project'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=${{ variables.buildConfiguration }}
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Run Tests'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
cd build
|
||||||
|
./tests
|
||||||
|
./main
|
||||||
|
|
||||||
|
- job: PRAnalysis
|
||||||
|
displayName: 'PR Changed Files Analysis'
|
||||||
|
condition: eq(variables['Build.Reason'], 'PullRequest')
|
||||||
|
steps:
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Install Dependencies'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y clang-tidy
|
||||||
|
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: 'Analyze Changed Files Only'
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: |
|
||||||
|
echo "Analyzing only changed files in PR..."
|
||||||
|
|
||||||
|
# 取得變更的檔案
|
||||||
|
git fetch origin $(System.PullRequest.TargetBranch)
|
||||||
|
CHANGED_FILES=$(git diff origin/$(System.PullRequest.TargetBranch)...HEAD --name-only | grep -E '\.(cpp|cxx|cc|c\+\+|h|hpp|hxx)$' || true)
|
||||||
|
|
||||||
|
if [ -z "$CHANGED_FILES" ]; then
|
||||||
|
echo "No C++ files changed in this PR"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Changed C++ files:"
|
||||||
|
echo "$CHANGED_FILES"
|
||||||
|
|
||||||
|
echo "Running clang-tidy on changed files..."
|
||||||
|
echo "$CHANGED_FILES" | xargs clang-tidy --config-file=.clang-tidy -- -std=c++98
|
29
scripts/run-linter.sh
Normal file → Executable file
29
scripts/run-linter.sh
Normal file → Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 本地執行 linter 的腳本
|
||||||
|
|
||||||
|
echo "Running clang-tidy on C++ files..."
|
||||||
|
|
||||||
|
# 檢查 clang-tidy 是否存在
|
||||||
|
if ! command -v clang-tidy &> /dev/null; then
|
||||||
|
echo "clang-tidy not found. Please install it first."
|
||||||
|
echo "Ubuntu/Debian: sudo apt install clang-tidy"
|
||||||
|
echo "macOS: brew install llvm"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 尋找所有 C++ 檔案
|
||||||
|
CPP_FILES=$(find src tests -name "*.cpp" -o -name "*.h" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$CPP_FILES" ]; then
|
||||||
|
echo "No C++ files found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Found files:"
|
||||||
|
echo "$CPP_FILES"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# 執行 clang-tidy
|
||||||
|
echo "$CPP_FILES" | xargs clang-tidy --config-file=.clang-tidy
|
||||||
|
|
||||||
|
echo "Linter check completed."
|
33
src/main.cpp
33
src/main.cpp
@@ -0,0 +1,33 @@
|
|||||||
|
// 這個檔案故意包含一些會被 linter 檢查的情況
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "C++ Linter Template Demo" << std::endl;
|
||||||
|
|
||||||
|
// 測試案例 1: 正常的代碼
|
||||||
|
std::vector<int> numbers;
|
||||||
|
numbers.push_back(1);
|
||||||
|
numbers.push_back(2);
|
||||||
|
numbers.push_back(3);
|
||||||
|
|
||||||
|
// 測試案例 2: 可能被 linter 警告的代碼
|
||||||
|
int* ptr = new int(42);
|
||||||
|
if (ptr) {
|
||||||
|
std::cout << "Value: " << *ptr << std::endl;
|
||||||
|
delete ptr;
|
||||||
|
ptr = NULL; // 好習慣,避免 dangling pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 測試案例 3: 容器大小檢查
|
||||||
|
if (!numbers.empty()) { // 比 numbers.size() > 0 好
|
||||||
|
std::cout << "Numbers count: " << numbers.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 測試案例 4: 呼叫工具函數
|
||||||
|
int result = calculateSum(numbers);
|
||||||
|
std::cout << "Sum: " << result << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
int calculateSum(const std::vector<int>& vec) {
|
||||||
|
int sum = 0;
|
||||||
|
// 使用舊式的 iterator(模擬舊代碼)
|
||||||
|
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
|
||||||
|
sum += *it;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPositive(int number) {
|
||||||
|
return number > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void safeCopy(char* dest, const char* src, int maxLen) {
|
||||||
|
if (dest && src && maxLen > 0) {
|
||||||
|
strncpy(dest, src, maxLen - 1);
|
||||||
|
dest[maxLen - 1] = '\0'; // 確保字串結尾
|
||||||
|
}
|
||||||
|
}
|
15
src/utils.h
15
src/utils.h
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// 計算向量元素總和
|
||||||
|
int calculateSum(const std::vector<int>& vec);
|
||||||
|
|
||||||
|
// 檢查數字是否為正數
|
||||||
|
bool isPositive(int number);
|
||||||
|
|
||||||
|
// 安全的字串複製(展示舊式 C++ 代碼)
|
||||||
|
void safeCopy(char* dest, const char* src, int maxLen);
|
||||||
|
|
||||||
|
#endif // UTILS_H
|
Reference in New Issue
Block a user