AI Code Review Real Cases
Real-world examples of using AI to discover bugs, optimize performance, and improve code quality
Overview
This article demonstrates AI applications in code review through real-world cases. All cases are derived from actual development practices, showing how to use AI tools to discover potential bugs, identify performance bottlenecks, detect security vulnerabilities, and improve overall code quality.
Case 1: AI Discovers Hidden Logic Bugs
Background
The development team missed an edge case bug during code review, causing occasional errors in production. During post-mortem review using AI, this deeply hidden bug was discovered.
Original Code
def calculate_discount(user, order_amount):
"""Calculate user discount price"""
if user.is_premium:
discount_rate = 0.2
elif user.is_regular:
discount_rate = 0.1
else:
discount_rate = 0.0
# Apply discount
discounted_price = order_amount * (1 - discount_rate)
# Volume discount
if discounted_price >= 100:
discounted_price -= 10
return discounted_priceAI Review Process
Prompt:
Please review the following Python code, focusing on:
1. Edge case handling
2. Possible logic errors
3. Potential numerical issues
[Code above]AI Output: Found 3 issues:
Issue 1: Floating-point precision problem
discounted_price = order_amount * (1 - discount_rate)When order_amount is 99.99 and discount_rate is 0.1:
- Expected result:
99.99 * 0.9 = 89.991 - Actual result: May fail inequality check due to floating-point precision
Issue 2: Edge case bug
if discounted_price >= 100:
discounted_price -= 10When discounted_price is exactly 100, it becomes 90 after subtracting 10, potentially causing user experience issues (why doesn't 99.99 get discount, but 100 becomes 90?)
Issue 3: Missing input validation
order_amountcould be negativeorder_amountcould be None- Missing amount upper limit check
Fixed Solution
from decimal import Decimal
def calculate_discount(user, order_amount):
"""Calculate user discount price"""
# Input validation
if order_amount is None or order_amount < 0:
raise ValueError("Order amount must be non-negative")
if order_amount > 1000000: # Set reasonable limit
raise ValueError("Order amount exceeds limit")
# Determine discount rate
if user.is_premium:
discount_rate = Decimal('0.2')
elif user.is_regular:
discount_rate = Decimal('0.1')
else:
discount_rate = Decimal('0.0')
# Apply discount (use Decimal to avoid precision issues)
discounted_price = Decimal(str(order_amount)) * (1 - discount_rate)
# Volume discount (clear boundary)
if discounted_price >= Decimal('100'):
discounted_price -= Decimal('10')
# Round to cents
return float(discounted_price.quantize(Decimal('0.01')))Verification Results
Write unit tests to verify the fix:
import pytest
from decimal import Decimal
def test_boundary_condition():
"""Test boundary conditions"""
# 99.99 doesn't qualify for volume discount
result = calculate_discount(premium_user, 99.99)
assert result == 79.99 # 99.99 * 0.8
# 100 qualifies for volume discount
result = calculate_discount(premium_user, 100)
assert result == 70.0 # 100 * 0.8 - 10
def test_decimal_precision():
"""Test floating-point precision"""
result = calculate_discount(regular_user, 99.99)
# Should not have precision errors
assert abs(result - 89.99) < 0.01
def test_negative_input():
"""Test negative input"""
with pytest.raises(ValueError):
calculate_discount(user, -100)Key Takeaways
- AI excels at finding edge cases: Humans easily overlook edge conditions, AI can systematically check
- Precision issues often neglected: Financial calculations must use Decimal
- Complete test coverage: Write tests immediately after fixing
Case 2: AI Identifies N+1 Query Performance Issue
Background
An API endpoint response time gradually increased from 200ms to 5 seconds. The development team used AI to review the code and discovered a severe N+1 query problem.
Original Code
from flask import Flask, jsonify
from models import db, User, Order, Product
app = Flask(__name__)
@app.route('/api/users/<int:user_id>/orders')
def get_user_orders(user_id):
"""Get all orders for a user with product information"""
user = User.query.get(user_id)
if not user:
return jsonify({'error': 'User not found'}), 404
orders = Order.query.filter_by(user_id=user_id).all()
result = []
for order in orders:
# Query product for each order
product = Product.query.get(order.product_id)
result.append({
'order_id': order.id,
'product_name': product.name,
'quantity': order.quantity,
'total_price': order.quantity * product.price
})
return jsonify({'orders': result})AI Review Process
Prompt:
This API endpoint is slow (5 seconds). Please analyze the code to find performance bottlenecks.
Database tables:
- users: User table
- orders: Order table (user_id foreign key)
- products: Product table
Please provide optimization suggestions.AI Output:
Discovered severe N+1 query problem:
Current implementation:
- Query user: 1 time
- Query order list: 1 time
- Query product for each order: N times
Total queries = 1 + 1 + N (If 100 orders, that's 102 queries)
Optimization Solutions
Solution 1: Use JOIN query
@app.route('/api/users/<int:user_id>/orders')
def get_user_orders(user_id):
"""Get all orders for a user with product information (optimized)"""
user = User.query.get(user_id)
if not user:
return jsonify({'error': 'User not found'}), 404
# Use JOIN to query all data at once
orders = db.session.query(Order, Product)\
.join(Product, Order.product_id == Product.id)\
.filter(Order.user_id == user_id)\
.all()
result = []
for order, product in orders:
result.append({
'order_id': order.id,
'product_name': product.name,
'quantity': order.quantity,
'total_price': order.quantity * product.price
})
return jsonify({'orders': result})Solution 2: Use eager loading
from sqlalchemy.orm import joinedload
@app.route('/api/users/<int:user_id>/orders')
def get_user_orders(user_id):
"""Optimize with eager loading"""
orders = Order.query\
.options(joinedload(Order.product))\
.filter_by(user_id=user_id)\
.all()
result = []
for order in orders:
result.append({
'order_id': order.id,
'product_name': order.product.name,
'quantity': order.quantity,
'total_price': order.quantity * order.product.price
})
return jsonify({'orders': result})Performance Comparison
| Metric | Before Optimization | After (JOIN) | After (eager loading) |
|---|---|---|---|
| Query count | 102 | 1 | 1 |
| Response time | 5s | 200ms | 180ms |
| Memory usage | High | Medium | Medium |
Key Takeaways
- AI excels at identifying N+1 issues: Such performance bottlenecks are easily overlooked in code review
- Database query optimization: Use JOIN or eager loading to reduce query count
- Performance monitoring: Add database query logging, monitor slow queries
Case 3: AI Detects Security Vulnerability (SQL Injection)
Background
During security audit, AI tools discovered a hidden SQL injection vulnerability in the code. Attackers could bypass authentication through carefully crafted input.
Original Code
from flask import Flask, request
import sqlite3
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
# Dangerous: Direct SQL string concatenation
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(query)
user = cursor.fetchone()
if user:
return "Login successful"
else:
return "Invalid credentials"AI Review Process
Prompt:
Please review the security of this login function, focusing on:
1. SQL injection risk
2. Password storage method
3. Session management
[Code above]AI Output:
Discovered critical SQL injection vulnerability:
Attack example:
# Attacker input
username = "admin'--"
password = "anything"
# Actual SQL executed
SELECT * FROM users WHERE username='admin'--' AND password='anything'
# -- is SQL comment, password check is commented out
# Equivalent to:
SELECT * FROM users WHERE username='admin'Other security issues:
- Password stored in plaintext
- Missing login failure rate limiting
- Missing CSRF protection
Fixed Solution
from flask import Flask, request, session
import sqlite3
import bcrypt
from functools import wraps
app = Flask(__name__)
app.secret_key = 'your-secret-key'
def rate_limit(f):
"""Login rate limiting decorator"""
@wraps(f)
def decorated_function(*args, **kwargs):
# Implement IP-level rate limiting
# Code omitted...
return f(*args, **kwargs)
return decorated_function
@app.route('/login', methods=['POST'])
@rate_limit
def login():
username = request.form['username']
password = request.form['password'].encode('utf-8')
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
# Safe: Use parameterized query
cursor.execute("SELECT id, password_hash FROM users WHERE username=?", (username,))
user = cursor.fetchone()
if user and bcrypt.checkpw(password, user[1]):
# Create session
session['user_id'] = user[0]
session.permanent = True
return "Login successful"
else:
return "Invalid credentials", 401
@app.route('/register', methods=['POST'])
def register():
username = request.form['username']
password = request.form['password'].encode('utf-8')
# Encrypt password with bcrypt
password_hash = bcrypt.hashpw(password, bcrypt.gensalt())
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
# Safe: Use parameterized query
cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)",
(username, password_hash))
conn.commit()
return "Registration successful"Security Testing
import pytest
def test_sql_injection_attempt():
"""Test SQL injection attack"""
response = client.post('/login', data={
'username': "admin'--",
'password': 'anything'
})
assert response.status_code == 401
assert b'Invalid credentials' in response.data
def test_normal_login():
"""Test normal login"""
# Register first
client.post('/register', data={
'username': 'testuser',
'password': 'testpass123'
})
# Then login
response = client.post('/login', data={
'username': 'testuser',
'password': 'testpass123'
})
assert response.status_code == 200
assert b'Login successful' in response.dataKey Takeaways
- AI effectively identifies security vulnerabilities: Especially injection vulnerabilities
- Always use parameterized queries: Never concatenate SQL statements
- Passwords must be encrypted: Use bcrypt or Argon2
- Add multiple layers of protection: Rate limiting, CSRF protection, security headers
Case 4: AI Discovers Memory Leak Issue
Background
A long-running background service's memory usage continued to grow from initial 100MB to several GB, eventually causing OOM. Using AI to review the code discovered the memory leak source.
Original Code
import requests
from collections import defaultdict
class DataCache:
def __init__(self):
self.cache = defaultdict(list)
def fetch_and_cache(self, url):
"""Fetch data and cache"""
response = requests.get(url)
data = response.json()
# Problem: Cache grows indefinitely
self.cache[url].append(data)
return data
# Global cache instance
cache = DataCache()
def process_urls(urls):
"""Process URL list"""
for url in urls:
data = cache.fetch_and_cache(url)
# Process data...
passAI Review Process
Prompt:
This background service's memory keeps growing. Please analyze the code to find the cause of memory leak.
Service operation:
- Long-running (no restart)
- Processes about 1000 URLs per hour
- After one week, memory grows from 100MB to 3GB
Please provide diagnosis and fix suggestions.AI Output:
Discovered memory leak issue:
- Indefinitely growing cache:
self.cache[url].append(data)keeps appending data to list, never cleans up - Missing cache expiration mechanism: Old data never expires
- Missing cache size limit: No upper bound control
Fixed Solution
import requests
from collections import defaultdict
from datetime import datetime, timedelta
import weakref
class DataCache:
def __init__(self, max_size=1000, ttl_seconds=3600):
self.cache = {}
self.access_times = {}
self.max_size = max_size
self.ttl_seconds = ttl_seconds
def _cleanup_expired(self):
"""Clean up expired data"""
current_time = datetime.now()
expired_keys = [
key for key, access_time in self.access_times.items()
if current_time - access_time > timedelta(seconds=self.ttl_seconds)
]
for key in expired_keys:
del self.cache[key]
del self.access_times[key]
def _evict_lru(self):
"""LRU eviction policy"""
if len(self.cache) >= self.max_size:
# Find least recently used key
lru_key = min(self.access_times.items(), key=lambda x: x[1])[0]
del self.cache[lru_key]
del self.access_times[lru_key]
def fetch_and_cache(self, url):
"""Fetch data and cache (optimized)"""
# Check cache
if url in self.cache:
self.access_times[url] = datetime.now()
return self.cache[url]
# Clean up expired and LRU eviction
self._cleanup_expired()
self._evict_lru()
# Fetch new data
response = requests.get(url)
data = response.json()
# Cache data
self.cache[url] = data
self.access_times[url] = datetime.now()
return data
def get_cache_stats(self):
"""Get cache statistics"""
return {
'cache_size': len(self.cache),
'max_size': self.max_size,
'ttl_seconds': self.ttl_seconds
}
# Use weak reference or singleton pattern
cache = DataCache(max_size=500, ttl_seconds=1800) # Max 500 items, 30 min expirationVerification Results
Memory statistics after 7 days:
| Metric | Before Fix | After Fix |
|---|---|---|
| Initial memory | 100MB | 100MB |
| Memory after 7 days | 3GB+ | 180MB |
| Cache entries | Indefinite growth | Max 500 |
| Service stability | Needs restart | Stable operation |
Key Takeaways
- AI excels at finding resource leaks: Memory, file handles, database connections, etc.
- Cache must have lifecycle: Set upper limit and expiration time
- Add monitoring: Real-time monitoring of memory and resource usage
- Regular cleanup: Implement automatic cleanup mechanism
Case 5: AI Discovers Concurrency Safety Issue
Background
A counter in multi-threaded environment had race condition, causing inaccurate counts. AI review discovered this concurrency safety problem.
Original Code
import threading
class Counter:
def __init__(self):
self.value = 0
def increment(self):
"""Increase count"""
current = self.value
# Simulate some processing
import time
time.sleep(0.001)
self.value = current + 1
def get_value(self):
return self.value
# Global counter
counter = Counter()
def worker():
"""Worker thread"""
for _ in range(1000):
counter.increment()
# Create 100 threads
threads = []
for _ in range(100):
t = threading.Thread(target=worker)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"Expected: 100000, Actual: {counter.get_value()}")
# Output: Expected: 100000, Actual: 98234 (different each time)AI Review Process
Prompt:
This multi-threaded counter has data inconsistency issues. Expected value is 100000, but actual result varies each time.
Please analyze:
1. Where is the concurrency safety issue?
2. How to fix?
3. What are the considerations?
[Code above]AI Output:
Discovered Race Condition:
Problem analysis:
current = self.value # Thread A reads value=0
# Thread B also reads value=0
time.sleep(0.001) # Thread A sleeps
# Thread B also sleeps
self.value = current + 1 # Thread A writes value=1
# Thread B also writes value=1 (should be 2)Two threads read the same value simultaneously, causing lost updates.
Fixed Solution
Solution 1: Use Lock
import threading
class Counter:
def __init__(self):
self.value = 0
self.lock = threading.Lock()
def increment(self):
"""Increase count (thread-safe)"""
with self.lock:
current = self.value
import time
time.sleep(0.001)
self.value = current + 1
def get_value(self):
with self.lock:
return self.valueSolution 2: Use atomic operations
import threading
class Counter:
def __init__(self):
self.value = 0
self.lock = threading.Lock()
def increment(self):
"""Increase count (atomic operation)"""
with self.lock:
self.value += 1
def get_value(self):
with self.lock:
return self.valueConcurrency Testing
import threading
def test_counter_thread_safety():
"""Test counter thread safety"""
counter = Counter()
def worker():
for _ in range(1000):
counter.increment()
threads = []
for _ in range(100):
t = threading.Thread(target=worker)
threads.append(t)
t.start()
for t in threads:
t.join()
assert counter.get_value() == 100000
print("✅ Thread safety test passed")
test_counter_thread_safety()Key Takeaways
- AI can identify concurrency issues: Race conditions, deadlocks, etc.
- Multi-threading must consider synchronization: Shared resources need protection
- Use correct synchronization primitives: Lock, RLock, Semaphore, etc.
- Concurrency testing is essential: Use stress testing to verify correctness
Best Practices Summary
1. AI Code Review Applicable Scenarios
| Scenario | AI Advantage | Human Advantage |
|---|---|---|
| Edge case checking | Systematic, comprehensive | Business understanding |
| Performance issue identification | Pattern recognition | System experience |
| Security vulnerability detection | Rich rule base | Offensive/defensive thinking |
| Code standard checking | Strong consistency | Flexible adjustment |
| Architecture issues | Partial identification | Global perspective |
2. Prompt Design Principles
- Specify review focus: Security, performance, logic, etc.
- Provide context: Project background, tech stack, constraints
- Specify review dimensions: Functionality, performance, security, maintainability
- Request specific suggestions: Not just point out problems, also provide solutions
3. Review Process Recommendations
1. AI quick scan → Find obvious issues
2. Manual deep review → Business logic and architecture
3. Write test cases → Verify issues actually exist
4. Fix and test → Ensure fix is effective
5. Regression review → Confirm no new issues introduced4. Tool Selection Guide
| Review Type | Recommended Tool | Reason |
|---|---|---|
| Security vulnerabilities | Claude | Rich rule base, deep understanding |
| Performance issues | DeepSeek | Strong code understanding |
| Code standards | ChatGPT | Rich examples, clear explanations |
| Comprehensive review | Multiple tools combined | Complement each other |
5. Common Pitfalls
- ❌ Over-reliance on AI: Neglect manual review
- ❌ Ignore business logic: Only focus on technical issues
- ❌ Lack verification: Fix without testing
- ❌ Ignore context: Don't understand project background
Conclusion
AI code review is an effective tool for improving code quality, but cannot completely replace manual review. Best practices are:
- AI as first line of defense: Quickly identify technical issues
- Manual as final gatekeeper: Ensure business logic is correct
- Continuous learning improvement: Accumulate review experience
- Build review checklist: Systematic review process
Remember: The goal of AI review is not to replace humans, but to let humans focus on truly important issues.
References:
- AI Code Review Tools Evaluation (DigitalOcean, 2025)
- Sentry AI Code Review Practice (Sentry Blog, 2025)
- Augment Code Review Benchmark (Augment Code, 2025)