Skip to content

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

python
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_price

AI 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

python
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

python
if discounted_price >= 100:
    discounted_price -= 10

When 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_amount could be negative
  • order_amount could be None
  • Missing amount upper limit check

Fixed Solution

python
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:

python
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

  1. AI excels at finding edge cases: Humans easily overlook edge conditions, AI can systematically check
  2. Precision issues often neglected: Financial calculations must use Decimal
  3. 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

python
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:

  1. Query user: 1 time
  2. Query order list: 1 time
  3. 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

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

python
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

MetricBefore OptimizationAfter (JOIN)After (eager loading)
Query count10211
Response time5s200ms180ms
Memory usageHighMediumMedium

Key Takeaways

  1. AI excels at identifying N+1 issues: Such performance bottlenecks are easily overlooked in code review
  2. Database query optimization: Use JOIN or eager loading to reduce query count
  3. 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

python
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:

python
# 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:

  1. Password stored in plaintext
  2. Missing login failure rate limiting
  3. Missing CSRF protection

Fixed Solution

python
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

python
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.data

Key Takeaways

  1. AI effectively identifies security vulnerabilities: Especially injection vulnerabilities
  2. Always use parameterized queries: Never concatenate SQL statements
  3. Passwords must be encrypted: Use bcrypt or Argon2
  4. 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

python
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...
        pass

AI 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:

  1. Indefinitely growing cache: self.cache[url].append(data) keeps appending data to list, never cleans up
  2. Missing cache expiration mechanism: Old data never expires
  3. Missing cache size limit: No upper bound control

Fixed Solution

python
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 expiration

Verification Results

Memory statistics after 7 days:

MetricBefore FixAfter Fix
Initial memory100MB100MB
Memory after 7 days3GB+180MB
Cache entriesIndefinite growthMax 500
Service stabilityNeeds restartStable operation

Key Takeaways

  1. AI excels at finding resource leaks: Memory, file handles, database connections, etc.
  2. Cache must have lifecycle: Set upper limit and expiration time
  3. Add monitoring: Real-time monitoring of memory and resource usage
  4. 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

python
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:

python
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

python
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.value

Solution 2: Use atomic operations

python
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.value

Concurrency Testing

python
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

  1. AI can identify concurrency issues: Race conditions, deadlocks, etc.
  2. Multi-threading must consider synchronization: Shared resources need protection
  3. Use correct synchronization primitives: Lock, RLock, Semaphore, etc.
  4. Concurrency testing is essential: Use stress testing to verify correctness

Best Practices Summary

1. AI Code Review Applicable Scenarios

ScenarioAI AdvantageHuman Advantage
Edge case checkingSystematic, comprehensiveBusiness understanding
Performance issue identificationPattern recognitionSystem experience
Security vulnerability detectionRich rule baseOffensive/defensive thinking
Code standard checkingStrong consistencyFlexible adjustment
Architecture issuesPartial identificationGlobal 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 introduced

4. Tool Selection Guide

Review TypeRecommended ToolReason
Security vulnerabilitiesClaudeRich rule base, deep understanding
Performance issuesDeepSeekStrong code understanding
Code standardsChatGPTRich examples, clear explanations
Comprehensive reviewMultiple tools combinedComplement 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:

  1. AI as first line of defense: Quickly identify technical issues
  2. Manual as final gatekeeper: Ensure business logic is correct
  3. Continuous learning improvement: Accumulate review experience
  4. 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)

MIT Licensed