#define written inside a method or function body
ID |
objectivec.maintainability.macro_define_in_block |
Severity |
info |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Preprocessor |
Language |
Objective-C |
Description
Reports a #define directive written inside a braced block - a method body, a function body or a nested block - rather than at file scope. The region runs from the line that opens the block to the closing brace at the same indentation, so a directive after the block has closed is not reported. A #undef, wherever it appears, belongs to the companion rule for undefining macros.
Rationale
The preprocessor has no idea the block exists: the macro is live from the directive to the end of the translation unit, not to the end of the method it is written in. Every method below inherits it, and a local variable or parameter elsewhere in the file that happens to share the name is silently rewritten. The indentation makes the opposite promise, so the reader has to know the language rule to see the bug.
The following code illustrates the pattern detected by this rule:
@implementation Uploader
- (void)upload {
// FLAGGED: #define written inside a method or function body
#define CHUNK 4096
NSLog(@"%d", CHUNK);
}
// The next directive sits after the method has closed: the control that shows the region ends at
// the method's own closing brace.
- (void)finish {
NSLog(@"done");
}
- (void)documented {
/*
* #define IN_A_BLOCK_COMMENT 1
*/
NSLog(@"nothing");
}
- (void)commentedOut {
// #define DISABLED 1
NSLog(@"nothing");
}
@end
Remediation
Move the directive to file scope, next to the other macros, so its lifetime matches where it reads as being defined. Better, replace it with something that really is local: a static const for a constant, or a local variable or static inline function for a computed value.