feat(iwyu): enhance IWYU mappings and add automatic fix scripts
This commit is contained in:
parent
b7dc3dd38d
commit
20b49e4e45
89
.iwyu.imp
89
.iwyu.imp
@ -1,17 +1,92 @@
|
||||
[
|
||||
# Standard C++ library mappings
|
||||
# ============================================================================
|
||||
# WEBSERV PROJECT IWYU MAPPINGS
|
||||
# Based on preferences: Forward declarations in headers, central common header,
|
||||
# umbrella headers for modules, strict standard library includes, stdexcept
|
||||
# ============================================================================
|
||||
|
||||
# Standard C++ library private implementation 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"] },
|
||||
{ include: ["<bits/types/time_t.h>", "private", "<ctime>", "public"] },
|
||||
{ include: ["<bits/chrono.h>", "private", "<chrono>", "public"] },
|
||||
{ include: ["<bits/exception.h>", "private", "<exception>", "public"] },
|
||||
{ include: ["<bits/std_function.h>", "private", "<functional>", "public"] },
|
||||
{ include: ["<bits/stringfwd.h>", "private", "<string>", "public"] },
|
||||
|
||||
# System headers
|
||||
# Standard library strict mappings (preference 5C - very strict)
|
||||
{ include: ["<iostream>", "public", "<iostream>", "public"] },
|
||||
{ symbol: ["std::cout", "private", "<iostream>", "public"] },
|
||||
{ symbol: ["std::cerr", "private", "<iostream>", "public"] },
|
||||
{ symbol: ["std::cin", "private", "<iostream>", "public"] },
|
||||
{ symbol: ["std::endl", "private", "<iostream>", "public"] },
|
||||
{ symbol: ["std::vector", "private", "<vector>", "public"] },
|
||||
{ symbol: ["std::string", "private", "<string>", "public"] },
|
||||
{ symbol: ["std::map", "private", "<map>", "public"] },
|
||||
{ symbol: ["std::unordered_map", "private", "<unordered_map>", "public"] },
|
||||
{ symbol: ["std::unique_ptr", "private", "<memory>", "public"] },
|
||||
{ symbol: ["std::shared_ptr", "private", "<memory>", "public"] },
|
||||
{ symbol: ["std::make_unique", "private", "<memory>", "public"] },
|
||||
{ symbol: ["std::make_shared", "private", "<memory>", "public"] },
|
||||
|
||||
# System headers for socket programming
|
||||
{ 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"] },
|
||||
{ include: ["<sys/epoll.h>", "public", "<sys/epoll.h>", "public"] },
|
||||
{ include: ["<fcntl.h>", "public", "<fcntl.h>", "public"] },
|
||||
{ include: ["<unistd.h>", "public", "<unistd.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"] }
|
||||
# Error handling (preference 6A - stdexcept)
|
||||
{ symbol: ["std::runtime_error", "private", "<stdexcept>", "public"] },
|
||||
{ symbol: ["std::logic_error", "private", "<stdexcept>", "public"] },
|
||||
{ symbol: ["std::invalid_argument", "private", "<stdexcept>", "public"] },
|
||||
{ symbol: ["std::out_of_range", "private", "<stdexcept>", "public"] },
|
||||
|
||||
# ============================================================================
|
||||
# PROJECT HEADER MAPPINGS - Standardized on <> angle brackets
|
||||
# ============================================================================
|
||||
|
||||
# Convert quoted includes to angle brackets for consistency
|
||||
{ include: ["\"webserv/log/Log.hpp\"", "public", "<webserv/log/Log.hpp>", "public"] },
|
||||
{ include: ["\"webserv/log/Channel.hpp\"", "public", "<webserv/log/Channel.hpp>", "public"] },
|
||||
{ include: ["\"webserv/log/StdoutChannel.hpp\"", "public", "<webserv/log/StdoutChannel.hpp>", "public"] },
|
||||
{ include: ["\"webserv/log/FileChannel.hpp\"", "public", "<webserv/log/FileChannel.hpp>", "public"] },
|
||||
|
||||
{ include: ["\"webserv/http/HttpRequest.hpp\"", "public", "<webserv/http/HttpRequest.hpp>", "public"] },
|
||||
{ include: ["\"webserv/http/HttpResponse.hpp\"", "public", "<webserv/http/HttpResponse.hpp>", "public"] },
|
||||
{ include: ["\"webserv/http/HttpHeaders.hpp\"", "public", "<webserv/http/HttpHeaders.hpp>", "public"] },
|
||||
{ include: ["\"webserv/http/HttpConstants.hpp\"", "public", "<webserv/http/HttpConstants.hpp>", "public"] },
|
||||
|
||||
{ include: ["\"webserv/config/ConfigManager.hpp\"", "public", "<webserv/config/ConfigManager.hpp>", "public"] },
|
||||
{ include: ["\"webserv/config/ServerConfig.hpp\"", "public", "<webserv/config/ServerConfig.hpp>", "public"] },
|
||||
{ include: ["\"webserv/config/LocationConfig.hpp\"", "public", "<webserv/config/LocationConfig.hpp>", "public"] },
|
||||
{ include: ["\"webserv/config/utils.hpp\"", "public", "<webserv/config/utils.hpp>", "public"] },
|
||||
|
||||
{ include: ["\"webserv/server/Server.hpp\"", "public", "<webserv/server/Server.hpp>", "public"] },
|
||||
{ include: ["\"webserv/client/Client.hpp\"", "public", "<webserv/client/Client.hpp>", "public"] },
|
||||
{ include: ["\"webserv/socket/Socket.hpp\"", "public", "<webserv/socket/Socket.hpp>", "public"] },
|
||||
{ include: ["\"webserv/router/Router.hpp\"", "public", "<webserv/router/Router.hpp>", "public"] },
|
||||
|
||||
{ include: ["\"webserv/handler/CgiHandler.hpp\"", "public", "<webserv/handler/CgiHandler.hpp>", "public"] },
|
||||
{ include: ["\"webserv/handler/FileHandler.hpp\"", "public", "<webserv/handler/FileHandler.hpp>", "public"] },
|
||||
{ include: ["\"webserv/handler/ErrorHandler.hpp\"", "public", "<webserv/handler/ErrorHandler.hpp>", "public"] },
|
||||
|
||||
# ============================================================================
|
||||
# FORWARD DECLARATION PREFERENCES
|
||||
# ============================================================================
|
||||
|
||||
# Suggest forward declarations instead of full includes in headers where possible
|
||||
{ symbol: ["Client", "private", "<webserv/client/Client.hpp>", "public"] },
|
||||
{ symbol: ["Server", "private", "<webserv/server/Server.hpp>", "public"] },
|
||||
{ symbol: ["HttpRequest", "private", "<webserv/http/HttpRequest.hpp>", "public"] },
|
||||
{ symbol: ["HttpResponse", "private", "<webserv/http/HttpResponse.hpp>", "public"] },
|
||||
{ symbol: ["HttpHeaders", "private", "<webserv/http/HttpHeaders.hpp>", "public"] },
|
||||
{ symbol: ["ServerConfig", "private", "<webserv/config/ServerConfig.hpp>", "public"] },
|
||||
{ symbol: ["ConfigManager", "private", "<webserv/config/ConfigManager.hpp>", "public"] },
|
||||
{ symbol: ["LocationConfig", "private", "<webserv/config/LocationConfig.hpp>", "public"] },
|
||||
{ symbol: ["Socket", "private", "<webserv/socket/Socket.hpp>", "public"] },
|
||||
{ symbol: ["Router", "private", "<webserv/router/Router.hpp>", "public"] },
|
||||
{ symbol: ["Channel", "private", "<webserv/log/Channel.hpp>", "public"] }
|
||||
]
|
||||
@ -52,6 +52,14 @@ fi
|
||||
|
||||
echo -e "${BLUE}🛠️ Using IWYU command: $IWYU_CMD${NC}"
|
||||
|
||||
# Check if mapping file exists
|
||||
if [ -f "$IWYU_MAPPING" ]; then
|
||||
echo -e "${GREEN}📋 Using IWYU mapping file: $IWYU_MAPPING${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ No IWYU mapping file found at: $IWYU_MAPPING${NC}"
|
||||
echo -e "${YELLOW}💡 Consider creating one for better IWYU suggestions${NC}"
|
||||
fi
|
||||
|
||||
# Check if we found a build directory
|
||||
if [ -z "$BUILD_DIR" ]; then
|
||||
echo -e "${YELLOW}⚠️ No build directory with compile_commands.json found.${NC}"
|
||||
@ -98,13 +106,14 @@ run_iwyu_on_file() {
|
||||
|
||||
echo -e "${BLUE}Analyzing: ${relative_path}${NC}"
|
||||
|
||||
# Run IWYU with compile commands
|
||||
# Run IWYU with compile commands and mapping file
|
||||
if "$IWYU_CMD" \
|
||||
-I"$PROJECT_ROOT" \
|
||||
-std=c++20 \
|
||||
-Xiwyu --verbose=3 \
|
||||
-Xiwyu --quoted_includes_first \
|
||||
-Xiwyu --cxx17ns \
|
||||
-Xiwyu --mapping_file="$IWYU_MAPPING" \
|
||||
"$file" \
|
||||
2>&1 | tee "$output_file"; then
|
||||
|
||||
|
||||
137
fix_iwyu_auto.sh
Executable file
137
fix_iwyu_auto.sh
Executable file
@ -0,0 +1,137 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Automatic IWYU Fix using iwyu-fix-includes
|
||||
# Uses the official iwyu-fix-includes tool to automatically apply IWYU suggestions
|
||||
|
||||
set -e
|
||||
|
||||
# Find project root (directory containing this script)
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
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}🔧 Automatic IWYU Fix using iwyu-fix-includes${NC}"
|
||||
echo -e "${YELLOW}⚠️ This will automatically apply all IWYU suggestions${NC}"
|
||||
|
||||
# Check if iwyu-fix-includes is available
|
||||
if ! command -v iwyu-fix-includes &> /dev/null; then
|
||||
echo -e "${RED}❌ iwyu-fix-includes not found. Please install it:${NC}"
|
||||
echo -e "${YELLOW} # On Ubuntu/Debian:${NC}"
|
||||
echo -e "${YELLOW} sudo apt install iwyu${NC}"
|
||||
echo -e "${YELLOW} # On Arch Linux:${NC}"
|
||||
echo -e "${YELLOW} sudo pacman -S include-what-you-use${NC}"
|
||||
echo -e "${YELLOW} # Or build from source${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$RESULTS_DIR" ]; then
|
||||
echo -e "${RED}❌ No IWYU results found. Run './check_iwyu.sh' first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure we can build first
|
||||
echo -e "${BLUE}🔍 Testing initial build...${NC}"
|
||||
if ! make -j$(nproc) release >/dev/null 2>&1; then
|
||||
echo -e "${RED}❌ Project doesn't build currently. Fix build issues first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Initial build successful${NC}"
|
||||
|
||||
# Count IWYU result files
|
||||
result_count=$(find "$RESULTS_DIR" -name "*.iwyu" -type f | wc -l)
|
||||
if [ "$result_count" -eq 0 ]; then
|
||||
echo -e "${YELLOW}⚠️ No .iwyu files found in $RESULTS_DIR${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}📁 Found $result_count IWYU result files${NC}"
|
||||
|
||||
# Apply all fixes using iwyu-fix-includes
|
||||
echo -e "${BLUE}🔧 Applying IWYU fixes...${NC}"
|
||||
|
||||
# iwyu-fix-includes options:
|
||||
# --comments: Add comments explaining why headers are included
|
||||
# --update_comments: Update existing IWYU comments
|
||||
# --safe_headers: Only remove headers that are definitely safe to remove
|
||||
iwyu_fix_options=""
|
||||
|
||||
# Ask user for options
|
||||
echo -e "${YELLOW}Choose fix options:${NC}"
|
||||
echo -e " 1) ${GREEN}Safe mode${NC} (conservative, only safe changes)"
|
||||
echo -e " 2) ${BLUE}Standard mode${NC} (recommended)"
|
||||
echo -e " 3) ${YELLOW}Aggressive mode${NC} (with comments, updates existing)"
|
||||
echo -n "Choose (1-3) [default: 2]: "
|
||||
|
||||
if [ -t 0 ]; then # Only read input if running interactively
|
||||
read -r choice
|
||||
else
|
||||
choice="2"
|
||||
fi
|
||||
|
||||
case "${choice:-2}" in
|
||||
1)
|
||||
iwyu_fix_options="--safe_headers"
|
||||
echo -e "${GREEN}Using safe mode${NC}"
|
||||
;;
|
||||
3)
|
||||
iwyu_fix_options="--comments --update_comments"
|
||||
echo -e "${YELLOW}Using aggressive mode with comments${NC}"
|
||||
;;
|
||||
*)
|
||||
iwyu_fix_options=""
|
||||
echo -e "${BLUE}Using standard mode${NC}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Apply the fixes
|
||||
echo -e "${BLUE}🚀 Running iwyu-fix-includes...${NC}"
|
||||
|
||||
# iwyu-fix-includes expects all IWYU output concatenated on stdin
|
||||
temp_output=$(mktemp)
|
||||
cat "$RESULTS_DIR"/*.iwyu > "$temp_output"
|
||||
|
||||
if cat "$temp_output" | iwyu-fix-includes $iwyu_fix_options; then
|
||||
echo -e "${GREEN}✅ IWYU fixes applied successfully!${NC}"
|
||||
|
||||
# Clean up
|
||||
rm -f "$temp_output"
|
||||
|
||||
# Test build after fixes
|
||||
echo -e "${BLUE}🔍 Testing build after fixes...${NC}"
|
||||
if make -j$(nproc) release >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}✅ Build successful after applying fixes!${NC}"
|
||||
|
||||
# Show what changed
|
||||
if command -v git &> /dev/null && git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
echo -e "${BLUE}📋 Files modified:${NC}"
|
||||
git diff --name-only | head -10
|
||||
if [ "$(git diff --name-only | wc -l)" -gt 10 ]; then
|
||||
echo -e "${YELLOW} ... and $(( $(git diff --name-only | wc -l) - 10 )) more files${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}💡 Next steps:${NC}"
|
||||
echo -e " • Review changes: ${BLUE}git diff${NC}"
|
||||
echo -e " • Run tests: ${BLUE}make test${NC} (if available)"
|
||||
echo -e " • Commit: ${BLUE}git add -A && git commit -m 'fix: apply IWYU suggestions'${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}❌ Build failed after applying fixes!${NC}"
|
||||
echo -e "${YELLOW}💡 You may need to manually fix some issues or revert changes${NC}"
|
||||
rm -f "$temp_output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
else
|
||||
echo -e "${RED}❌ iwyu-fix-includes failed!${NC}"
|
||||
echo -e "${YELLOW}💡 Check the error output above for details${NC}"
|
||||
rm -f "$temp_output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}🎉 IWYU fix process completed!${NC}"
|
||||
138
safe_iwyu_fix.sh
Executable file
138
safe_iwyu_fix.sh
Executable file
@ -0,0 +1,138 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Safe automatic IWYU fix with build system validation
|
||||
# This version applies fixes and validates using your actual build system
|
||||
|
||||
# Detect project root
|
||||
if [ -d "/workspace" ]; then
|
||||
PROJECT_ROOT="/workspace"
|
||||
else
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
fi
|
||||
|
||||
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}🔧 Safe IWYU Auto-Fix with Build Validation${NC}"
|
||||
echo -e "${YELLOW}⚠️ This will apply fixes one file at a time and validate with your build system${NC}"
|
||||
|
||||
if [ ! -d "$RESULTS_DIR" ]; then
|
||||
echo -e "${RED}❌ No IWYU results found. Run './check_iwyu.sh' first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure we can build first
|
||||
echo -e "${BLUE}🔍 Testing initial build...${NC}"
|
||||
if ! make -j$(nproc) release >/dev/null 2>&1; then
|
||||
echo -e "${RED}❌ Project doesn't build currently. Fix build issues first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Initial build successful${NC}"
|
||||
|
||||
files_fixed=0
|
||||
files_processed=0
|
||||
|
||||
# Process each .iwyu result file
|
||||
for result_file in "$RESULTS_DIR"/*.iwyu; do
|
||||
[ ! -f "$result_file" ] && continue
|
||||
|
||||
# Get the corresponding source file
|
||||
base_name=$(basename "$result_file" .iwyu)
|
||||
source_file=""
|
||||
|
||||
# Find the actual source file
|
||||
while IFS= read -r -d '' file; do
|
||||
if [[ "$(basename "$file" .cpp)" == "$base_name" ]]; then
|
||||
source_file="$file"
|
||||
break
|
||||
fi
|
||||
done < <(find "$PROJECT_ROOT/webserv" -name "*.cpp" -print0)
|
||||
|
||||
if [ -z "$source_file" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
((files_processed++))
|
||||
relative_path="${source_file#$PROJECT_ROOT/}"
|
||||
|
||||
echo -e "\n${BLUE}[$files_processed] Processing: $relative_path${NC}"
|
||||
|
||||
# Check if there are actual suggestions
|
||||
if ! grep -q "should add these lines:" "$result_file"; then
|
||||
echo -e "${GREEN} ✅ No additions needed${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Create backup
|
||||
backup_file="${source_file}.backup"
|
||||
cp "$source_file" "$backup_file"
|
||||
|
||||
# Extract and apply only the additions (safer than removals)
|
||||
additions_made=false
|
||||
|
||||
# Get the lines to add and store in temp file to avoid subshell issues
|
||||
temp_includes=$(mktemp)
|
||||
awk '/should add these lines:/{flag=1; next} /should remove these lines:|^$/{flag=0} flag && /^#include/{print}' "$result_file" > "$temp_includes"
|
||||
|
||||
# Process each include line
|
||||
while IFS= read -r include_line; do
|
||||
[ -z "$include_line" ] && continue
|
||||
|
||||
# Clean up the line (remove any trailing whitespace/comments after //)
|
||||
clean_include=$(echo "$include_line" | sed 's|//.*$||' | sed 's/[[:space:]]*$//')
|
||||
|
||||
# Check if this exact include is already present (be more strict)
|
||||
if grep -F "$clean_include" "$source_file" >/dev/null; then
|
||||
echo -e "${YELLOW} ~ Already present: $clean_include${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Add the include after the first existing #include
|
||||
if sed -i "1,/^#include/ { /^#include/ a\\
|
||||
$include_line
|
||||
}" "$source_file"; then
|
||||
echo -e "${GREEN} + Added: $include_line${NC}"
|
||||
additions_made=true
|
||||
fi
|
||||
done < "$temp_includes"
|
||||
|
||||
rm -f "$temp_includes"
|
||||
|
||||
if [ "$additions_made" = true ]; then
|
||||
# Test build with changes
|
||||
echo -e "${BLUE} 🔨 Testing build...${NC}"
|
||||
if make -j$(nproc) release >/dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✅ Build successful with changes${NC}"
|
||||
rm "$backup_file"
|
||||
((files_fixed++))
|
||||
else
|
||||
echo -e "${RED} ❌ Build failed, reverting changes${NC}"
|
||||
mv "$backup_file" "$source_file"
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN} ✅ No new includes to add${NC}"
|
||||
rm "$backup_file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n${BLUE}📊 Safe Auto-fix Summary:${NC}"
|
||||
echo -e "Files processed: $files_processed"
|
||||
echo -e "Files successfully modified: $files_fixed"
|
||||
|
||||
if [ $files_fixed -gt 0 ]; then
|
||||
echo -e "${GREEN}🎉 Applied $files_fixed successful fixes!${NC}"
|
||||
echo -e "${BLUE}💡 Next steps:${NC}"
|
||||
echo -e " • Review changes: ${BLUE}git diff${NC}"
|
||||
echo -e " • Run full test: ${BLUE}make clean && make all${NC}"
|
||||
echo -e " • Commit: ${BLUE}git add -A && git commit -m 'fix: add missing includes (IWYU)'${NC}"
|
||||
else
|
||||
echo -e "${GREEN}🎉 No fixes needed - all includes are already optimal!${NC}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Loading…
Reference in New Issue
Block a user