CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-checkerframework--checker-qual

Type qualifier annotations for the Checker Framework static analysis tool

Pending
Overview
Eval results
Files

signedness.mddocs/

Signedness Checker Annotations

Signedness Checker annotations distinguish between signed and unsigned interpretations of integer types. While Java's integer types are inherently signed, this checker helps prevent errors when working with unsigned values (such as those from C libraries, byte arrays, or bitwise operations) by tracking the intended interpretation of numeric values.

Capabilities

Signed Integer Type

Indicates that the value should be interpreted as signed (default for most Java integer types).

/**
 * The value is to be interpreted as signed. That is, if the most significant bit
 * in the bitwise representation is set, then the bits should be interpreted as a negative number.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({UnknownSignedness.class})
@DefaultQualifierInHierarchy
@DefaultFor(
    typeKinds = {
        TypeKind.BYTE, TypeKind.INT, TypeKind.LONG, TypeKind.SHORT,
        TypeKind.FLOAT, TypeKind.DOUBLE
    },
    types = {
        java.lang.Byte.class, java.lang.Integer.class, java.lang.Long.class,
        java.lang.Short.class, java.lang.Float.class, java.lang.Double.class
    },
    value = TypeUseLocation.EXCEPTION_PARAMETER)
public @interface Signed {}

Usage Examples:

import org.checkerframework.checker.signedness.qual.Signed;

public class SignedExample {
    // Explicitly signed values (though this is the default)
    @Signed int temperature = -10; // Can be negative
    @Signed long accountBalance = -1000L; // Can represent debt
    
    // Method working with signed values
    public @Signed int calculateDifference(@Signed int a, @Signed int b) {
        return a - b; // Result can be negative
    }
    
    // Safe signed operations
    public void processSignedData(@Signed byte[] data) {
        for (@Signed byte b : data) {
            if (b < 0) {
                // Handle negative values appropriately
                System.out.println("Negative byte: " + b);
            }
        }
    }
}

Unsigned Integer Type

Indicates that the value should be interpreted as unsigned (positive values with extended range).

/**
 * The value is to be interpreted as unsigned. That is, if the most significant bit
 * in the bitwise representation is set, then the bits should be interpreted as a
 * large positive number rather than as a negative number.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({UnknownSignedness.class})
@DefaultFor(
    typeKinds = {TypeKind.CHAR},
    types = {java.lang.Character.class})
public @interface Unsigned {}

Usage Examples:

import org.checkerframework.checker.signedness.qual.Unsigned;

public class UnsignedExample {
    // Unsigned values - always interpreted as positive
    @Unsigned int pixelColor = 0xFF0000FF; // RGBA color value
    @Unsigned byte[] hashBytes; // Hash values are unsigned
    
    // Method working with unsigned byte data
    public void processUnsignedBytes(@Unsigned byte[] data) {
        for (@Unsigned byte b : data) {
            // Interpret as 0-255, not -128 to 127
            int unsignedValue = Byte.toUnsignedInt(b);
            System.out.println("Unsigned value: " + unsignedValue);
        }
    }
    
    // Network protocol handling
    public @Unsigned int parseUnsignedInt(@Unsigned byte[] bytes) {
        // Build unsigned integer from byte array
        return ((bytes[0] & 0xFF) << 24) |
               ((bytes[1] & 0xFF) << 16) |
               ((bytes[2] & 0xFF) << 8) |
                (bytes[3] & 0xFF);
    }
    
    // File size handling
    public long getFileSize(@Unsigned int highBytes, @Unsigned int lowBytes) {
        return (((long) highBytes) << 32) | (lowBytes & 0xFFFFFFFFL);
    }
}

Signed Positive Type

Indicates values that are positive in both signed and unsigned interpretations.

/**
 * The expression's value is in the signed positive range; that is, its most significant bit is zero.
 * The value has the same interpretation as @Signed and @Unsigned — both interpretations are equivalent.
 * 
 * Programmers should rarely write @SignedPositive. Instead, write @Signed or @Unsigned 
 * to indicate the intended interpretation.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf(SignednessGlb.class)
public @interface SignedPositive {}

Usage Examples:

import org.checkerframework.checker.signedness.qual.SignedPositive;

public class SignedPositiveExample {
    // Values that are definitely positive (MSB = 0)
    @SignedPositive int count = 42; // Always positive
    @SignedPositive long timestamp = System.currentTimeMillis();
    
    // Method that ensures positive values
    public @SignedPositive int absoluteValue(@Signed int value) {
        return Math.abs(value); // Result is always positive
    }
    
    // Safe for both signed and unsigned operations
    public void processSafeValue(@SignedPositive int value) {
        // Safe to use in both contexts
        @Signed int signedView = value;     // OK - positive value
        @Unsigned int unsignedView = value; // OK - positive value
    }
}

Polymorphic Signedness

Creates polymorphic relationships preserving signedness across method calls.

/**
 * A polymorphic qualifier for signedness types.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@PolymorphicQualifier(UnknownSignedness.class)
public @interface PolySigned {}

Usage Examples:

import org.checkerframework.checker.signedness.qual.PolySigned;

public class PolySignedExample {
    // Preserves signedness of input
    public @PolySigned int identity(@PolySigned int value) {
        return value; // Same signedness as input
    }
    
    // Bitwise operations preserving signedness
    public @PolySigned int bitwiseAnd(@PolySigned int a, @PolySigned int b) {
        return a & b; // Preserves signedness interpretation
    }
    
    // Array processing with preserved signedness
    public @PolySigned int[] processArray(@PolySigned int[] input) {
        @PolySigned int[] result = new @PolySigned int[input.length];
        for (int i = 0; i < input.length; i++) {
            result[i] = input[i] * 2; // Maintains signedness
        }
        return result;
    }
}

Unknown Signedness

Indicates that the signedness is not known or not applicable.

/**
 * The value's signedness is not known to the Signedness Checker.
 * This is also used for non-numeric values, which cannot have a signedness.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({})
public @interface UnknownSignedness {}

Signedness Hierarchy Annotations

Additional annotations for the signedness type hierarchy.

/**
 * The greatest lower bound (GLB) of @Signed and @Unsigned.
 * Represents values that could be interpreted as either signed or unsigned.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({Signed.class, Unsigned.class})
public @interface SignednessGlb {}

/**
 * The bottom type in the signedness hierarchy.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({SignedPositive.class})
@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
public @interface SignednessBottom {}

Common Usage Patterns

File I/O and Network Operations:

import org.checkerframework.checker.signedness.qual.*;

public class IOExample {
    // Reading unsigned byte data
    public void readUnsignedBytes(InputStream is) throws IOException {
        @Unsigned byte[] buffer = new @Unsigned byte[1024];
        int bytesRead = is.read(buffer);
        
        for (int i = 0; i < bytesRead; i++) {
            @Unsigned byte b = buffer[i];
            int unsignedValue = Byte.toUnsignedInt(b); // 0-255 range
            processUnsignedByte(unsignedValue);
        }
    }
    
    // Network protocol with unsigned integers
    public @Unsigned int readUnsignedInt32(DataInputStream dis) throws IOException {
        return dis.readInt(); // Interpret as unsigned 32-bit value
    }
}

Cryptographic Operations:

public class CryptoExample {
    // Hash values are always unsigned
    public @Unsigned byte[] computeHash(byte[] input) {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        return md.digest(input);
    }
    
    // Bitwise operations on unsigned data
    public @Unsigned int combineUnsignedBytes(@Unsigned byte[] bytes) {
        @Unsigned int result = 0;
        for (@Unsigned byte b : bytes) {
            result = (result << 8) | (b & 0xFF);
        }
        return result;
    }
}

Type Definitions

// Import statements for using signedness annotations
import org.checkerframework.checker.signedness.qual.Signed;
import org.checkerframework.checker.signedness.qual.Unsigned;
import org.checkerframework.checker.signedness.qual.SignedPositive;
import org.checkerframework.checker.signedness.qual.PolySigned;
import org.checkerframework.checker.signedness.qual.UnknownSignedness;
import org.checkerframework.checker.signedness.qual.SignednessGlb;
import org.checkerframework.checker.signedness.qual.SignednessBottom;

// Utility methods for safe signedness conversions
public class SignednessUtils {
    // Convert signed to unsigned interpretation
    public static @Unsigned int toUnsigned(@Signed int value) {
        return value; // Same bits, different interpretation
    }
    
    // Convert unsigned to signed interpretation  
    public static @Signed int toSigned(@Unsigned int value) {
        return value; // Same bits, different interpretation
    }
    
    // Safe unsigned comparison
    public static boolean unsignedLessThan(@Unsigned int a, @Unsigned int b) {
        return Integer.compareUnsigned(a, b) < 0;
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-checkerframework--checker-qual

docs

concurrency.md

constant-value.md

contracts.md

framework.md

index-bounds.md

index.md

nullness.md

optional.md

resources.md

signedness.md

string-format.md

units.md

tile.json