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/
|
||||
|
@@ -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