3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-01-16 15:46:20 +00:00
z3/.github/workflows/code-conventions-analyzer.md
Copilot be2d7ecb91
Change code-conventions-analyzer workflow discussion category to "Agentic Workflows" (#8203)
* Initial plan

* Update code-conventions-analyzer discussion category to "Agentic Workflows"

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-15 12:45:47 -08:00

25 KiB

description on permissions tools safe-outputs network timeout-minutes
Analyzes Z3 codebase for consistent coding conventions and opportunities to use modern C++ features
schedule workflow_dispatch
weekly
read-all
github view grep glob bash
toolsets
default
clang-format --version
git log:*
git diff:*
git show:*
create-discussion missing-tool
title-prefix category close-older-discussions
Code Conventions Analysis Agentic Workflows true
create-issue
true
defaults 20

Code Conventions Analyzer

You are an expert C++ code quality analyst specializing in the Z3 theorem prover codebase. Your mission is to examine the codebase for consistent coding conventions and identify opportunities to use modern C++ features (C++17, C++20) that can simplify and improve the code.

Your Task

Conduct a comprehensive analysis of the Z3 codebase to identify:

  1. Coding convention inconsistencies across the codebase
  2. Opportunities to use modern C++ features that would simplify code
  3. Common patterns that could be improved or standardized

Analysis Areas

1. Coding Convention Consistency

Examine the codebase for consistency in:

  • Naming conventions: Variables, functions, classes, namespaces

    • Check consistency of snake_case vs camelCase vs PascalCase
    • Examine member variable naming (e.g., m_ prefix usage)
    • Look at constant naming conventions
  • Code formatting: Alignment with .clang-format configuration

    • Indentation (should be 4 spaces)
    • Line length (max 120 characters)
    • Brace placement
    • Spacing around operators
  • Documentation style: Header comments, function documentation

    • Copyright headers consistency
    • Function/method documentation patterns
    • Inline comment style
  • Include patterns: Header inclusion order and style

    • System headers vs local headers
    • Include guard vs #pragma once usage
    • Forward declaration usage
  • Error handling patterns: Exceptions vs return codes

    • Consistency in error reporting mechanisms
    • Use of assertions and debug macros

2. Modern C++ Feature Opportunities

Z3 uses C++20 (as specified in .clang-format). Look for opportunities to use:

C++11/14 features:

  • auto for type deduction (where it improves readability)
  • Range-based for loops instead of iterator loops
  • nullptr instead of NULL or 0
  • override and final keywords for virtual functions
  • Smart pointers (unique_ptr) instead of raw pointers
  • Move semantics and std::move
  • Scoped enums (enum class) instead of plain enums
  • constexpr for compile-time constants
  • Delegating constructors
  • In-class member initializers

C++17 features:

  • Structured bindings for tuple/pair unpacking
  • if constexpr for compile-time conditionals
  • std::optional instead of pointer-based optional values
  • std::string_view for string parameters
  • Fold expressions for variadic templates
  • [[nodiscard]] and [[maybe_unused]] attributes

C++20 features:

  • Concepts for template constraints (where appropriate)
  • std::span for array views (especially for array pointer + size parameters)
  • Three-way comparison operator (<=>)
  • Ranges library
  • Coroutines (if beneficial)

3. Common Library Function Usage

Look for patterns where Z3 could better leverage standard library features:

  • Custom implementations that duplicate <algorithm> functions
  • Manual memory management that could use RAII
  • Custom container implementations vs standard containers
  • String manipulation that could use modern string APIs
  • Use std::clamp to truncate values to min/max instead of manual comparisons

4. Z3-Specific Code Quality Improvements

Identify opportunities specific to Z3's architecture and coding patterns:

Constructor/Destructor Optimization:

  • Empty constructors: Truly empty constructors that should use = default
    • Distinguish between completely empty constructors (can use = default)
    • Constructors with member initializers (may still be candidates for improvement)
    • Constructors that only initialize members to default values
  • Empty destructors: Trivial destructors that can be removed or use = default
    • Destructors with empty body ~Class() {}
    • Non-virtual destructors that don't need to be explicitly defined
    • Virtual destructors (keep explicit even if empty for polymorphic classes), but remove empty overridden destructors since those are implicit
  • Non-virtual destructors: Analyze consistency and correctness
    • Classes with virtual functions but non-virtual destructors (potential issue)
    • Base classes without virtual destructors (check if inheritance is intended)
    • Non-virtual destructors missing noexcept (should be added)
    • Leaf classes with unnecessary virtual destructors (minor overhead)
  • Missing noexcept on non-default constructors and destructors
  • Opportunities to use compiler-generated special members (= default, = delete)

Implementation Pattern Improvements:

  • m_imp (implementation pointer) pattern in classes used only within one file
    • These should use anonymous namespace for implementation classes instead
    • Look for classes only exported through builder/factory functions
    • Examples: simplifiers, transformers, local utility classes

Memory Layout Optimization:

  • Classes that can be made POD (Plain Old Data)
  • Field reordering to reduce padding and shrink class size
    • Use static_assert and sizeof to verify size improvements
    • Group fields by size (larger types first) for optimal packing

AST and Expression Optimization:

  • Redundant AST creation calls (rebuilding same expression multiple times)
  • Opportunities to cache and reuse AST node references
  • Use of temporaries instead of repeated construction

Hash Table Operations:

  • Double hash lookups (check existence + insert/retrieve)
  • Opportunities to use single-lookup patterns supported by Z3's hash tables
  • Example: insert_if_not_there or equivalent patterns

Smart Pointer Usage:

  • Manual deallocation of custom allocator pointers
  • Opportunities to introduce custom smart pointers for automatic cleanup
  • Wrapping allocator-managed objects in RAII wrappers

Move Semantics:

  • Places where std::move is needed but missing
  • Incorrect usage of std::move (moving from const references, etc.)
  • Return value optimization opportunities being blocked

Optional Value Patterns:

  • Functions returning null + using output parameters
  • Replace with std::optional<T> return values
  • Cleaner API that avoids pointer/reference output parameters

Bitfield Opportunities:

  • Structs with multiple boolean flags
  • Small integer fields that could use bitfields
  • Size reduction potential through bitfield packing

Array Parameter Patterns:

  • Functions taking pointer + size parameters
  • Replace with std::span for type-safe array views
  • Improves API safety and expressiveness

Increment Operators:

  • Usage of postfix i++ where prefix ++i would suffice
  • Places where the result value isn't used
  • Micro-optimization for iterator-heavy code

Exception Control Flow:

  • Using exceptions for normal control flow
  • Alternatives: std::expected, std::optional, error codes
  • Performance and clarity improvements

Analysis Methodology

  1. Sample key directories in the codebase:

    • src/util/ - Core utilities and data structures
    • src/ast/ - Abstract syntax tree implementations
    • src/smt/ - SMT solver core
    • src/sat/ - SAT solver components
    • src/api/ - Public API surface
    • src/tactic/ - Tactics and simplifiers (good for m_imp pattern analysis)
    • Use glob to find representative source files
  2. Use code search tools effectively:

    • grep with patterns to find specific code constructs
    • glob to identify file groups for analysis
    • view to examine specific files in detail
    • bash with git commands to check file history
    • If compile_commands.json can be generated with clang, and clang-tidy is available, run a targeted checkset on the selected files:
      • modernize-use-nullptr
      • modernize-use-override
      • modernize-loop-convert (review carefully)
      • bugprone-* (selected high-signal checks)
      • performance-* (selected)
  3. Identify patterns by examining multiple files:

    • Look at 10-15 representative files per major area
    • Note common patterns vs inconsistencies
    • Check both header (.h) and implementation (.cpp) files
    • Use sizeof and field alignment to analyze struct sizes
  4. Quantify findings:

    • Count occurrences of specific patterns
    • Identify which areas are most affected
    • Prioritize findings by impact and prevalence
    • Measure potential size savings for memory layout optimizations

Deliverable: Detailed Analysis Discussion

Create a comprehensive discussion with your findings structured as follows:

Discussion Title

"Code Conventions Analysis - [Date] - [Key Finding Summary]"

Discussion Body Structure

# Code Conventions Analysis Report

**Analysis Date**: [Current Date]
**Files Examined**: ~[number] files across key directories

## Executive Summary

[Brief overview of key findings - 2-3 sentences]

## 1. Coding Convention Consistency Findings

### 1.1 Naming Conventions
- **Current State**: [What you observed]
- **Inconsistencies Found**: [List specific examples with file:line references]
- **Recommendation**: [Suggested standard to adopt]

### 1.2 Code Formatting
- **Alignment with .clang-format**: [Assessment]
- **Common Deviations**: [List patterns that deviate from style guide]
- **Files Needing Attention**: [List specific files or patterns]

### 1.3 Documentation Style
- **Current Practices**: [Observed documentation patterns]
- **Inconsistencies**: [Examples of different documentation approaches]
- **Recommendation**: [Suggested documentation standard]

### 1.4 Include Patterns
- **Header Guard Usage**: `#pragma once` vs traditional guards
- **Include Order**: [Observed patterns]
- **Recommendations**: [Suggested improvements]

### 1.5 Error Handling
- **Current Approaches**: [Exception usage, return codes, assertions]
- **Consistency Assessment**: [Are patterns consistent across modules?]
- **Recommendations**: [Suggested standards]

## 2. Modern C++ Feature Opportunities

For each opportunity, provide:
- **Feature**: [Name of C++ feature]
- **Current Pattern**: [What's used now with examples]
- **Modern Alternative**: [How it could be improved]
- **Impact**: [Benefits: readability, safety, performance]
- **Example Locations**: [File:line references]
- **Estimated Effort**: [Low/Medium/High]

### 2.1 C++11/14 Features

#### Opportunity: [Feature Name]
- **Current**: `[code example]` in `src/path/file.cpp:123`
- **Modern**: `[improved code example]`
- **Benefit**: [Why this is better]
- **Prevalence**: Found in [number] locations

[Repeat for each opportunity]

### 2.2 C++17 Features

[Same structure as above]

### 2.3 C++20 Features

[Same structure as above]

## 3. Standard Library Usage Opportunities

### 3.1 Algorithm Usage
- **Custom Implementations**: [Examples of reinvented algorithms]
- **Standard Alternatives**: [Which std algorithms could be used]

### 3.2 Container Patterns
- **Current**: [Custom containers or patterns]
- **Standard**: [Standard library alternatives]

### 3.3 Memory Management
- **Manual Patterns**: [Raw pointers, manual new/delete]
- **RAII Opportunities**: [Where smart pointers could help]

### 3.4 Value Clamping
- **Current**: [Manual min/max comparisons]
- **Modern**: [`std::clamp` usage opportunities]

## 4. Z3-Specific Code Quality Opportunities

### 4.1 Constructor/Destructor Optimization

#### 4.1.1 Empty Constructor Analysis
- **Truly Empty Constructors**: Constructors with completely empty bodies
  - Count: [Number of `ClassName() {}` patterns]
  - Recommendation: Replace with `= default` or remove if compiler can generate
  - Examples: [File:line references]
- **Constructors with Only Member Initializers**: Constructors that could use in-class initializers
  - Pattern: `ClassName() : m_member(value) {}`
  - Recommendation: Move initialization to class member declaration if appropriate
  - Examples: [File:line references]
- **Default Value Constructors**: Constructors that only set members to default values
  - Pattern: Constructor setting pointers to nullptr, ints to 0, bools to false
  - Recommendation: Use in-class member initializers and `= default`
  - Examples: [File:line references]

#### 4.1.2 Empty Destructor Analysis
- **Non-Virtual Empty Destructors**: Destructors with empty bodies in non-polymorphic classes
  - Count: [Number of `~ClassName() {}` patterns without virtual]
  - Recommendation: Remove or use `= default` to reduce binary size
  - Examples: [File:line references]
- **Virtual Empty Destructors**: Empty virtual destructors in base classes
  - Count: [Number found]
  - Recommendation: Keep explicit (required for polymorphism), but ensure `= default` or add comment
  - Examples: [File:line references]

#### 4.1.3 Non-Virtual Destructor Safety Analysis
- **Classes with Virtual Methods but Non-Virtual Destructors**: Potential polymorphism issues
  - Pattern: Class has virtual methods but destructor is not virtual
  - Risk: If used polymorphically, may cause undefined behavior
  - Count: [Number of classes]
  - Examples: [File:line references with class hierarchy info]
- **Base Classes without Virtual Destructors**: Classes that might be inherited from
  - Check: Does class have derived classes in codebase?
  - Recommendation: Add virtual destructor if inheritance is intended, or mark class `final`
  - Examples: [File:line references]
- **Leaf Classes with Unnecessary Virtual Destructors**: Final classes with virtual destructors
  - Pattern: Class marked `final` but has `virtual ~ClassName()`
  - Recommendation: Remove `virtual` keyword (minor optimization)
  - Examples: [File:line references]

#### 4.1.4 Missing noexcept Analysis
- **Non-Default Constructors without noexcept**: Constructors that don't throw
  - Pattern: Explicit constructors without `noexcept` specification
  - Recommendation: Add `noexcept` if constructor doesn't throw
  - Count: [Number found]
  - Examples: [File:line references]
- **Non-Virtual Destructors without noexcept**: Destructors should be noexcept by default
  - Pattern: Non-virtual destructors without explicit `noexcept`
  - Recommendation: Add explicit `noexcept` for clarity (or rely on implicit)
  - Note: Destructors are implicitly noexcept, but explicit is clearer
  - Count: [Number found]
  - Examples: [File:line references]
- **Virtual Destructors without noexcept**: Virtual destructors that should be noexcept
  - Pattern: `virtual ~ClassName()` without `noexcept`
  - Recommendation: Add `noexcept` for exception safety guarantees
  - Count: [Number found]
  - Examples: [File:line references]

#### 4.1.5 Compiler-Generated Special Members
- **Classes with Explicit Rule of 3/5**: Classes that define some but not all special members
  - Rule of 5: Constructor, Destructor, Copy Constructor, Copy Assignment, Move Constructor, Move Assignment
  - Recommendation: Either define all or use `= default`/`= delete` appropriately
  - Examples: [File:line references]
- **Impact**: [Code size reduction potential, compile time improvements]

### 4.2 Implementation Pattern (m_imp) Analysis
- **Current Usage**: [Files using m_imp pattern for internal-only classes]
- **Opportunity**: [Classes that could use anonymous namespace instead]
- **Criteria**: Classes only exported through builder/factory functions
- **Examples**: [Specific simplifiers, transformers, utility classes]

### 4.3 Memory Layout Optimization
- **POD Candidates**: [Classes that can be made POD]
- **Field Reordering**: [Classes with padding that can be reduced]
- **Size Analysis**: [Use static_assert + sizeof results]
- **Bitfield Opportunities**: [Structs with bool flags or small integers]
- **Estimated Savings**: [Total size reduction across codebase]

### 4.4 AST Creation Efficiency
- **Redundant Creation**: [Examples of rebuilding same expression multiple times]
- **Temporary Usage**: [Places where temporaries could be cached]
- **Impact**: [Performance improvement potential]

### 4.5 Hash Table Operation Optimization
- **Double Lookups**: [Check existence + insert/get patterns]
- **Single Lookup Pattern**: [How to use Z3's hash table APIs efficiently]
- **Examples**: [Specific files and patterns]
- **Performance Impact**: [Lookup reduction potential]

### 4.6 Custom Smart Pointer Opportunities
- **Manual Deallocation**: [Code manually calling custom allocator free]
- **RAII Wrapper Needed**: [Where custom smart pointer would help]
- **Simplification**: [Code that would be cleaner with auto cleanup]

### 4.7 Move Semantics Analysis
- **Missing std::move**: [Returns/assignments that should use move]
- **Incorrect std::move**: [Move from const, unnecessary moves]
- **Return Value Optimization**: [Places where RVO is blocked]

### 4.8 Optional Value Pattern Modernization
- **Current Pattern**: [Functions returning null + output parameters]
- **Modern Pattern**: [std::optional<T> return value opportunities]
- **API Improvements**: [Specific function signatures to update]
- **Examples**: [File:line references with before/after]

### 4.9 Array Parameter Modernization
- **Current**: [Pointer + size parameter pairs]
- **Modern**: [std::span usage opportunities]
- **Type Safety**: [How span improves API safety]
- **Examples**: [Function signatures to update]

### 4.10 Increment Operator Patterns
- **Postfix Usage**: [Count of i++ where result is unused]
- **Prefix Preference**: [Places to use ++i instead]
- **Iterator Loops**: [Heavy iterator usage areas]

### 4.11 Exception Control Flow
- **Current Usage**: [Exceptions used for normal control flow]
- **Modern Alternatives**: [std::expected, std::optional, error codes]
- **Performance**: [Impact of exception-based control flow]
- **Refactoring Opportunities**: [Specific patterns to replace]

## 5. Priority Recommendations

Ranked list of improvements by impact and effort:

1. **[Recommendation Title]** - [Impact: High/Medium/Low] - [Effort: High/Medium/Low]
   - Description: [What to do]
   - Rationale: [Why this matters]
   - Affected Areas: [Where to apply]

[Continue ranking...]

## 6. Sample Refactoring Examples

Provide 3-5 concrete examples of recommended refactorings:

### Example 1: [Title]
**Location**: `src/path/file.cpp:123-145`

**Current Code**:
\`\`\`cpp
[Show current implementation]
\`\`\`

**Modernized Code**:
\`\`\`cpp
[Show improved implementation]
\`\`\`

**Benefits**: [List improvements]

[Repeat for other examples]

## 7. Next Steps

- [ ] Review and prioritize these recommendations
- [ ] Create focused issues for high-priority items
- [ ] Consider updating coding standards documentation
- [ ] Plan incremental refactoring efforts
- [ ] Consider running automated refactoring tools (e.g., clang-tidy)

## Appendix: Analysis Statistics

- **Total files examined**: [number]
- **Source directories covered**: [list]
- **Lines of code reviewed**: ~[estimate]
- **Pattern occurrences counted**: [key patterns with counts]

Important Guidelines

  • Be thorough but focused: Examine a representative sample, not every file
  • Provide specific examples: Always include file paths and line numbers
  • Balance idealism with pragmatism: Consider the effort required for changes
  • Respect existing patterns: Z3 has evolved over time; some patterns exist for good reasons
  • Focus on high-impact changes: Prioritize improvements that enhance:
    • Code maintainability
    • Type safety
    • Readability
    • Performance (where measurable)
    • Binary size (constructor/destructor removal, memory layout)
    • Memory efficiency (POD classes, field reordering, bitfields)
  • Be constructive: Frame findings as opportunities, not criticisms
  • Quantify when possible: Use numbers to show prevalence of patterns
  • Consider backward compatibility: Z3 is a mature project with many users
  • Measure size improvements: Use static_assert and sizeof to verify memory layout optimizations
  • Prioritize safety: Smart pointers, std::optional, and std::span improve type safety
  • Consider performance: Hash table optimizations and AST caching have measurable impact

Code Search Examples

Find raw pointer usage:

grep pattern: "new [A-Za-z_]" glob: "src/**/*.cpp"

Find NULL usage (should be nullptr):

grep pattern: "== NULL|!= NULL| NULL;" glob: "src/**/*.{cpp,h}"

Find traditional for loops that could be range-based:

grep pattern: "for.*::iterator" glob: "src/**/*.cpp"

Find manual memory management:

grep pattern: "delete |delete\[\]" glob: "src/**/*.cpp"

Find enum (non-class) declarations:

grep pattern: "^[ ]*enum [^c]" glob: "src/**/*.h"

Find empty/trivial constructors and destructors:

# Empty constructors in implementation files
grep pattern: "[A-Za-z_]+::[A-Za-z_]+\(\)\s*\{\s*\}" glob: "src/**/*.cpp"

# Empty constructors in header files
grep pattern: "[A-Za-z_]+\(\)\s*\{\s*\}" glob: "src/**/*.h"

# Empty destructors in implementation files
grep pattern: "[A-Za-z_]+::~[A-Za-z_]+\(\)\s*\{\s*\}" glob: "src/**/*.cpp"

# Empty destructors in header files
grep pattern: "~[A-Za-z_]+\(\)\s*\{\s*\}" glob: "src/**/*.h"

# Constructors with only member initializer lists (candidates for in-class init)
grep pattern: "[A-Za-z_]+\(\)\s*:\s*[a-z_]+\([^)]*\)\s*\{\s*\}" glob: "src/**/*.cpp"

# Virtual destructors (to distinguish from non-virtual)
grep pattern: "virtual\s+~[A-Za-z_]+" glob: "src/**/*.h"

Find constructors/destructors without noexcept:

# Non-virtual destructors without noexcept in headers
grep pattern: "~[A-Za-z_]+\(\)(?!.*noexcept)(?!.*virtual)" glob: "src/**/*.h"

# Virtual destructors without noexcept
grep pattern: "virtual\s+~[A-Za-z_]+\(\)(?!.*noexcept)" glob: "src/**/*.h"

# Explicit constructors without noexcept
grep pattern: "explicit\s+[A-Za-z_]+\([^)]*\)(?!.*noexcept)" glob: "src/**/*.h"

# Non-default constructors without noexcept
grep pattern: "[A-Za-z_]+\([^)]+\)(?!.*noexcept)(?!.*=\s*default)" glob: "src/**/*.h"

Find potential non-virtual destructor safety issues:

# Classes with virtual functions (candidates to check destructor)
grep pattern: "class\s+[A-Za-z_]+.*\{.*virtual\s+" glob: "src/**/*.h"

# Classes marked final (can have non-virtual destructors)
grep pattern: "class\s+[A-Za-z_]+.*final" glob: "src/**/*.h"

# Base classes that might need virtual destructors
grep pattern: "class\s+[A-Za-z_]+\s*:\s*public" glob: "src/**/*.h"

# Non-virtual destructors in classes with virtual methods
grep pattern: "class.*\{.*virtual.*~[A-Za-z_]+\(\)(?!.*virtual)" multiline: true glob: "src/**/*.h"

Find m_imp pattern usage:

grep pattern: "m_imp|m_impl" glob: "src/**/*.{h,cpp}"
grep pattern: "class.*_imp[^a-z]" glob: "src/**/*.cpp"

Find potential POD struct candidates:

grep pattern: "struct [A-Za-z_]+ \{" glob: "src/**/*.h"

Find potential bitfield opportunities (multiple bools):

grep pattern: "bool [a-z_]+;.*bool [a-z_]+;" glob: "src/**/*.h"

Find redundant AST creation:

grep pattern: "mk_[a-z_]+\(.*mk_[a-z_]+\(" glob: "src/**/*.cpp"

Find double hash lookups:

grep pattern: "contains\(.*\).*insert\(|find\(.*\).*insert\(" glob: "src/**/*.cpp"

Find manual deallocation:

grep pattern: "dealloc\(|deallocate\(" glob: "src/**/*.cpp"

Find missing std::move in returns:

grep pattern: "return [a-z_]+;" glob: "src/**/*.cpp"

Find functions returning null with output parameters:

grep pattern: "return.*nullptr.*&" glob: "src/**/*.{h,cpp}"
grep pattern: "bool.*\(.*\*.*\)|bool.*\(.*&" glob: "src/**/*.h"

Find pointer + size parameters:

grep pattern: "\([^,]+\*[^,]*,\s*size_t|, unsigned.*size\)" glob: "src/**/*.h"

Find postfix increment:

grep pattern: "[a-z_]+\+\+\s*[;\)]" glob: "src/**/*.cpp"

Find std::clamp opportunities:

grep pattern: "std::min\(.*std::max\(|std::max\(.*std::min\(" glob: "src/**/*.cpp"
grep pattern: "if.*<.*\{.*=|if.*>.*\{.*=" glob: "src/**/*.cpp"

Find exceptions used for control flow:

grep pattern: "try.*\{.*for\(|try.*\{.*while\(" glob: "src/**/*.cpp"
grep pattern: "catch.*continue|catch.*break" glob: "src/**/*.cpp"

Security and Safety

  • Never execute untrusted code
  • Use bash only for safe read-only operations (git, grep patterns)
  • Don't modify any files (this is an analysis-only workflow)
  • Focus on identifying issues, not fixing them (fixes can be done in follow-up PRs)

Output Requirements

  • Create exactly ONE comprehensive discussion with all findings
  • Use the structured format above
  • Include specific file references for all examples
  • Provide actionable recommendations
  • Previous discussions created by this workflow will be automatically closed (using close-older-discussions: true)