feat(iwyu): add scripts for Include What You Use analysis and results review

This commit is contained in:
whaffman 2025-09-24 09:57:48 +02:00
parent 169bcf96c4
commit b7dc3dd38d
5 changed files with 276 additions and 0 deletions

View File

@ -7,6 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
# Build essentials # Build essentials
build-essential \ build-essential \
# Standard clang tools (this will install the default version)
clang \ clang \
clang-format \ clang-format \
clang-tidy \ clang-tidy \

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ build-*
.cache .cache
webserv.log webserv.log
compile_commands.json compile_commands.json
iwyu_results/

17
.iwyu.imp Normal file
View File

@ -0,0 +1,17 @@
[
# Standard C++ library mappings
{ include: ["<bits/std_abs.h>", "private", "<cstdlib>", "public"] },
{ include: ["<bits/stdint-intn.h>", "private", "<cstdint>", "public"] },
{ include: ["<bits/stdint-uintn.h>", "private", "<cstdint>", "public"] },
# System headers
{ include: ["<sys/socket.h>", "public", "<sys/socket.h>", "public"] },
{ include: ["<netinet/in.h>", "public", "<netinet/in.h>", "public"] },
{ include: ["<arpa/inet.h>", "public", "<arpa/inet.h>", "public"] },
# Project mappings - adjust these to your actual header structure
{ include: ["\"webserv/server/Server.hpp\"", "public", "\"webserv/server/Server.hpp\"", "public"] },
{ include: ["\"webserv/log/Log.hpp\"", "public", "\"webserv/log/Log.hpp\"", "public"] },
{ include: ["\"webserv/socket/Socket.hpp\"", "public", "\"webserv/socket/Socket.hpp\"", "public"] },
{ include: ["\"webserv/client/Client.hpp\"", "public", "\"webserv/client/Client.hpp\"", "public"] }
]

179
check_iwyu.sh Executable file
View File

