Octal escape, hexadecimal escape or universal character name in a literal

ID

objectivec.maintainability.avoid_octal_escape

Severity

info

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Literal Format

Language

Objective-C

Description

Reports a well-formed numeric escape inside a string or character literal - an octal escape of one to three digits, a hexadecimal escape of one or two digits, and the universal character names \uXXXX and \UXXXXXXXX. The null terminator \0 is exempt, and so are the named escapes such as \n, \t and \", an escaped backslash, and occurrences inside a comment. An escape that runs into the characters after it - \x41f, \1011 - is not reported here; the malformed-escape-sequence rule owns that case, so the two rules never report the same escape.

Rationale

A numeric escape hides the character it produces behind a code the reader has to look up, and the two numeric bases are easy to confuse: \010 is a backspace, while \10 written by someone thinking in decimal is not ten either. The forms also have different lengths - octal stops after three digits, hexadecimal does not stop at all - so appending an ordinary character to a literal can silently change the escape rather than follow it. A universal character name has the same problem for text: the reader cannot see which character the literal holds without decoding the code point.

The following code illustrates the pattern detected by this rule:

@implementation Escapes
- (void)numericEscapes {
    // FLAGGED: Octal escape, hexadecimal escape or universal character name in a literal
    NSString *bell = @"ring\007 now";
    // FLAGGED: Octal escape, hexadecimal escape or universal character name in a literal
    char vertical = '\013';
    // FLAGGED: Octal escape, hexadecimal escape or universal character name in a literal
    NSString *letter = @"\x4A done";
    // FLAGGED: Octal escape, hexadecimal escape or universal character name in a literal
    char delimiter = '\x1f';
    NSString *accented = @"caf\u00E9 latte";
    NSString *emoji = @"\U0001F600 hello";
    NSLog(@"%@ %d %@ %d %@ %@", bell, vertical, letter, delimiter, accented, emoji);
}
@end

Remediation

Use the named escape where one exists - \n, \t, \r, \\, \". For text, write the character itself in a UTF-8 source file rather than encoding it as \u00E9 or \U0001F600. Where a specific byte value genuinely has to appear, give it a name - a static const char or an enum constant - so the meaning sits next to the value instead of inside the literal.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved