Summary: These pages are not referenced from anywhere and are stale, oops! We even linked to checker-bug-types from our footer on all pages... These pages are stale and replaced with auto-generated ones now. Reviewed By: skcho Differential Revision: D26544298 fbshipit-source-id: c3b7742b8master
parent
e8dc75f92a
commit
620f6f53ea
File diff suppressed because it is too large
Load Diff
@ -1,271 +0,0 @@
|
|||||||
---
|
|
||||||
id: eradicate-warnings
|
|
||||||
title: Eradicate warnings
|
|
||||||
---
|
|
||||||
|
|
||||||
Below you will find a description of all the warnings reported by
|
|
||||||
[Eradicate](/docs/eradicate).
|
|
||||||
|
|
||||||
## Eradicate null field access
|
|
||||||
|
|
||||||
A field access of the form x.field where x could be null.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void foo(@Nullable C x) {
|
|
||||||
x.field = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Make sure that x cannot be null by changing the code or changing
|
|
||||||
annotations. If this cannot be done, the only choice is to use defensive
|
|
||||||
programming: if (x != null) { ... x.field ... } else { ... you need to decide
|
|
||||||
what to do when x is null ... } The general recommendation is to push null
|
|
||||||
checks up the call chain as much as possible in order to detect the place where
|
|
||||||
null values originate and deal with them at that point. When a null value is
|
|
||||||
propagated down the call chain it is often difficult to determine its origin
|
|
||||||
without global knowledge of what the program does. For example, a null value
|
|
||||||
could originate in third party libraries which are not under your control, and
|
|
||||||
the best place to check for null is typically immediately after calling these
|
|
||||||
library functions.
|
|
||||||
|
|
||||||
## Eradicate null method call
|
|
||||||
|
|
||||||
A method call x.m(...) where x could be null.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void foo(@Nullable C x) {
|
|
||||||
String s = x.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Same as for Null field access.
|
|
||||||
|
|
||||||
## Eradicate field not nullable
|
|
||||||
|
|
||||||
An assignment x.f = v where v could be null and field f is not annotated with
|
|
||||||
@Nullable.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
String f;
|
|
||||||
|
|
||||||
void foo(@Nullable String s) {
|
|
||||||
f = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to ensure that a null value is never stored in
|
|
||||||
the field, by changing the code or changing annotations. If this cannot be done,
|
|
||||||
add a @Nullable annotation to the field. This annotation might trigger more
|
|
||||||
warnings in other code that uses the field, as that code must now deal with null
|
|
||||||
values.
|
|
||||||
|
|
||||||
## Eradicate field not initialized
|
|
||||||
|
|
||||||
The constructor does not initialize a field f which is not annotated with
|
|
||||||
@Nullable
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
String f;
|
|
||||||
|
|
||||||
C () { // field f not initialized and not annotated @Nullable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to initialize the field with a value that is not
|
|
||||||
null. If, by design, null is a valid value for the field, then it should be
|
|
||||||
annotated with @Nullable.
|
|
||||||
|
|
||||||
## Eradicate parameter not nullable
|
|
||||||
|
|
||||||
Method call x.m(..., v, ...) where v can be null and the corresponding parameter
|
|
||||||
in method m is not annotated with @Nullable
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void m(C x) {
|
|
||||||
String s = x.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
void test(@Nullable C x) {
|
|
||||||
m(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to ensure that a null value is never passed to
|
|
||||||
the method, by changing the code or changing annotations. If this cannot be
|
|
||||||
done, add a @Nullable annotation to the relevant parameter in the method
|
|
||||||
declaration. This annotation might trigger more warnings in the implementation
|
|
||||||
of method m, as that code must now deal with null values.
|
|
||||||
|
|
||||||
## Eradicate return not nullable
|
|
||||||
|
|
||||||
Method m can return null, but the method's return type is not annotated with
|
|
||||||
@Nullable
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
String m() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to ensure that a null value is never returned by
|
|
||||||
the method, by changing the code or changing annotations. If this cannot be
|
|
||||||
done, add a @Nullable annotation to the the method declaration. This annotation
|
|
||||||
might trigger more warnings in the callers of method m, as the callers must now
|
|
||||||
deal with null values.
|
|
||||||
|
|
||||||
## Eradicate condition redundant
|
|
||||||
|
|
||||||
This report is inactive by default. Condition (x != null) or (x == null) when x
|
|
||||||
cannot be null: the first condition is always true and the second is always
|
|
||||||
false
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void m() {
|
|
||||||
String s = new String("abc");
|
|
||||||
if (s != null) {
|
|
||||||
int n = s.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Make sure that the annotations are correct, as the condition is
|
|
||||||
considered redundant based on the existing annotations. In particular, check the
|
|
||||||
annotation of any input parameters and fields of the current method, as well as
|
|
||||||
the annotations of any method called directly by the current method, if
|
|
||||||
relevant. If the annotations are correct, you can remove the redundant case.
|
|
||||||
|
|
||||||
## Eradicate return overannotated
|
|
||||||
|
|
||||||
This report is inactive by default. Method m is annotated with @Nullable but the
|
|
||||||
method cannot return null
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
@Nullable String m() {
|
|
||||||
String s = new String("abc");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Make sure that the annotations are correct, as the return annotation is
|
|
||||||
considered redundant based on the existing annotations. In particular, check the
|
|
||||||
annotation of any input parameters and fields of the current method, as well as
|
|
||||||
the annotations of any method called directly by the current method, if
|
|
||||||
relevant. If the annotations are correct, you can remove the @Nullable
|
|
||||||
annotation.
|
|
||||||
|
|
||||||
## Eradicate inconsistent subclass return annotation
|
|
||||||
|
|
||||||
The return type of the overridden method is annotated @Nullable, but the
|
|
||||||
corresponding method in the superclass is not.
|
|
||||||
|
|
||||||
Action: choose a consistent annotation based on the desired invariant.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class A {
|
|
||||||
String create() {
|
|
||||||
return new String("abc");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B extends A {
|
|
||||||
@Nullable String create() { // Inconsistent @Nullable annotation.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A consistent use of @Nullable on the return type across subtyping should prevent
|
|
||||||
runtime issue like in:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class Main {
|
|
||||||
|
|
||||||
int foo(A a) {
|
|
||||||
String s = a.create();
|
|
||||||
return s.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(String[] args) {
|
|
||||||
A a = new B();
|
|
||||||
foo(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Inconsistent subclass parameter annotation
|
|
||||||
|
|
||||||
A parameter of the overridden method is missing a @Nullable annotation present in the superclass.
|
|
||||||
|
|
||||||
Action: choose a consistent annotation based on the desired invariant.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class A {
|
|
||||||
|
|
||||||
int len(@Nullable String s) {
|
|
||||||
if (s != null) {
|
|
||||||
return s.length();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B extends A {
|
|
||||||
|
|
||||||
int len(String s) { // @Nullable missing.
|
|
||||||
return s.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A consistent use of @Nullable on parameters across subtyping should prevent runtime issue like in:
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
String s;
|
|
||||||
|
|
||||||
int foo() {
|
|
||||||
A a = new B();
|
|
||||||
return a.len(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,193 +0,0 @@
|
|||||||
---
|
|
||||||
id: linters-bug-types
|
|
||||||
title: Linters bug types
|
|
||||||
---
|
|
||||||
|
|
||||||
Here is an overview of the linter checks we provide in Infer:
|
|
||||||
|
|
||||||
## Assign pointer warning
|
|
||||||
|
|
||||||
This check fires when a pointer to an Obj-C object is tagged with an `assign`
|
|
||||||
property (similar to the `-Warc-unsafe-retained-assign` compiler flag). Not
|
|
||||||
holding a strong reference to the object makes it easy to accidentally create
|
|
||||||
and use a dangling pointer.
|
|
||||||
|
|
||||||
## Bad pointer comparison
|
|
||||||
|
|
||||||
Infer reports these warnings in Objective-C when a boxed primitive type such as
|
|
||||||
`NSNumber *` is coerced to a boolean in a comparison. For example, consider the
|
|
||||||
code
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
void foo(NSNumber * n) {
|
|
||||||
if (n) ...
|
|
||||||
```
|
|
||||||
|
|
||||||
The branch in the above code will be taken when the pointer `n` is non-`nil`,
|
|
||||||
but the programmer might have actually wanted the branch to be taken when the
|
|
||||||
integer pointed to by `n` is nonzero (e.g., she may have meant to call an
|
|
||||||
accessor like `[n intValue]` instead). Infer will ask the programmer explicitly
|
|
||||||
compare `n` to `nil` or call an accessor to clarify her intention.
|
|
||||||
|
|
||||||
## C++ reference captured in Objective-C block
|
|
||||||
|
|
||||||
With this check, Infer detects C++ references captured in a block. Doing this is
|
|
||||||
almost always wrong. The reason is that C++ references are not managed pointers
|
|
||||||
(like ARC pointers) and so the referent is likely to be gone by the time the
|
|
||||||
block gets executed. One solution is to do a local copy of the reference and
|
|
||||||
pass that to the block. Example:
|
|
||||||
|
|
||||||
```c
|
|
||||||
(int &) v;
|
|
||||||
...
|
|
||||||
const int copied_v = v;
|
|
||||||
^{
|
|
||||||
// use copied_v not v
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Direct atomic property access
|
|
||||||
|
|
||||||
This check warns you when you are accessing an atomic property directly with an
|
|
||||||
ivar. This makes the atomic property not atomic anymore. So potentially you may
|
|
||||||
get a race condition.
|
|
||||||
|
|
||||||
To fix the problem you need to access properties with their getter or setter.
|
|
||||||
|
|
||||||
## Global variable initialized with function or method call
|
|
||||||
|
|
||||||
This checker warns you when the initialization of global variable contain a
|
|
||||||
method or function call. The warning wants to make you aware that some functions
|
|
||||||
are expensive. As the global variables are initialized before main() is called,
|
|
||||||
these initializations can slow down the start-up time of an app.
|
|
||||||
|
|
||||||
## Registered observer being deallocated
|
|
||||||
|
|
||||||
Objects register with a notification center to receive notifications. This check
|
|
||||||
warns you when an object is registered as observer of a NSNotificationCenter but
|
|
||||||
it is never unregistered. This is problematic as if the object is not
|
|
||||||
unregistered the notification center can still send notification even after the
|
|
||||||
object has been deallocated. In that case we would get a crash.
|
|
||||||
|
|
||||||
## Strong delegate warning
|
|
||||||
|
|
||||||
This check warns you when you have a property called delegate or variations
|
|
||||||
thereof which is declared strong. The idea is that delegates should generally be
|
|
||||||
weak, otherwise this may cause retain cycles.
|
|
||||||
|
|
||||||
## Unavailable api in supported ios sdk
|
|
||||||
|
|
||||||
This checks warns you when you are using an API (constant, method call, etc.)
|
|
||||||
that is only defined in a version higher than the version that you support. To
|
|
||||||
enable this check, pass to Infer the option
|
|
||||||
`--iphoneos-target-sdk-version version`. Calling an undefined API will lead to a
|
|
||||||
crash in the app. To fix this, you can choose a different API or use it inside
|
|
||||||
an if, as in:
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) {
|
|
||||||
font = [UIFont systemFontOfSize:size weight:0];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_9_0) {
|
|
||||||
font = [UIFont systemFontOfSize:size weight:0];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Pointer To const Objective-C Class
|
|
||||||
|
|
||||||
In Objective-C, `const Class *` represents a mutable pointer pointing to an
|
|
||||||
Objective-C class where the ivars cannot be changed. More useful is
|
|
||||||
`Class *const` instead, meaning the destination of the pointer cannot be
|
|
||||||
changed.
|
|
||||||
|
|
||||||
## Objective-C Weak Property has Custom Setter
|
|
||||||
|
|
||||||
This check warns you when you have a custom setter for a weak property. When
|
|
||||||
compiled with Automatic Reference Counting (ARC, `-fobj-arc`) ARC may set the
|
|
||||||
property to `nil` without invoking the setter, for example:
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@interface Employee : NSObject {
|
|
||||||
NSString* _name;
|
|
||||||
__weak Employee* _manager;
|
|
||||||
}
|
|
||||||
-(id)initWithName:(NSString*)name;
|
|
||||||
@property(atomic, weak) Employee* manager;
|
|
||||||
-(void)report;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Employee
|
|
||||||
|
|
||||||
-(id)initWithName:(NSString*)name {
|
|
||||||
_name = name;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(NSString*)description {
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)report {
|
|
||||||
NSLog(@"I work for %@", _manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
-(Employee*)manager {
|
|
||||||
return _manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DON'T do this; ARC will not call this when setting _manager to nil.
|
|
||||||
-(void)setManager:(Employee*)newManager {
|
|
||||||
NSLog(@"Meet the new boss...");
|
|
||||||
_manager = newManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
Employee* bob = [[Employee alloc] initWithName:@"Bob"];
|
|
||||||
Employee* sue = [[Employee alloc] initWithName:@"Sue"];
|
|
||||||
bob.manager = sue;
|
|
||||||
[bob report];
|
|
||||||
sue = nil;
|
|
||||||
[bob report];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This prints:
|
|
||||||
|
|
||||||
```
|
|
||||||
Meet the new boss...
|
|
||||||
I work for Sue
|
|
||||||
I work for (null)
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the custom setter was only invoked once.
|
|
||||||
|
|
||||||
## Component factory function
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/break-out-composites)
|
|
||||||
|
|
||||||
## Component initializer with side effects
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/no-side-effects)
|
|
||||||
|
|
||||||
## Component with multiple factory methods
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/avoid-overrides)
|
|
||||||
|
|
||||||
## Component with unconventional superclass
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/never-subclass-components)
|
|
||||||
|
|
||||||
## Mutable local variable in component file
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/avoid-local-variables)
|
|
File diff suppressed because it is too large
Load Diff
@ -1,271 +0,0 @@
|
|||||||
---
|
|
||||||
id: eradicate-warnings
|
|
||||||
title: Eradicate warnings
|
|
||||||
---
|
|
||||||
|
|
||||||
Below you will find a description of all the warnings reported by
|
|
||||||
[Eradicate](/docs/eradicate).
|
|
||||||
|
|
||||||
## Eradicate null field access
|
|
||||||
|
|
||||||
A field access of the form x.field where x could be null.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void foo(@Nullable C x) {
|
|
||||||
x.field = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Make sure that x cannot be null by changing the code or changing
|
|
||||||
annotations. If this cannot be done, the only choice is to use defensive
|
|
||||||
programming: if (x != null) { ... x.field ... } else { ... you need to decide
|
|
||||||
what to do when x is null ... } The general recommendation is to push null
|
|
||||||
checks up the call chain as much as possible in order to detect the place where
|
|
||||||
null values originate and deal with them at that point. When a null value is
|
|
||||||
propagated down the call chain it is often difficult to determine its origin
|
|
||||||
without global knowledge of what the program does. For example, a null value
|
|
||||||
could originate in third party libraries which are not under your control, and
|
|
||||||
the best place to check for null is typically immediately after calling these
|
|
||||||
library functions.
|
|
||||||
|
|
||||||
## Eradicate null method call
|
|
||||||
|
|
||||||
A method call x.m(...) where x could be null.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void foo(@Nullable C x) {
|
|
||||||
String s = x.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Same as for Null field access.
|
|
||||||
|
|
||||||
## Eradicate field not nullable
|
|
||||||
|
|
||||||
An assignment x.f = v where v could be null and field f is not annotated with
|
|
||||||
@Nullable.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
String f;
|
|
||||||
|
|
||||||
void foo(@Nullable String s) {
|
|
||||||
f = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to ensure that a null value is never stored in
|
|
||||||
the field, by changing the code or changing annotations. If this cannot be done,
|
|
||||||
add a @Nullable annotation to the field. This annotation might trigger more
|
|
||||||
warnings in other code that uses the field, as that code must now deal with null
|
|
||||||
values.
|
|
||||||
|
|
||||||
## Eradicate field not initialized
|
|
||||||
|
|
||||||
The constructor does not initialize a field f which is not annotated with
|
|
||||||
@Nullable
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
String f;
|
|
||||||
|
|
||||||
C () { // field f not initialized and not annotated @Nullable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to initialize the field with a value that is not
|
|
||||||
null. If, by design, null is a valid value for the field, then it should be
|
|
||||||
annotated with @Nullable.
|
|
||||||
|
|
||||||
## Eradicate parameter not nullable
|
|
||||||
|
|
||||||
Method call x.m(..., v, ...) where v can be null and the corresponding parameter
|
|
||||||
in method m is not annotated with @Nullable
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void m(C x) {
|
|
||||||
String s = x.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
void test(@Nullable C x) {
|
|
||||||
m(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to ensure that a null value is never passed to
|
|
||||||
the method, by changing the code or changing annotations. If this cannot be
|
|
||||||
done, add a @Nullable annotation to the relevant parameter in the method
|
|
||||||
declaration. This annotation might trigger more warnings in the implementation
|
|
||||||
of method m, as that code must now deal with null values.
|
|
||||||
|
|
||||||
## Eradicate return not nullable
|
|
||||||
|
|
||||||
Method m can return null, but the method's return type is not annotated with
|
|
||||||
@Nullable
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
String m() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: The preferred action is to ensure that a null value is never returned by
|
|
||||||
the method, by changing the code or changing annotations. If this cannot be
|
|
||||||
done, add a @Nullable annotation to the the method declaration. This annotation
|
|
||||||
might trigger more warnings in the callers of method m, as the callers must now
|
|
||||||
deal with null values.
|
|
||||||
|
|
||||||
## Eradicate condition redundant
|
|
||||||
|
|
||||||
This report is inactive by default. Condition (x != null) or (x == null) when x
|
|
||||||
cannot be null: the first condition is always true and the second is always
|
|
||||||
false
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
void m() {
|
|
||||||
String s = new String("abc");
|
|
||||||
if (s != null) {
|
|
||||||
int n = s.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Make sure that the annotations are correct, as the condition is
|
|
||||||
considered redundant based on the existing annotations. In particular, check the
|
|
||||||
annotation of any input parameters and fields of the current method, as well as
|
|
||||||
the annotations of any method called directly by the current method, if
|
|
||||||
relevant. If the annotations are correct, you can remove the redundant case.
|
|
||||||
|
|
||||||
## Eradicate return overannotated
|
|
||||||
|
|
||||||
This report is inactive by default. Method m is annotated with @Nullable but the
|
|
||||||
method cannot return null
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class C {
|
|
||||||
@Nullable String m() {
|
|
||||||
String s = new String("abc");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Action: Make sure that the annotations are correct, as the return annotation is
|
|
||||||
considered redundant based on the existing annotations. In particular, check the
|
|
||||||
annotation of any input parameters and fields of the current method, as well as
|
|
||||||
the annotations of any method called directly by the current method, if
|
|
||||||
relevant. If the annotations are correct, you can remove the @Nullable
|
|
||||||
annotation.
|
|
||||||
|
|
||||||
## Eradicate inconsistent subclass return annotation
|
|
||||||
|
|
||||||
The return type of the overridden method is annotated @Nullable, but the
|
|
||||||
corresponding method in the superclass is not.
|
|
||||||
|
|
||||||
Action: choose a consistent annotation based on the desired invariant.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class A {
|
|
||||||
String create() {
|
|
||||||
return new String("abc");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B extends A {
|
|
||||||
@Nullable String create() { // Inconsistent @Nullable annotation.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A consistent use of @Nullable on the return type across subtyping should prevent
|
|
||||||
runtime issue like in:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class Main {
|
|
||||||
|
|
||||||
int foo(A a) {
|
|
||||||
String s = a.create();
|
|
||||||
return s.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(String[] args) {
|
|
||||||
A a = new B();
|
|
||||||
foo(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Inconsistent subclass parameter annotation
|
|
||||||
|
|
||||||
A parameter of the overridden method is missing a @Nullable annotation present in the superclass.
|
|
||||||
|
|
||||||
Action: choose a consistent annotation based on the desired invariant.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```java
|
|
||||||
class A {
|
|
||||||
|
|
||||||
int len(@Nullable String s) {
|
|
||||||
if (s != null) {
|
|
||||||
return s.length();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class B extends A {
|
|
||||||
|
|
||||||
int len(String s) { // @Nullable missing.
|
|
||||||
return s.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A consistent use of @Nullable on parameters across subtyping should prevent runtime issue like in:
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
String s;
|
|
||||||
|
|
||||||
int foo() {
|
|
||||||
A a = new B();
|
|
||||||
return a.len(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,193 +0,0 @@
|
|||||||
---
|
|
||||||
id: linters-bug-types
|
|
||||||
title: Linters bug types
|
|
||||||
---
|
|
||||||
|
|
||||||
Here is an overview of the linter checks we provide in Infer:
|
|
||||||
|
|
||||||
## Assign pointer warning
|
|
||||||
|
|
||||||
This check fires when a pointer to an Obj-C object is tagged with an `assign`
|
|
||||||
property (similar to the `-Warc-unsafe-retained-assign` compiler flag). Not
|
|
||||||
holding a strong reference to the object makes it easy to accidentally create
|
|
||||||
and use a dangling pointer.
|
|
||||||
|
|
||||||
## Bad pointer comparison
|
|
||||||
|
|
||||||
Infer reports these warnings in Objective-C when a boxed primitive type such as
|
|
||||||
`NSNumber *` is coerced to a boolean in a comparison. For example, consider the
|
|
||||||
code
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
void foo(NSNumber * n) {
|
|
||||||
if (n) ...
|
|
||||||
```
|
|
||||||
|
|
||||||
The branch in the above code will be taken when the pointer `n` is non-`nil`,
|
|
||||||
but the programmer might have actually wanted the branch to be taken when the
|
|
||||||
integer pointed to by `n` is nonzero (e.g., she may have meant to call an
|
|
||||||
accessor like `[n intValue]` instead). Infer will ask the programmer explicitly
|
|
||||||
compare `n` to `nil` or call an accessor to clarify her intention.
|
|
||||||
|
|
||||||
## C++ reference captured in Objective-C block
|
|
||||||
|
|
||||||
With this check, Infer detects C++ references captured in a block. Doing this is
|
|
||||||
almost always wrong. The reason is that C++ references are not managed pointers
|
|
||||||
(like ARC pointers) and so the referent is likely to be gone by the time the
|
|
||||||
block gets executed. One solution is to do a local copy of the reference and
|
|
||||||
pass that to the block. Example:
|
|
||||||
|
|
||||||
```c
|
|
||||||
(int &) v;
|
|
||||||
...
|
|
||||||
const int copied_v = v;
|
|
||||||
^{
|
|
||||||
// use copied_v not v
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Direct atomic property access
|
|
||||||
|
|
||||||
This check warns you when you are accessing an atomic property directly with an
|
|
||||||
ivar. This makes the atomic property not atomic anymore. So potentially you may
|
|
||||||
get a race condition.
|
|
||||||
|
|
||||||
To fix the problem you need to access properties with their getter or setter.
|
|
||||||
|
|
||||||
## Global variable initialized with function or method call
|
|
||||||
|
|
||||||
This checker warns you when the initialization of global variable contain a
|
|
||||||
method or function call. The warning wants to make you aware that some functions
|
|
||||||
are expensive. As the global variables are initialized before main() is called,
|
|
||||||
these initializations can slow down the start-up time of an app.
|
|
||||||
|
|
||||||
## Registered observer being deallocated
|
|
||||||
|
|
||||||
Objects register with a notification center to receive notifications. This check
|
|
||||||
warns you when an object is registered as observer of a NSNotificationCenter but
|
|
||||||
it is never unregistered. This is problematic as if the object is not
|
|
||||||
unregistered the notification center can still send notification even after the
|
|
||||||
object has been deallocated. In that case we would get a crash.
|
|
||||||
|
|
||||||
## Strong delegate warning
|
|
||||||
|
|
||||||
This check warns you when you have a property called delegate or variations
|
|
||||||
thereof which is declared strong. The idea is that delegates should generally be
|
|
||||||
weak, otherwise this may cause retain cycles.
|
|
||||||
|
|
||||||
## Unavailable api in supported ios sdk
|
|
||||||
|
|
||||||
This checks warns you when you are using an API (constant, method call, etc.)
|
|
||||||
that is only defined in a version higher than the version that you support. To
|
|
||||||
enable this check, pass to Infer the option
|
|
||||||
`--iphoneos-target-sdk-version version`. Calling an undefined API will lead to a
|
|
||||||
crash in the app. To fix this, you can choose a different API or use it inside
|
|
||||||
an if, as in:
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) {
|
|
||||||
font = [UIFont systemFontOfSize:size weight:0];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_9_0) {
|
|
||||||
font = [UIFont systemFontOfSize:size weight:0];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Pointer To const Objective-C Class
|
|
||||||
|
|
||||||
In Objective-C, `const Class *` represents a mutable pointer pointing to an
|
|
||||||
Objective-C class where the ivars cannot be changed. More useful is
|
|
||||||
`Class *const` instead, meaning the destination of the pointer cannot be
|
|
||||||
changed.
|
|
||||||
|
|
||||||
## Objective-C Weak Property has Custom Setter
|
|
||||||
|
|
||||||
This check warns you when you have a custom setter for a weak property. When
|
|
||||||
compiled with Automatic Reference Counting (ARC, `-fobj-arc`) ARC may set the
|
|
||||||
property to `nil` without invoking the setter, for example:
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@interface Employee : NSObject {
|
|
||||||
NSString* _name;
|
|
||||||
__weak Employee* _manager;
|
|
||||||
}
|
|
||||||
-(id)initWithName:(NSString*)name;
|
|
||||||
@property(atomic, weak) Employee* manager;
|
|
||||||
-(void)report;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Employee
|
|
||||||
|
|
||||||
-(id)initWithName:(NSString*)name {
|
|
||||||
_name = name;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(NSString*)description {
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)report {
|
|
||||||
NSLog(@"I work for %@", _manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
-(Employee*)manager {
|
|
||||||
return _manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DON'T do this; ARC will not call this when setting _manager to nil.
|
|
||||||
-(void)setManager:(Employee*)newManager {
|
|
||||||
NSLog(@"Meet the new boss...");
|
|
||||||
_manager = newManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
Employee* bob = [[Employee alloc] initWithName:@"Bob"];
|
|
||||||
Employee* sue = [[Employee alloc] initWithName:@"Sue"];
|
|
||||||
bob.manager = sue;
|
|
||||||
[bob report];
|
|
||||||
sue = nil;
|
|
||||||
[bob report];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This prints:
|
|
||||||
|
|
||||||
```
|
|
||||||
Meet the new boss...
|
|
||||||
I work for Sue
|
|
||||||
I work for (null)
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the custom setter was only invoked once.
|
|
||||||
|
|
||||||
## Component factory function
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/break-out-composites)
|
|
||||||
|
|
||||||
## Component initializer with side effects
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/no-side-effects)
|
|
||||||
|
|
||||||
## Component with multiple factory methods
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/avoid-overrides)
|
|
||||||
|
|
||||||
## Component with unconventional superclass
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/never-subclass-components)
|
|
||||||
|
|
||||||
## Mutable local variable in component file
|
|
||||||
|
|
||||||
[Doc in ComponentKit page](http://componentkit.org/docs/avoid-local-variables)
|
|
Loading…
Reference in new issue