@ -0,0 +1,179 @@
#!/bin/bash
# Don't exit on first error - we want to continue checking all files
# set -e
# Detect project root - try container path first, then current directory
if [ -d "/workspace" ]; then
PROJECT_ROOT="/workspace"
else
PROJECT_ROOT="$(pwd)"
fi
# Find the build directory - check multiple possible locations
BUILD_DIR=""
echo -e "${BLUE}🔍 Looking for build directory with compile_commands.json...${NC}"
for build_candidate in "$PROJECT_ROOT/build-container" "$PROJECT_ROOT/build-local" "$PROJECT_ROOT/build"; do
echo -e " Checking: $build_candidate"
if [ -d "$build_candidate" ] && [ -f "$build_candidate/compile_commands.json" ]; then
BUILD_DIR="$build_candidate"
echo -e "${GREEN} ✅ Found!${NC}"
break
else
echo -e "${YELLOW} ❌ Not found or no compile_commands.json${NC}"
fi
done
IWYU_MAPPING="$PROJECT_ROOT/.iwyu.imp"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🔍 Running Include What You Use Analysis...${NC}"
echo -e "${BLUE}📁 Project root: $PROJECT_ROOT${NC}"
# Check if IWYU is available (try both common names)
IWYU_CMD=""
if command -v include-what-you-use >/dev/null 2>&1; then
IWYU_CMD="include-what-you-use"
echo -e "${GREEN}✅ Found IWYU as: include-what-you-use${NC}"
elif command -v iwyu >/dev/null 2>&1; then
IWYU_CMD="iwyu"
echo -e "${GREEN}✅ Found IWYU as: iwyu${NC}"
else
echo -e "${RED}❌ IWYU not found. Please install it first.${NC}"
echo -e "${YELLOW}💡 Try: sudo apt install iwyu or yay -S include-what-you-use${NC}"
exit 1
fi
echo -e "${BLUE}🛠️ Using IWYU command: $IWYU_CMD${NC}"
# Check if we found a build directory
if [ -z "$BUILD_DIR" ]; then
echo -e "${YELLOW}⚠️ No build directory with compile_commands.json found.${NC}"
echo -e "${YELLOW}📂 Checked: build-container/, build-local/, build/${NC}"
echo -e "${YELLOW}🔨 Running cmake to create build directory...${NC}"
cd "$PROJECT_ROOT"
# Try to create build directory (prefer build-container in container, build-local otherwise)
if [ -d "/workspace" ]; then
BUILD_DIR="$PROJECT_ROOT/build-container"
else
BUILD_DIR="$PROJECT_ROOT/build-local"
fi
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
else
echo -e "${GREEN}✅ Found build directory: $BUILD_DIR${NC}"
fi
# Final check that compile_commands.json exists
if [ ! -f "$BUILD_DIR/compile_commands.json" ]; then
echo -e "${RED}❌ Failed to create compile_commands.json in $BUILD_DIR${NC}"
cd "$PROJECT_ROOT"
cmake -B "$BUILD_DIR" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug
# Check again after cmake
if [ ! -f "$BUILD_DIR/compile_commands.json" ]; then
echo -e "${RED}❌ Still no compile_commands.json after cmake. Exiting.${NC}"
exit 1
fi
fi
# Create results directory
RESULTS_DIR="$PROJECT_ROOT/iwyu_results"
mkdir -p "$RESULTS_DIR"
# Function to run IWYU on a single file
run_iwyu_on_file() {
local file="$1"
local relative_path="${file#$PROJECT_ROOT/}"
local output_file="$RESULTS_DIR/$(basename "$file" .cpp).iwyu"
echo -e "${BLUE}Analyzing: ${relative_path}${NC}"
# Run IWYU with compile commands
if "$IWYU_CMD" \
-I"$PROJECT_ROOT" \
-std=c++20 \
-Xiwyu --verbose=3 \
-Xiwyu --quoted_includes_first \
-Xiwyu --cxx17ns \
"$file" \
2>&1 | tee "$output_file"; then
# Check if IWYU found issues
if grep -q "should add these lines:" "$output_file" || grep -q "should remove these lines:" "$output_file"; then
echo -e "${YELLOW}⚠️ Issues found in $relative_path${NC}"
return 2 # Issues found (not a script failure)
else
echo -e "${GREEN}$relative_path looks good${NC}"
return 0 # All good
fi
else
local iwyu_exit_code=$?
echo -e "${RED}❌ IWYU failed for $relative_path (exit code: $iwyu_exit_code)${NC}"
return 1 # IWYU execution failed
return 1
fi
}
# Find all C++ source files
echo -e "\n${BLUE}Finding C++ source files...${NC}"
cpp_files=()
while IFS= read -r -d '' file; do
cpp_files+=("$file")
done < <(find "$PROJECT_ROOT/webserv" -name "*.cpp" -print0 2>/dev/null)
if [ ${#cpp_files[@]} -eq 0 ]; then
echo -e "${RED}❌ No .cpp files found in webserv directory${NC}"
exit 1
fi
echo -e "${BLUE}Found ${#cpp_files[@]} C++ source files${NC}\n"
# Run IWYU on all files
issues_found=0
total_files=${#cpp_files[@]}
current_file=0
for file in "${cpp_files[@]}"; do
((current_file++))
echo -e "${BLUE}[$current_file/$total_files]${NC}"
run_iwyu_on_file "$file"
exit_code=$?
if [ $exit_code -eq 2 ]; then
# Issues found (normal)
((issues_found++))
elif [ $exit_code -eq 1 ]; then
# IWYU execution failed (error)
echo -e "${RED}⚠️ IWYU execution error for $(basename "$file")${NC}"
((issues_found++))
fi
# exit_code 0 means no issues found
echo ""
done
# Summary
echo -e "${BLUE}📊 IWYU Analysis Summary${NC}"
echo -e "Total files analyzed: $total_files"
echo -e "Files with issues: $issues_found"
echo -e "Results saved in: $RESULTS_DIR"
if [ $issues_found -eq 0 ]; then
echo -e "${GREEN}🎉 All files have proper includes!${NC}"
exit 0
else
echo -e "${YELLOW}⚠️ $issues_found files need attention${NC}"
echo -e "${BLUE}💡 Run './fix_iwyu.sh' to review suggested fixes${NC}"
exit 0 # Don't fail the script for include suggestions
fi

78
fix_iwyu.sh Executable file
View File

@ -0,0 +1,78 @@
#!/bin/bash
set -e
PROJECT_ROOT="/workspace"
RESULTS_DIR="$PROJECT_ROOT/iwyu_results"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🔧 Reviewing IWYU fixes...${NC}"
if [ ! -d "$RESULTS_DIR" ]; then
echo -e "${RED}❌ No IWYU results found. Run './check_iwyu.sh' first.${NC}"
exit 1
fi
# Check if there are any result files
result_files=("$RESULTS_DIR"/*.iwyu)
if [ ! -f "${result_files[0]}" ]; then
echo -e "${YELLOW}⚠️ No IWYU result files found.${NC}"
exit 1
fi
echo -e "${BLUE}💡 IWYU Analysis Results - Manual Review Required${NC}"
echo -e "${YELLOW}Note: Automatic fixing requires careful review before applying changes.${NC}\n"
files_with_issues=0
for result_file in "$RESULTS_DIR"/*.iwyu; do
if [ -f "$result_file" ]; then
filename=$(basename "$result_file" .iwyu)
# Check if this file has suggestions
if grep -q "should add these lines:\|should remove these lines:" "$result_file"; then
((files_with_issues++))
echo -e "${BLUE}=== $filename.cpp ===${NC}"
# Show additions
if grep -q "should add these lines:" "$result_file"; then
echo -e "${GREEN}📥 Suggested additions:${NC}"
sed -n '/should add these lines:/,/^$/p' "$result_file" | grep -v "should add these lines:" | head -20
echo ""
fi
# Show removals
if grep -q "should remove these lines:" "$result_file"; then
echo -e "${RED}📤 Suggested removals:${NC}"
sed -n '/should remove these lines:/,/^$/p' "$result_file" | grep -v "should remove these lines:" | head -20
echo ""
fi
# Show full analysis (first 30 lines for context)
echo -e "${BLUE}📋 Full analysis:${NC}"
head -30 "$result_file"
echo -e "${YELLOW}... (see $result_file for complete output)${NC}"
echo -e "${BLUE}${'='*60}${NC}\n"
fi
fi
done
if [ $files_with_issues -eq 0 ]; then
echo -e "${GREEN}🎉 No issues found in any analyzed files!${NC}"
else
echo -e "${YELLOW}📊 Summary: $files_with_issues files have suggested changes${NC}"
echo -e "${BLUE}💡 Tips for applying fixes:${NC}"
echo -e " • Review each suggestion carefully"
echo -e " • Test compilation after each change"
echo -e " • Some suggestions might be false positives"
echo -e " • Consider project-specific header policies"
echo ""
echo -e "${BLUE}🗂️ Detailed results available in: $RESULTS_DIR${NC}"
fi