[help] import issue types documentation from website

Summary:
Take all the issue type documentation in the website and add it to infer
itself so it can generate the website (see further diffs).

I mostly generated this diff by writing a script to call from `utop`
with various file lists to do most of the heavy lifting for me and make
sure I didn't forget any issue types: P132800781

Reviewed By: ngorogiannis

Differential Revision: D21934372

fbshipit-source-id: f3ea8c566
master
Jules Villard 5 years ago committed by Facebook GitHub Bot
parent bc24cacd3a
commit f34bd2b069

@ -0,0 +1,4 @@
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.

@ -0,0 +1,14 @@
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.

@ -0,0 +1,8 @@
This will happen in one of two cases generally:
1. One uses `weakSelf` but forgot to declare it weak first.
2. One is using `strongSelf`, declared in a block, in another (inside) block.
This changes the delicate balance of the `weakSelf`/`strongSelf` use in the
first block. The retain cycle is avoided there because `strongSelf` is a
local variable to the block. If `strongSelf` is used in the inside block,
then it's not a local variable anymore, but a captured variable.

@ -0,0 +1,9 @@
This error type is Android-specific. It fires when a `Fragment` type fails to
nullify one or more of its declared `View` fields in `onDestroyView`. In
performance-sensitive applications, a `Fragment` should initialize all `View`'s
in `onCreateView` and nullify them in `onDestroyView`. If a `Fragment` is placed
on the back stack and fails to nullify a `View` in `onDestroyView`, it will
retain a useless reference to that `View` that will not be cleaned up until the
`Fragment` is resumed or destroyed.
Action: Nullify the `View` in question in `onDestroyView`.

@ -0,0 +1,15 @@
This error type is reported in Java. It fires when an immutable collection is
returned from a method whose type is mutable.
```java
public List<String> getSomeList() {
ImmutableList<String> l = foo(...);
return l;
}
```
This can lead to a runtime error if users of `getSomeList` try to modify the
list e.g. by adding elements.
Action: you can change the return type to be immutable, or make a copy of the
collection so that it can be modified.

@ -0,0 +1 @@
[Doc in ComponentKit page](http://componentkit.org/docs/never-subclass-components)

@ -0,0 +1,14 @@
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
};
```

@ -0,0 +1,60 @@
This error is currently reported in Java. A deadlock occurs when two distinct
threads try to acquire two locks in reverse orders. The following code
illustrates a textbook example. Of course, in real deadlocks, the lock
acquisitions may be separated by deeply nested call chains.
```java
public void lockAThenB() {
synchronized(lockA) {
synchronized(lockB) {
// do something with both resources
}
}
}
public void lockBThenA() {
synchronized(lockB) {
synchronized(lockA) {
// do something with both resources
}
}
}
```
The standard solution to a deadlock is to fix an order of lock acquisition and
adhere to that order in all cases. Another solution may be to shrink the
critical sections (i.e., the code executing under lock) to the minimum required.
Old-style containers such as `Vector` are synchronized on the object monitor,
which means that deadlocks can occur even without explicit synchronisation on
both threads. For instance:
```java
public void lockAThenAddToVector() {
synchronized(lockA) {
vector.add(object);
}
}
public void lockVectorThenA() {
synchronized(vector) {
synchronized(lockA) {
// do something with both resources
}
}
}
```
Infer has support for detecting these deadlocks too.
To suppress reports of deadlocks in a method `m()` use the
`@SuppressLint("DEADLOCK")` annotation, as follows:
```java
import android.annotation.SuppressLint;
@SuppressLint("DEADLOCK")
public void m() {
...
}
```

@ -0,0 +1,2 @@
This error is reported in C++. It fires when the value assigned to a variables
is never used (e.g., `int i = 1; i = 2; return i;`).

@ -0,0 +1,5 @@
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.

@ -0,0 +1,64 @@
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.

@ -0,0 +1,12 @@
This error type is reported only in C++, in versions >= C++11.
The code is trying to access an element of a vector that Infer believes to be
empty. Such an access will cause undefined behavior at runtime.
```c++
#include <vector>
int foo(){
const std::vector<int> vec;
return vec[0]; // Empty vector access reported here
}
```

@ -0,0 +1,22 @@
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.

@ -0,0 +1,17 @@
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.

@ -0,0 +1,20 @@
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.

@ -0,0 +1,40 @@
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);
}
}
```

@ -0,0 +1,39 @@
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);
}
}
```

@ -0,0 +1,22 @@
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.

@ -0,0 +1,18 @@
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.

@ -0,0 +1,20 @@
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.

@ -0,0 +1,4 @@
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.

@ -0,0 +1,6 @@
This error indicates that you have invoked an interface method not annotated
with `@ThreadSafe` from a thread-safe context (e.g., code that uses locks or is
marked `@ThreadSafe`). The fix is to add the `@ThreadSafe` annotation to the
interface or to the interface method. For background on why these annotations
are needed, see the detailed explanation
[here](racerd#interface-not-thread-safe).

@ -0,0 +1,14 @@
This error type is only reported in Objective-C. This is similar to Null
dereference, but Infer hasn't found a whole trace where the error can happen,
but only found that a null dereference can happen if an instance variable of a
parameter is `nil`. For example:
```objectivec
-(int) foo {
B b* = [self->_a foo]; // sending a message with receiver nil returns nil
return b->x; // dereferencing b, potential NPE if you pass nil as the argument a.
}
```
Possible solutions are adding a check for `nil`, or making sure that the method
is not called with `nil`.

@ -0,0 +1,20 @@
This is a C++ and Objective C error reported whenever:
- A class contains a member `lock` used for synchronization (most often a
`std::mutex`).
- It has a public method which writes to some member `x` while holding `lock`.
- It has a public method which reads `x` without holding `lock`.
The above may happen through a chain of calls. Above, `x` may also be a
container (an array, a vector, etc).
### Fixing Lock Consistency Violation reports
- Avoid the offending access (most often the read). Of course, this may not be
possible.
- Use synchronization to protect the read, by using the same lock protecting the
corresponding write.
- Make the method doing the read access private. This should silence the
warning, since Infer looks for a pair of non-private methods. Objective-C:
Infer considers a method as private if it's not exported in the header-file
interface.

@ -0,0 +1,24 @@
### Memory leak in C
This error type is only reported in C and Objective-C code. In Java we do not
report memory leaks because it is a garbage collected language.
In C, Infer reports memory leaks when objects are created with `malloc` and not
freed. For example:
```c
-(void) memory_leak_bug {
struct Person *p = malloc(sizeof(struct Person));
}
```
### Memory leak in Objective-C
Additionally, in Objective-C, Infer reports memory leaks that happen when
objects from Core Foundation or Core Graphics don't get released.
```objectivec
-(void) memory_leak_bug_cf {
CGPathRef shadowPath = CGPathCreateWithRect(self.inputView.bounds, NULL); //object created and not released.
}
```

@ -0,0 +1,4 @@
This happens when an Objective-C block captures both `self` and `weakSelf`, a
weak pointer to `self`. Possibly the developer meant to capture only `weakSelf`
to avoid a retain cycle, but made a typo and used `self` as well in the block,
instead of `strongSelf`. In this case, this could cause a retain cycle.

@ -0,0 +1,5 @@
An Objective-C block uses `weakSelf` more than once. This could lead to
unexpected behaviour. Even if `weakSelf` is not nil in the first use, it could
be nil in the following uses since the object that `weakSelf` points to could be
freed anytime. One should assign it to a strong pointer first, and then use it
in the block.

@ -0,0 +1 @@
[Doc in ComponentKit page](http://componentkit.org/docs/avoid-local-variables)

@ -0,0 +1,24 @@
This error type is reported only in Objective-C. It is similar to Null
dereference, but Infer hasn't found a whole trace where the error can happen,
but only found that a null dereference can happen if you call a method with nil
as an argument. Therefore it is only a warning. For example:
```objectivec
-(int) foo:(A* a) {
B b* = [a foo]; // sending a message with receiver nil returns nil
return b->x; // dereferencing b, potential NPE if you pass nil as the argument a.
}
```
or when the parameter is a block:
```objectivec
-(void) foo:(void (^)(BOOL))block {
block(YES); // calling a nil block will cause a crash.
}
```
Possible solutions are adding a check for `nil`, or making sure that the method
is not called with `nil`. When an argument will never be `nil`, you can add the
annotation `nonnull` to the argument's type, to tell Infer (and the type
system), that the argument won't be `nil`. This will silence the warning.

@ -0,0 +1,4 @@
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.

@ -0,0 +1,15 @@
This error type is reported in C and Objective-C. In many variadic methods,
`nil` is used to signify the end of the list of input objects. This is similar
to nil-termination of C strings. If one of the arguments that is not the last
argument to the method is `nil` as well, Infer reports an error because that may
lead to unexpected behavior.
An example of such variadic methods is
[arrayWithObjects](https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/index.html#//apple_ref/occ/clm/NSArray/arrayWithObjects)
```objectivec
NSArray *foo = [NSArray arrayWithObjects: @"aaa", str, @"bbb", nil];
```
In this example, if `str` is `nil` then an array `@[@"aaa"]` of size 1 will be
created, and not an array `@[@"aaa", str, @"bbb"]` of size 3 as expected.

@ -0,0 +1,5 @@
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.

@ -0,0 +1,273 @@
Infer reports resource leaks in C, Objective-C and Java. In general, resources
are entities such as files, sockets, connections, etc, that need to be closed
after being used.
### Resource leak in C
This is an example of a resource leak in C code:
```c
-(void) resource_leak_bug {
FILE *fp;
fp=fopen("c:\\test.txt", "r"); // file opened and not closed.
}
```
### Resource leak in Java
For the remaining of this section, we will consider examples of resource leaks
in Java code.
TIP: A common source of bugs is <b>exceptions skipping past close()
statements</b>. That is the first thing to look for if INFER reports a potential
resource leak.
### Basics and Standard Idiom
Some objects in Java, the <i>resources</i>, are supposed to be closed when you
stop using them, and failure to close is a <i>resource leak</i>. Resources
include input streams, output streams, readers, writers, sockets, http
connections, cursors, and json parsers.
The standard idiom is
```java
// Standard idiom
Allocate resource
try {
do some stuff
} finally {
close resource
}
```
or more for example,
```java
// Standard Idiom
public static void foo () throws IOException{
FileOutputStream fos = new FileOutputStream(new File("whatever.txt"));
try {
fos.write(7);
} finally {
fos.close();
}
}
```
and you should use the standard idiom for the most part, when you don't want to
return the resource to the surrounding context.
Sometimes people just leave out close(), and that is a bug, but more typically
exceptional paths are the root of the problem, as in
```java
// leak because of exception
public static void foo () throws IOException {
FileOutputStream fos = new FileOutputStream(new File("whatever.txt"));
fos.write(7); //DOH! What if exception?
fos.close();
}
```
where an exception in fos.write will cause execution to skip past the close()
statement.
#### Multiple Resources Bugs
We can deal with multiple resources correctly and simply just by nesting the
standard idiom.
```java
// Two Resources nested
public static void foo() throws IOException {
FileInputStream fis = new FileInputStream(new File("whatever.txt"));
try {
FileOutputStream fos = new FileOutputStream(new File("everwhat.txt"));
try {
fos.write(fis.read());
} finally {
fos.close();
}
} finally {
fis.close();
}
}
```
Bugs often occur when using multiple resources in other ways because of
exceptions in close() methods. For example,
```java
// Classic Two Resources Bug
public static void foo() throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(new File("whatever.txt"));
fos = new FileOutputStream(new File("everwhat.txt"));
fos.write(fis.read());
} finally {
if (fis!=null) fis.close();
if (fos!=null) fos.close();
}
}
```
Here, if there is an exception in the call to fis.close() execution will skip
past fos.close(); a leak.
Another way, besides the standard idiom, to deal with this problem is to swallow
exceptions.
```java
// Two Resources Fix 1
public static void foo() throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(new File("whatever.txt"));
fos = new FileOutputStream(new File("everwhat.txt"));
fos.write(fis.read());
} finally {
try {
if (fis!=null) fis.close();
} catch (Exception e) {}; // Exception swallowing
if (fos!=null) fos.close();
}
}
```
You can also swallow the exception on the output stream. Some people prefer not
to swallow output stream exceptions, and also flush before closing.
http://code.google.com/p/guava-libraries/issues/detail?id=1118
Notice that the nested standard idiom does not need the checks for null, which
are in there in this case to protect against the case when one of the
allocations throws an exception, in which case one would get a
NullPointerException.
### Nested_Allocations
When a resource allocation is included as an argument to a constructor, if the
constructor fails it can leave an an unreachable resource that no one can close.
For example gzipOutputStream = new GZIPOutputStream(new FileOutputStream(out));
is bad in case the outer constructor, GZIPOutputStream, throws an exception. In
that case, no one will have a hold of the FileOutputStream and so no one will be
able to close it.
In such a case you need to move the allocation the FileOutputStream out of the
nested position and name it, so you are able to close if anything goes wrong
during execution of the GZIPOutputStream constructor.
Here are resources that can throw exceptions i their constructor(s).
- ObjectInputStream , ObjectOutputStream, PipedInputStream, PipedOutputStream,
PipedReader, PipedWriter, JarInputStream, JarOutputStream, GZIPInputStream,
GZIPOutputStream , ZipFile all throw IOException
- PrintStream throws UnsupportedEncodingException
The constructors for FileInputStream, FileOutputStream and RandomAccessFile
throw FileNotFoundException, but these cases are not problematic in the sense
that their arguments are not resources and so they do not cause the nested
resource leak.
### Allocation of JSonParser and Cursor resources
Some resources are created inside libraries instead of by "new".
Cursor is an interface, the actual resources are something like SQLiteCursor.
So, every time you call a function that returns a Cursor object, there is an
allocation.
For instance, in the functions from SQLiteDatabase query(…) and rawQuery(…)
allocate a cursor resource. For SQLiteQueryBuilder, ContentProviderClient,
ContentResolver. MediaStore and DownloadManager it is only query(…) Cursor
objects cursor created by these functions need to be closed (i.e.,
cursor.close()).
Similarly, JsonParser is an abstract class, and create a resource in functions
from the class JsonFactory createParser(byte[] data) createParser(byte[] data,
int offset, int len) createParser(String content) createParser(URL url)
createParser(File f) JsonParser objects js created by these functions need to be
closed (jp.close()). On the other hand . JasonParsers gotten from
createParser(InputStream in) and createParser(Reader r) give you JsonParsers
that dont need to be closed. This is because they receive the resource from
somewhere that will maintain the responsibility to close it.
### Escaping resources and exceptions
Sometimes you want to return a resource to the outside, in which case you should
not close it, but you still need to be careful of exceptions in case control
skips past the return leaving no one to close. Here is a simple example of a
positive use of escaping resources.
```java
// An escaping resource, shouldn't close
public BugReportAttachment createAttachment(File reportDirectory, String fileName)
throws FileNotFoundException {
File file = new File(reportDirectory, fileName);
OutputStream stream = new FileOutputStream(file);
return new BugReportAttachment(Uri.fromFile(file), stream);
}
```
In this case it is intended that an object that wraps `stream` is passed to the
caller of `createAttachment`. You should certainly not close stream here,
because it is being passed to the outside.
But for escaping resources like this you still need to be careful of exceptions.
For example, in
```java
// An escaping resource, and a leak
public BugReportAttachment createAttachment(File reportDirectory, String fileName)
throws FileNotFoundException {
File file = new File(reportDirectory, fileName);
OutputStream stream = new FileOutputStream(file);
stream.write(7);
return new BugReportAttachment(Uri.fromFile(file), stream);
}
```
if stream.write(7) throws an exception, then no one will have a hold of stream,
and no one will be able to close it; a leak.
### Java 7's try-with-resources
**(For use with Java 7 only)**
Clearly, accounting for the ramifications of all the exceptional cases is
complicated, and there is a better way in Java 7.
```java
// Two Resources Fix 2; via try-with-resources
public static void foo() throws IOException {
try (
FileInputStream fis = new FileInputStream(new File("whatever.txt"));
FileOutputStream fos = new FileOutputStream(new File("everwhat.txt"))
) {
fos.write(fis.read());
}
}
```
All the complicated exceptional cases above are (apparently) covered by this
construct, and the result is much simpler.
So, if you are trying to fix a potential leak in code with multiples resources
you can go ahead and try to understand whether the potential leak is real. Or,
if the code is complex and it is hard to figure out, it would be perfectly
legitimate to simply convert the code over to try-with-resources if you have
access to Java 7, so as to save yourself some brain-cycles. You will also end up
with cleaner code.
If try-with-resources is so great you should <i>always</i> use it. But you
shouldn't… Try-with-resources gives resources static scoping, and works via a
stack discipline. Sometimes, you want a resource to persist beyond scope, as in
the escaping example above. In an escaping example maybe you could refactor lots
of code so that try-with-resources applies, and maybe you cannot in a sensible
way. This just illustrates that, though you might hear people say that
try-with-resources "solves" the resource problem, it does not. It is very
useful, but you cannot use it blindly when you see a resource-allocation site.

@ -0,0 +1,30 @@
A retain cycle is a situation when object A retains object B, and object B
retains object A at the same time. Here is an example:
```objectivec
@class Child;
@interface Parent : NSObject {
Child *child; // Instance variables are implicitly __strong
}
@end
@interface Child : NSObject {
Parent *parent;
}
@end
```
You can fix a retain cycle in ARC by using \_\_weak variables or weak properties
for your "back links", i.e. links to direct or indirect parents in an object
hierarchy:
```objectivec
@class Child;
@interface Parent : NSObject {
Child *child;
}
@end
@interface Child : NSObject {
__weak Parent *parent;
}
@end
```

@ -0,0 +1,55 @@
This error is reported in Java, and specifically on Android. These reports are
triggered when a method that runs on the UI thread may block, thus potentially
leading to an Application Not Responding error.
Infer considers a method as running on the UI thread whenever:
- The method, one of its overrides, its class, or an ancestral class, is
annotated with `@UiThread`.
- The method, or one of its overrides is annotated with `@OnEvent`, `@OnClick`,
etc.
- The method or its callees call a `Litho.ThreadUtils` method such as
`assertMainThread`.
The issue is reported when a method deemed to run on the UI thread
- Makes a method call which may block.
- Takes a lock, and another thread takes the same lock, and before releasing it,
makes a call that may block.
Calls that may block are considered:
- Certain I/O calls.
- Two way `Binder.transact` calls.
- Certain OS calls.
- `Future` or `AsyncTask` calls to `get` without timeouts, or with too large
timeouts.
To suppress starvation reports in a method `m()` use the
`@SuppressLint("STARVATION")` annotation, as follows:
```java
import android.annotation.SuppressLint;
@SuppressLint("STARVATION")
public void m() {
...
}
```
To signal to Infer that a method does not perform any blocking calls, despite
appearences, you can use the `@NonBlocking` annotation:
```java
import com.facebook.infer.annotation.NonBlocking;
@NonBlocking
public void m() {
...
}
```
This instructs Infer to filter out any potentially blocking calls in `m()`
(also, transitively), and thus any other method can expect no starvation reports
due to a call to `m()`. You will need to set up your class path appropriately to
include the JAR files in `infer/annotations` for this annotation to work.

@ -0,0 +1,9 @@
Android has a feature called
[strict mode](https://developer.android.com/reference/android/os/StrictMode),
which if enabled, will flag the occasions where the main thread makes a call
that results in disk I/O, waiting on a network socket, etc. The analysis
catching starvation errors and deadlocks (the `--starvation` analysis) has the
ability to statically detect such violations.
To suppress this warning, it's enough to annotate the offending method with
`@SuppressLint("STRICT_MODE_VIOLATION")`.

@ -0,0 +1,3 @@
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.

@ -0,0 +1,12 @@
When a block captures `weakSelf` in the following pattern:
```
__weak __typeof(self) weakSelf = self;
int (^my_block)() = ^() {
__strong __typeof(weakSelf) strongSelf = weakSelf;
int y = strongSelf->x;
```
the variable `strongSelf` should be checked for `null` before being used,
otherwise this could cause a crash because the weak pointer `weakSelf` could be
`null`.

@ -0,0 +1,94 @@
This warning indicates a potential data race in Java. The analyser is called
RacerD and this section gives brief but a mostly complete description of its
features. See the [RacerD page](/docs/racerd) for more in-depth information and
examples.
NB this warning **is not related to @GuardedBy** and not issued by the same
analysis.
### Thread-safety: What is a data race
Here a data race is a pair of accesses to the same member field such that:
- at least one is a write, and,
- at least one occurs without any lock synchronization, and,
- the two accesses occur on threads (if known) which can run in parallel.
### Thread-safety: Potential fixes
- Synchronizing the accesses (using the `synchronized` keyword, thread-exclusion
such as atomic objects, `volatile` etc).
- Making an offending method private -- this will exclude it from being checked
at the top level, though it will be checked if called by a public method which
may itself, e.g., hold a lock when calling it.
- Putting the two accesses on the same thread, e.g., by using `@MainThread` or
`@ThreadConfined`.
### Thread-safety: Conditions checked before reporting
The class and method are not marked `@ThreadSafe(enableChecks = false)`, and,
- The method is declared `synchronized`, or employs (non-transitively) locking,
or,
- The class is not marked `@NotThreadSafe`, and,
- The class/method is marked `@ThreadSafe,` or one of the configured synonyms
in `.inferconfig`, or,
- A parent class, or an override method are marked with the above annotations.
NB currently RacerD **does not take into account `@GuardedBy`**.
### Thread-safety: Thread annotations recognized by RacerD
These class and method annotations imply the method is on the main thread:
`@MainThread`, `@UiThread`
These method annotations imply the method is on the main thread: `@OnBind`,
`@OnEvent`, `@OnMount`, `@OnUnbind`, `@OnUnmount`
Both classes of annotations work through the inheritance tree (i.e. if a parent
class or method is marked with one of these annotations, so is the child class /
method override).
In addition to these, RacerD recognizes many lifecycle methods as necessarily
running on the main thread, eg `Fragment.onCreate` etc.
Finally, the thread status of being on the main thread propagates backwards
through the call graph (ie if `foo` calls `bar` and `bar` is marked `@UiThtread`
then `foo` is automatically considered on the main thread too). Calling
`assertMainThread`, `assertOnUiThread`, `checkOnMainThread` has the same effect.
NB RacerD currently **does not recognize `@WorkerThread`, `@BinderThread` or
`@AnyThread`**.
### Thread-safety: Other annotations and what they do
These annotations can be found at `com.facebook.infer.annotation.*`.
- `@Functional` This is a method annotation indicating the method always returns
the same value. When a method `foo` is annotated `@Functional`, RacerD will
ignore any writes of the return value of `foo`. For example, in
`this.x = foo()`, the write to `this.x` is ignored. The reasoning is that if
the method returns the same value whenever it's called, any data race on
`this.x` is benign, if that is the only write.
- `@ThreadConfined` This is a class/method/field annotation which takes a single
parameter which can be `UI`, `ANY` or a user chosen string. It indicates to
RacerD a thread identifier for the class/method/field. Thus,
`@ThreadConfined(UI)` is equivalent to `@UiThread`, and `@ThreadConfined(ANY)`
is equivalent to not having the annotation at all, for classes and methods.
When this annotation is applied to a field it instructs Infer to assume
(without checking) that all accesses to that field are made on the same thread
(and can, therefore, not race by definition). The intention is that RacerD
uses that to detect exclusion between accesses occurring on the same thread.
However, only the UI thread is supported at this time, and any user provided
value is considered equal to `UI`.
- `@VisibleForTesting` A method annotation making Infer consider the method as
effectively `private`. This means it will not be checked for races against
other non-private methods of the class, but only if called by one.
- `@ReturnsOwnership` A method annotation indicating that the method returns a
freshly owned object. Accesses to the returned value will not be considered
for data races, as the object is in-effect unique and not accessible yet from
other threads. The main utility of this annotation is in interfaces, where
Infer cannot look up the implementation and decide for itself.

@ -0,0 +1,20 @@
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];
}
```

@ -0,0 +1,4 @@
In many methods that take a block as an argument, the block position is
annotated with NS_NOESCAPE to mark that the block passed to this method won't be
leaving the current scope. In those cases, there is no need to use `weakSelf` to
avoid the block to capture `self`. This issue type flags this case.

@ -7,124 +7,124 @@
// a property declared atomic should not be accessed directly via its ivar
DEFINE-CHECKER DIRECT_ATOMIC_PROPERTY_ACCESS = {
SET report_when =
WHEN
((NOT context_in_synchronized_block()) AND is_ivar_atomic())
AND NOT is_method_property_accessor_of_ivar()
AND NOT is_objc_constructor()
AND NOT is_objc_dealloc()
HOLDS-IN-NODE ObjCIvarRefExpr;
SET message = "Direct access to ivar %ivar_name% of an atomic property";
SET suggestion = "Accessing an ivar of an atomic property makes the property nonatomic.";
SET severity = "WARNING";
SET report_when =
WHEN
((NOT context_in_synchronized_block()) AND is_ivar_atomic())
AND NOT is_method_property_accessor_of_ivar()
AND NOT is_objc_constructor()
AND NOT is_objc_dealloc()
HOLDS-IN-NODE ObjCIvarRefExpr;
SET message = "Direct access to ivar %ivar_name% of an atomic property";
SET suggestion = "Accessing an ivar of an atomic property makes the property nonatomic.";
SET severity = "WARNING";
};
// ASSIGN_POINTER_WARNING:
// a property with a pointer type should not be declared `assign`
DEFINE-CHECKER ASSIGN_POINTER_WARNING = {
SET report_when =
WHEN
is_assign_property() AND is_property_pointer_type()
SET report_when =
WHEN
is_assign_property() AND is_property_pointer_type()
HOLDS-IN-NODE ObjCPropertyDecl;
SET message = "Property %decl_name% is a pointer type marked with the `assign` attribute";
SET suggestion = "Use a different attribute like `strong` or `weak`.";
SET severity = "WARNING";
SET message = "Property %decl_name% is a pointer type marked with the `assign` attribute";
SET suggestion = "Use a different attribute like `strong` or `weak`.";
SET severity = "WARNING";
};
// BAD_POINTER_COMPARISON:
// Fires whenever a NSNumber is dangerously coerced to a boolean in a comparison
DEFINE-CHECKER BAD_POINTER_COMPARISON = {
LET bool_op =
is_binop_with_kind("LAnd") OR is_binop_with_kind("LOr")
OR is_unop_with_kind("LNot") OR is_unop_with_kind("LNot");
LET bool_op =
is_binop_with_kind("LAnd") OR is_binop_with_kind("LOr")
OR is_unop_with_kind("LNot") OR is_unop_with_kind("LNot");
LET comparison_with_integral =
( is_binop_with_kind("EQ") OR is_binop_with_kind("NE")
OR is_binop_with_kind("GT") OR is_binop_with_kind("GE")
OR is_binop_with_kind("LT") OR is_binop_with_kind("LE"))
AND
( (is_node("ImplicitCastExpr") AND has_type("NSNumber *")
AND has_cast_kind("IntegralToPointer")
) HOLDS-NEXT);
( is_binop_with_kind("EQ") OR is_binop_with_kind("NE")
OR is_binop_with_kind("GT") OR is_binop_with_kind("GE")
OR is_binop_with_kind("LT") OR is_binop_with_kind("LE"))
AND
( (is_node("ImplicitCastExpr") AND has_type("NSNumber *")
AND has_cast_kind("IntegralToPointer")
) HOLDS-NEXT);
LET root_is_stmt_expecting_bool =
is_node("IfStmt") OR is_node("ForStmt") OR is_node("WhileStmt");
LET root_is_stmt_expecting_bool =
is_node("IfStmt") OR is_node("ForStmt") OR is_node("WhileStmt");
LET use_num_as_bool =
(bool_op OR root_is_stmt_expecting_bool) AND (has_type("NSNumber *") HOLDS-NEXT);
LET use_num_as_bool =
(bool_op OR root_is_stmt_expecting_bool) AND (has_type("NSNumber *") HOLDS-NEXT);
LET bad_conditional =
is_node("ConditionalOperator") AND (has_type("NSNumber *") HOLDS-NEXT WITH-TRANSITION Cond);
LET bad_conditional =
is_node("ConditionalOperator") AND (has_type("NSNumber *") HOLDS-NEXT WITH-TRANSITION Cond);
SET report_when =
use_num_as_bool OR comparison_with_integral OR bad_conditional;
SET report_when =
use_num_as_bool OR comparison_with_integral OR bad_conditional;
SET message = "Implicitly checking whether NSNumber pointer is nil or comparing to integral value";
SET suggestion =
"Did you mean to use/compare against the unboxed value instead? Please either explicitly compare the NSNumber instance to nil, or use one of the NSNumber accessors before the comparison.";
SET suggestion =
"Did you mean to use/compare against the unboxed value instead? Please either explicitly compare the NSNumber instance to nil, or use one of the NSNumber accessors before the comparison.";
};
DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = {
LET exists_method_calling_addObserver =
call_method("addObserver:selector:name:object:") HOLDS-EVENTUALLY;
LET exists_method_calling_addObserver =
call_method("addObserver:selector:name:object:") HOLDS-EVENTUALLY;
LET exists_method_calling_addObserverForName =
call_method("addObserverForName:object:queue:usingBlock:") HOLDS-EVENTUALLY;
LET exists_method_calling_addObserverForName =
call_method("addObserverForName:object:queue:usingBlock:") HOLDS-EVENTUALLY;
LET add_observer =
exists_method_calling_addObserver OR exists_method_calling_addObserverForName;
LET add_observer =
exists_method_calling_addObserver OR exists_method_calling_addObserverForName;
LET eventually_addObserver =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(add_observer)
HOLDS-EVENTUALLY;
LET eventually_addObserver =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(add_observer)
HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserver =
call_method("removeObserver:") HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserver =
call_method("removeObserver:") HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserverName =
call_method("removeObserver:name:object:") HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserverName =
call_method("removeObserver:name:object:") HOLDS-EVENTUALLY;
LET remove_observer =
exists_method_calling_removeObserver OR exists_method_calling_removeObserverName;
LET remove_observer =
exists_method_calling_removeObserver OR exists_method_calling_removeObserverName;
LET remove_observer_in_block =
IN-NODE BlockDecl WITH-TRANSITION Body
(remove_observer)
HOLDS-EVENTUALLY;
LET remove_observer_in_block =
IN-NODE BlockDecl WITH-TRANSITION Body
(remove_observer)
HOLDS-EVENTUALLY;
LET remove_observer1 =
remove_observer OR remove_observer_in_block;
LET remove_observer1 =
remove_observer OR remove_observer_in_block;
LET remove_observer_in_method =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(remove_observer1)
HOLDS-EVENTUALLY;
LET remove_observer_in_method =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(remove_observer1)
HOLDS-EVENTUALLY;
LET eventually_removeObserver =
IN-NODE ObjCImplementationDecl, ObjCProtocolDecl WITH-TRANSITION Any
(remove_observer_in_method OR
remove_observer_in_method HOLDS-IN-SOME-SUPERCLASS-OF ObjCImplementationDecl)
HOLDS-EVENTUALLY;
LET eventually_removeObserver =
IN-NODE ObjCImplementationDecl, ObjCProtocolDecl WITH-TRANSITION Any
(remove_observer_in_method OR
remove_observer_in_method HOLDS-IN-SOME-SUPERCLASS-OF ObjCImplementationDecl)
HOLDS-EVENTUALLY;
SET report_when =
WHEN
NOT (eventually_addObserver IMPLIES eventually_removeObserver) AND
NOT iphoneos_target_sdk_version_greater_or_equal("9.0") //this is not needed after iOS SDK 9.0
HOLDS-IN-NODE ObjCImplementationDecl, ObjCProtocolDecl;
SET report_when =
WHEN
NOT (eventually_addObserver IMPLIES eventually_removeObserver) AND
NOT iphoneos_target_sdk_version_greater_or_equal("9.0") //this is not needed after iOS SDK 9.0
HOLDS-IN-NODE ObjCImplementationDecl, ObjCProtocolDecl;
SET message =
"Object self is registered in a notification center but not being removed before deallocation";
SET message =
"Object self is registered in a notification center but not being removed before deallocation";
SET suggestion =
"Consider removing the object from the notification center before its deallocation.";
SET suggestion =
"Consider removing the object from the notification center before its deallocation.";
};
@ -132,14 +132,14 @@ DEFINE-CHECKER STRONG_DELEGATE_WARNING = {
LET name_contains_delegate = declaration_has_name(REGEXP("[dD]elegate"));
LET name_does_not_contain_delegates =
NOT declaration_has_name(REGEXP("[dD]elegates"));
NOT declaration_has_name(REGEXP("[dD]elegates"));
LET name_does_not_contains_queue =
NOT declaration_has_name(REGEXP("[qQ]ueue"));
NOT declaration_has_name(REGEXP("[qQ]ueue"));
SET report_when =
WHEN
name_contains_delegate AND name_does_not_contain_delegates AND name_does_not_contains_queue AND is_strong_property()
HOLDS-IN-NODE ObjCPropertyDecl;
WHEN
name_contains_delegate AND name_does_not_contain_delegates AND name_does_not_contains_queue AND is_strong_property()
HOLDS-IN-NODE ObjCPropertyDecl;
SET message = "Property or ivar %decl_name% declared strong";
SET suggestion = "In general delegates should be declared weak or assign.";
@ -151,22 +151,22 @@ DEFINE-CHECKER GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL = {
LET is_global_but_not_const_variable =
is_objc_extension() AND is_global_var() AND (NOT is_const_expr_var()) AND (NOT is_init_integral_constant_expr());
LET makes_an_expensive_call =
(is_node("CallExpr") AND NOT call_function("CGPointMake"))
OR is_node("CXXTemporaryObjectExpr")
LET makes_an_expensive_call =
(is_node("CallExpr") AND NOT call_function("CGPointMake"))
OR is_node("CXXTemporaryObjectExpr")
OR is_node("CXXMemberCallExpr")
OR is_node("CXXOperatorCallExpr")
OR is_node("ObjCMessageExpr");
LET is_initialized_with_expensive_call =
IN-NODE VarDecl WITH-TRANSITION InitExpr
(makes_an_expensive_call HOLDS-EVENTUALLY)
HOLDS-EVENTUALLY;
(makes_an_expensive_call HOLDS-EVENTUALLY)
HOLDS-EVENTUALLY;
SET report_when =
WHEN
(is_global_but_not_const_variable AND is_initialized_with_expensive_call)
HOLDS-IN-NODE VarDecl;
WHEN
(is_global_but_not_const_variable AND is_initialized_with_expensive_call)
HOLDS-IN-NODE VarDecl;
SET message =
"Global variable %decl_name% is initialized using a function or method call";
@ -177,75 +177,75 @@ DEFINE-CHECKER GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL = {
DEFINE-CHECKER CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK = {
// The current node is block definition capturing a C++ reference
LET capture_reference =
WHEN
((is_node("BlockDecl") AND captures_cxx_references()) HOLDS-NEXT)
HOLDS-IN-NODE BlockExpr;
// The current node is block definition capturing a C++ reference
LET capture_reference =
WHEN
((is_node("BlockDecl") AND captures_cxx_references()) HOLDS-NEXT)
HOLDS-IN-NODE BlockExpr;
// At some point we encounter a block definition capturing a C++ reference
LET block_definition_capture_reference =
capture_reference HOLDS-EVENTUALLY;
// At some point we encounter a block definition capturing a C++ reference
LET block_definition_capture_reference =
capture_reference HOLDS-EVENTUALLY;
// A variable definition initialized with a block capturing a C++ reference
LET variable_initialized_with_block =
IN-NODE VarDecl WITH-TRANSITION InitExpr
(block_definition_capture_reference)
HOLDS-EVENTUALLY;
// A variable definition initialized with a block capturing a C++ reference
LET variable_initialized_with_block =
IN-NODE VarDecl WITH-TRANSITION InitExpr
(block_definition_capture_reference)
HOLDS-EVENTUALLY;
// Reference to a variable initialized with a capturing block
LET variable_block_definition =
IN-NODE DeclRefExpr WITH-TRANSITION PointerToDecl
(variable_initialized_with_block)
HOLDS-EVENTUALLY;
// Reference to a variable initialized with a capturing block
LET variable_block_definition =
IN-NODE DeclRefExpr WITH-TRANSITION PointerToDecl
(variable_initialized_with_block)
HOLDS-EVENTUALLY;
// Report when a function that does not have NoEscapeAttribute call a block or a variable definied with
// a block capturing a C++ ref
SET report_when =
WHEN
(NOT has_no_escape_attribute) AND (block_definition_capture_reference OR variable_block_definition)
HOLDS-IN-NODE CallExpr;
// Report when a function that does not have NoEscapeAttribute call a block or a variable definied with
// a block capturing a C++ ref
SET report_when =
WHEN
(NOT has_no_escape_attribute) AND (block_definition_capture_reference OR variable_block_definition)
HOLDS-IN-NODE CallExpr;
SET message =
"C++ Reference variable(s) %cxx_ref_captured_in_block% captured by Objective-C block";
SET message =
"C++ Reference variable(s) %cxx_ref_captured_in_block% captured by Objective-C block";
SET suggestion = "This will very likely cause a crash because C++ References are unmanaged and may be invalid by the time the block executes.";
SET suggestion = "This will very likely cause a crash because C++ References are unmanaged and may be invalid by the time the block executes.";
SET severity = "ERROR";
SET mode = "ON";
};
SET mode = "ON";
};
// If the declaration has availability attributes, check that it's compatible with
// the iphoneos_target_sdk_version
DEFINE-CHECKER UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK = {
// If the declaration has availability attributes, check that it's compatible with
// the iphoneos_target_sdk_version
DEFINE-CHECKER UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK = {
SET report_when =
WHEN HOLDS-NEXT WITH-TRANSITION PointerToDecl
(decl_unavailable_in_supported_ios_sdk() AND
NOT within_responds_to_selector_block())
HOLDS-IN-NODE DeclRefExpr, ObjCMessageExpr;
SET report_when =
WHEN HOLDS-NEXT WITH-TRANSITION PointerToDecl
(decl_unavailable_in_supported_ios_sdk() AND
NOT within_responds_to_selector_block())
HOLDS-IN-NODE DeclRefExpr, ObjCMessageExpr;
SET message =
"%decl_ref_or_selector_name% is not available in the required iOS SDK version %iphoneos_target_sdk_version% (only available from version %available_ios_sdk%)";
SET message =
"%decl_ref_or_selector_name% is not available in the required iOS SDK version %iphoneos_target_sdk_version% (only available from version %available_ios_sdk%)";
SET name = "Unavailable API In Supported iOS SDK";
SET suggestion = "This could cause a crash.";
SET severity = "ERROR";
};
DEFINE-CHECKER UNAVAILABLE_CLASS_IN_SUPPORTED_IOS_SDK = {
SET report_when =
WHEN ((class_unavailable_in_supported_ios_sdk()) AND
NOT within_available_class_block() AND
(call_class_method("alloc") OR
call_class_method("new")))
HOLDS-IN-NODE ObjCMessageExpr;
SET message =
"The receiver %receiver_method_call% of %name% is not available in the required iOS SDK version %iphoneos_target_sdk_version% (only available from version %class_available_ios_sdk%)";
SET name = "Unavailable API In Supported iOS SDK";
SET severity = "ERROR";
SET mode = "ON";
};
SET suggestion = "This could cause a crash.";
SET severity = "ERROR";
};
DEFINE-CHECKER UNAVAILABLE_CLASS_IN_SUPPORTED_IOS_SDK = {
SET report_when =
WHEN ((class_unavailable_in_supported_ios_sdk()) AND
NOT within_available_class_block() AND
(call_class_method("alloc") OR
call_class_method("new")))
HOLDS-IN-NODE ObjCMessageExpr;
SET message =
"The receiver %receiver_method_call% of %name% is not available in the required iOS SDK version %iphoneos_target_sdk_version% (only available from version %class_available_ios_sdk%)";
SET name = "Unavailable API In Supported iOS SDK";
SET severity = "ERROR";
SET mode = "ON";
};
DEFINE-CHECKER POINTER_TO_INTEGRAL_IMPLICIT_CAST = {
@ -253,7 +253,7 @@ DEFINE-CHECKER POINTER_TO_INTEGRAL_IMPLICIT_CAST = {
WHEN has_cast_kind("PointerToIntegral")
HOLDS-IN-NODE ImplicitCastExpr;
SET message = "Implicit conversion from %child_type% to %type% in usage of %name%";
SET doc_url = "https://clang.llvm.org/docs/DiagnosticsReference.html#wint-conversion";
SET doc_url = "https://clang.llvm.org/docs/DiagnosticsReference.html#wint-conversion";
};
DEFINE-CHECKER POINTER_TO_CONST_OBJC_CLASS = {
@ -263,7 +263,7 @@ DEFINE-CHECKER POINTER_TO_CONST_OBJC_CLASS = {
it represents a mutable pointer pointing to an Objective-C
class where the ivars cannot be changed.";
SET suggestion = "Consider using `%class_name% *const` instead, meaning
the destination of the pointer cannot be changed.";
the destination of the pointer cannot be changed.";
SET severity = "WARNING";
SET mode = "ON";
};
@ -288,14 +288,14 @@ DEFINE-CHECKER DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER = {
DEFINE-CHECKER WRONG_SCOPE_FOR_DISPATCH_ONCE_T = {
SET report_when =
WHEN
NOT (is_global_var() OR is_static_local_var()) AND
has_type("dispatch_once_t")
HOLDS-IN-NODE VarDecl;
SET message = "Variables of type dispatch_once_t must have global or static scope. The result of using this type with automatic or dynamic allocation is undefined.";
SET severity = "WARNING";
SET mode = "ON";
WHEN
NOT (is_global_var() OR is_static_local_var()) AND
has_type("dispatch_once_t")
HOLDS-IN-NODE VarDecl;
SET message = "Variables of type dispatch_once_t must have global or static scope. The result of using this type with automatic or dynamic allocation is undefined.";
SET severity = "WARNING";
SET mode = "ON";
};
@ -309,8 +309,8 @@ DEFINE-CHECKER UNSAFE_CALL_TO_OPTIONAL_METHOD = {
HOLDS-IN-NODE ObjCMessageExpr;
SET message = "This is a call to an `@optional` protocol method. Calling it without checking if its implemented can lead to crashes at run time.";
SET suggestion = "Please make sure to test the method is implemented by first calling `if ([object respondsToSelector:@selector(%decl_name%)]) ...` ";
SET severity = "ERROR";
SET mode = "ON";
SET suggestion = "Please make sure to test the method is implemented by first calling `if ([object respondsToSelector:@selector(%decl_name%)]) ...` ";
SET severity = "ERROR";
SET mode = "ON";
};

@ -360,9 +360,11 @@ OPTIONS
ARRAY_OUT_OF_BOUNDS_L1 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L2 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L3 (disabled by default),
ASSIGN_POINTER_WARNING (enabled by default),
Abduction_case_not_implemented (enabled by default),
Array_of_pointsto (enabled by default),
Assert_failure (enabled by default),
BAD_POINTER_COMPARISON (enabled by default),
BIABDUCTION_ANALYSIS_STOPS (disabled by default),
BIABD_CONDITION_ALWAYS_FALSE (disabled by default),
BIABD_CONDITION_ALWAYS_TRUE (disabled by default),
@ -401,6 +403,7 @@ OPTIONS
CONSTANT_ADDRESS_DEREFERENCE (disabled by default),
CREATE_INTENT_FROM_URI (enabled by default),
CROSS_SITE_SCRIPTING (enabled by default),
CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK (enabled by default),
Cannot_star (enabled by default),
DANGLING_POINTER_DEREFERENCE (disabled by default),
DANGLING_POINTER_DEREFERENCE_MAYBE (disabled by default),
@ -409,6 +412,8 @@ OPTIONS
DEALLOCATE_STACK_VARIABLE (enabled by default),
DEALLOCATE_STATIC_MEMORY (enabled by default),
DEALLOCATION_MISMATCH (enabled by default),
DIRECT_ATOMIC_PROPERTY_ACCESS (enabled by default),
DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER (enabled by default),
DIVIDE_BY_ZERO (disabled by default),
DO_NOT_REPORT (enabled by default),
EMPTY_VECTOR_ACCESS (enabled by default),
@ -483,12 +488,14 @@ OPTIONS
NULL_TEST_AFTER_DEREFERENCE (disabled by default),
PARAMETER_NOT_NULL_CHECKED (enabled by default),
POINTER_SIZE_MISMATCH (enabled by default),
POINTER_TO_CONST_OBJC_CLASS (enabled by default),
PRECONDITION_NOT_FOUND (enabled by default),
PRECONDITION_NOT_MET (enabled by default),
PREMATURE_NIL_TERMINATION_ARGUMENT (enabled by default),
PULSE_MEMORY_LEAK (disabled by default),
PURE_FUNCTION (enabled by default),
QUANDARY_TAINT_ERROR (enabled by default),
REGISTERED_OBSERVER_BEING_DEALLOCATED (enabled by default),
RESOURCE_LEAK (enabled by default),
RETAIN_CYCLE (enabled by default),
SHELL_INJECTION (enabled by default),
@ -501,12 +508,14 @@ OPTIONS
STARVATION (enabled by default),
STATIC_INITIALIZATION_ORDER_FIASCO (enabled by default),
STRICT_MODE_VIOLATION (enabled by default),
STRONG_DELEGATE_WARNING (enabled by default),
STRONG_SELF_NOT_CHECKED (enabled by default),
Symexec_memory_error (enabled by default),
THREAD_SAFETY_VIOLATION (enabled by default),
TOPL_ERROR (enabled by default),
UNARY_MINUS_APPLIED_TO_UNSIGNED_EXPRESSION (disabled by
default),
UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK (enabled by default),
UNINITIALIZED_VALUE (enabled by default),
UNREACHABLE_CODE (enabled by default),
UNTRUSTED_BUFFER_ACCESS (disabled by default),

@ -84,9 +84,11 @@ OPTIONS
ARRAY_OUT_OF_BOUNDS_L1 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L2 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L3 (disabled by default),
ASSIGN_POINTER_WARNING (enabled by default),
Abduction_case_not_implemented (enabled by default),
Array_of_pointsto (enabled by default),
Assert_failure (enabled by default),
BAD_POINTER_COMPARISON (enabled by default),
BIABDUCTION_ANALYSIS_STOPS (disabled by default),
BIABD_CONDITION_ALWAYS_FALSE (disabled by default),
BIABD_CONDITION_ALWAYS_TRUE (disabled by default),
@ -125,6 +127,7 @@ OPTIONS
CONSTANT_ADDRESS_DEREFERENCE (disabled by default),
CREATE_INTENT_FROM_URI (enabled by default),
CROSS_SITE_SCRIPTING (enabled by default),
CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK (enabled by default),
Cannot_star (enabled by default),
DANGLING_POINTER_DEREFERENCE (disabled by default),
DANGLING_POINTER_DEREFERENCE_MAYBE (disabled by default),
@ -133,6 +136,8 @@ OPTIONS
DEALLOCATE_STACK_VARIABLE (enabled by default),
DEALLOCATE_STATIC_MEMORY (enabled by default),
DEALLOCATION_MISMATCH (enabled by default),
DIRECT_ATOMIC_PROPERTY_ACCESS (enabled by default),
DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER (enabled by default),
DIVIDE_BY_ZERO (disabled by default),
DO_NOT_REPORT (enabled by default),
EMPTY_VECTOR_ACCESS (enabled by default),
@ -207,12 +212,14 @@ OPTIONS
NULL_TEST_AFTER_DEREFERENCE (disabled by default),
PARAMETER_NOT_NULL_CHECKED (enabled by default),
POINTER_SIZE_MISMATCH (enabled by default),
POINTER_TO_CONST_OBJC_CLASS (enabled by default),
PRECONDITION_NOT_FOUND (enabled by default),
PRECONDITION_NOT_MET (enabled by default),
PREMATURE_NIL_TERMINATION_ARGUMENT (enabled by default),
PULSE_MEMORY_LEAK (disabled by default),
PURE_FUNCTION (enabled by default),
QUANDARY_TAINT_ERROR (enabled by default),
REGISTERED_OBSERVER_BEING_DEALLOCATED (enabled by default),
RESOURCE_LEAK (enabled by default),
RETAIN_CYCLE (enabled by default),
SHELL_INJECTION (enabled by default),
@ -225,12 +232,14 @@ OPTIONS
STARVATION (enabled by default),
STATIC_INITIALIZATION_ORDER_FIASCO (enabled by default),
STRICT_MODE_VIOLATION (enabled by default),
STRONG_DELEGATE_WARNING (enabled by default),
STRONG_SELF_NOT_CHECKED (enabled by default),
Symexec_memory_error (enabled by default),
THREAD_SAFETY_VIOLATION (enabled by default),
TOPL_ERROR (enabled by default),
UNARY_MINUS_APPLIED_TO_UNSIGNED_EXPRESSION (disabled by
default),
UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK (enabled by default),
UNINITIALIZED_VALUE (enabled by default),
UNREACHABLE_CODE (enabled by default),
UNTRUSTED_BUFFER_ACCESS (disabled by default),

@ -360,9 +360,11 @@ OPTIONS
ARRAY_OUT_OF_BOUNDS_L1 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L2 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L3 (disabled by default),
ASSIGN_POINTER_WARNING (enabled by default),
Abduction_case_not_implemented (enabled by default),
Array_of_pointsto (enabled by default),
Assert_failure (enabled by default),
BAD_POINTER_COMPARISON (enabled by default),
BIABDUCTION_ANALYSIS_STOPS (disabled by default),
BIABD_CONDITION_ALWAYS_FALSE (disabled by default),
BIABD_CONDITION_ALWAYS_TRUE (disabled by default),
@ -401,6 +403,7 @@ OPTIONS
CONSTANT_ADDRESS_DEREFERENCE (disabled by default),
CREATE_INTENT_FROM_URI (enabled by default),
CROSS_SITE_SCRIPTING (enabled by default),
CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK (enabled by default),
Cannot_star (enabled by default),
DANGLING_POINTER_DEREFERENCE (disabled by default),
DANGLING_POINTER_DEREFERENCE_MAYBE (disabled by default),
@ -409,6 +412,8 @@ OPTIONS
DEALLOCATE_STACK_VARIABLE (enabled by default),
DEALLOCATE_STATIC_MEMORY (enabled by default),
DEALLOCATION_MISMATCH (enabled by default),
DIRECT_ATOMIC_PROPERTY_ACCESS (enabled by default),
DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER (enabled by default),
DIVIDE_BY_ZERO (disabled by default),
DO_NOT_REPORT (enabled by default),
EMPTY_VECTOR_ACCESS (enabled by default),
@ -483,12 +488,14 @@ OPTIONS
NULL_TEST_AFTER_DEREFERENCE (disabled by default),
PARAMETER_NOT_NULL_CHECKED (enabled by default),
POINTER_SIZE_MISMATCH (enabled by default),
POINTER_TO_CONST_OBJC_CLASS (enabled by default),
PRECONDITION_NOT_FOUND (enabled by default),
PRECONDITION_NOT_MET (enabled by default),
PREMATURE_NIL_TERMINATION_ARGUMENT (enabled by default),
PULSE_MEMORY_LEAK (disabled by default),
PURE_FUNCTION (enabled by default),
QUANDARY_TAINT_ERROR (enabled by default),
REGISTERED_OBSERVER_BEING_DEALLOCATED (enabled by default),
RESOURCE_LEAK (enabled by default),
RETAIN_CYCLE (enabled by default),
SHELL_INJECTION (enabled by default),
@ -501,12 +508,14 @@ OPTIONS
STARVATION (enabled by default),
STATIC_INITIALIZATION_ORDER_FIASCO (enabled by default),
STRICT_MODE_VIOLATION (enabled by default),
STRONG_DELEGATE_WARNING (enabled by default),
STRONG_SELF_NOT_CHECKED (enabled by default),
Symexec_memory_error (enabled by default),
THREAD_SAFETY_VIOLATION (enabled by default),
TOPL_ERROR (enabled by default),
UNARY_MINUS_APPLIED_TO_UNSIGNED_EXPRESSION (disabled by
default),
UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK (enabled by default),
UNINITIALIZED_VALUE (enabled by default),
UNREACHABLE_CODE (enabled by default),
UNTRUSTED_BUFFER_ACCESS (disabled by default),

@ -221,8 +221,18 @@ let assert_failure =
register_from_string ~visibility:Developer ~id:"Assert_failure" Error Biabduction
let _assign_pointer_warning =
register_from_string ~id:"ASSIGN_POINTER_WARNING" Warning Linters
~user_documentation:[%blob "../../documentation/issues/ASSIGN_POINTER_WARNING.md"]
let bad_footprint = register_from_string ~visibility:Developer ~id:"Bad_footprint" Error Biabduction
let _bad_pointer_comparison =
register_from_string ~id:"BAD_POINTER_COMPARISON" Warning Linters
~user_documentation:[%blob "../../documentation/issues/BAD_POINTER_COMPARISON.md"]
let biabduction_analysis_stops =
register_from_string ~visibility:Developer ~enabled:false ~id:"BIABDUCTION_ANALYSIS_STOPS" Warning
Biabduction
@ -280,6 +290,7 @@ let cannot_star = register_from_string ~visibility:Developer ~id:"Cannot_star" E
let captured_strong_self =
register_from_string ~id:"CAPTURED_STRONG_SELF" ~hum:"Captured strongSelf" Error SelfInBlock
~user_documentation:[%blob "../../documentation/issues/CAPTURED_STRONG_SELF.md"]
let checkers_allocates_memory =
@ -305,10 +316,12 @@ let checkers_expensive_overrides_unexpensive =
let checkers_fragment_retain_view =
register_from_string ~id:"CHECKERS_FRAGMENT_RETAINS_VIEW" ~hum:"Fragment Retains View" Warning
FragmentRetainsView
~user_documentation:[%blob "../../documentation/issues/CHECKERS_FRAGMENT_RETAINS_VIEW.md"]
let checkers_immutable_cast =
register_from_string ~id:"CHECKERS_IMMUTABLE_CAST" Warning ImmutableCast
~user_documentation:[%blob "../../documentation/issues/CHECKERS_IMMUTABLE_CAST.md"]
let checkers_printf_args = register_from_string ~id:"CHECKERS_PRINTF_ARGS" Error PrintfArgs
@ -322,6 +335,7 @@ let class_load = register_from_string ~id:"CLASS_LOAD" Warning ClassLoads
let component_factory_function =
register_from_string ~id:"COMPONENT_FACTORY_FUNCTION" Advice Linters
~user_documentation:[%blob "../../documentation/issues/COMPONENT_FACTORY_FUNCTION.md"]
let component_file_cyclomatic_complexity =
@ -334,14 +348,20 @@ let component_file_line_count =
let component_initializer_with_side_effects =
register_from_string ~id:"COMPONENT_INITIALIZER_WITH_SIDE_EFFECTS" Advice Linters
~user_documentation:
[%blob "../../documentation/issues/COMPONENT_INITIALIZER_WITH_SIDE_EFFECTS.md"]
let component_with_multiple_factory_methods =
register_from_string ~id:"COMPONENT_WITH_MULTIPLE_FACTORY_METHODS" Advice Linters
~user_documentation:
[%blob "../../documentation/issues/COMPONENT_WITH_MULTIPLE_FACTORY_METHODS.md"]
let component_with_unconventional_superclass =
register_from_string ~id:"COMPONENT_WITH_UNCONVENTIONAL_SUPERCLASS" Advice Linters
~user_documentation:
[%blob "../../documentation/issues/COMPONENT_WITH_UNCONVENTIONAL_SUPERCLASS.md"]
let condition_always_false =
@ -360,6 +380,11 @@ let create_intent_from_uri = register_from_string ~id:"CREATE_INTENT_FROM_URI" E
let cross_site_scripting = register_from_string ~id:"CROSS_SITE_SCRIPTING" Error Quandary
let _cxx_reference_captured_in_objc_block =
register_from_string ~id:"CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK" Warning Linters
~user_documentation:[%blob "../../documentation/issues/CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK.md"]
let dangling_pointer_dereference =
register_from_string ~enabled:false ~id:"DANGLING_POINTER_DEREFERENCE" Error Biabduction
@ -369,9 +394,15 @@ let dangling_pointer_dereference_maybe =
Warning Biabduction
let dead_store = register_from_string ~id:"DEAD_STORE" Error Liveness
let dead_store =
register_from_string ~id:"DEAD_STORE" Error Liveness
~user_documentation:[%blob "../../documentation/issues/DEAD_STORE.md"]
let deadlock =
register_from_string ~id:"DEADLOCK" Error Starvation
~user_documentation:[%blob "../../documentation/issues/DEADLOCK.md"]
let deadlock = register_from_string ~id:"DEADLOCK" Error Starvation
let deallocate_stack_variable =
register_from_string ~id:"DEALLOCATE_STACK_VARIABLE" Error Biabduction
@ -381,11 +412,25 @@ let deallocate_static_memory = register_from_string ~id:"DEALLOCATE_STATIC_MEMOR
let deallocation_mismatch = register_from_string ~id:"DEALLOCATION_MISMATCH" Error Biabduction
let _direct_atomic_property_access =
register_from_string ~id:"DIRECT_ATOMIC_PROPERTY_ACCESS" Warning Linters
~user_documentation:[%blob "../../documentation/issues/DIRECT_ATOMIC_PROPERTY_ACCESS.md"]
let _discouraged_weak_property_custom_setter =
register_from_string ~id:"DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER" Warning Linters
~user_documentation:
[%blob "../../documentation/issues/DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER.md"]
let divide_by_zero = register_from_string ~enabled:false ~id:"DIVIDE_BY_ZERO" Error Biabduction
let do_not_report = register_from_string ~id:"DO_NOT_REPORT" Error Quandary
let empty_vector_access = register_from_string ~id:"EMPTY_VECTOR_ACCESS" Error Biabduction
let empty_vector_access =
register_from_string ~id:"EMPTY_VECTOR_ACCESS" Error Biabduction
~user_documentation:[%blob "../../documentation/issues/EMPTY_VECTOR_ACCESS.md"]
(* Condition redundant is a very non-precise issue. Depending on the origin of what is compared with
null, this can have a lot of reasons to be actually nullable.
@ -395,6 +440,7 @@ let empty_vector_access = register_from_string ~id:"EMPTY_VECTOR_ACCESS" Error B
let eradicate_condition_redundant =
register_from_string ~id:"ERADICATE_CONDITION_REDUNDANT" ~hum:"Condition Redundant" Advice
Eradicate
~user_documentation:[%blob "../../documentation/issues/ERADICATE_CONDITION_REDUNDANT.md"]
(* TODO(T54070503) remove condition redundant nonnull *)
@ -406,11 +452,13 @@ let _ =
let eradicate_field_not_initialized =
register_from_string ~id:"ERADICATE_FIELD_NOT_INITIALIZED" ~hum:"Field Not Initialized" Warning
Eradicate
~user_documentation:[%blob "../../documentation/issues/ERADICATE_FIELD_NOT_INITIALIZED.md"]
let eradicate_field_not_nullable =
register_from_string ~id:"ERADICATE_FIELD_NOT_NULLABLE" ~hum:"Field Not Nullable" Warning
Eradicate
~user_documentation:[%blob "../../documentation/issues/ERADICATE_FIELD_NOT_NULLABLE.md"]
(* Very non-precise issue. Should be actually turned off unless for experimental purposes. *)
@ -422,11 +470,15 @@ let eradicate_field_over_annotated =
let eradicate_inconsistent_subclass_parameter_annotation =
register_from_string ~id:"ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION"
~hum:"Inconsistent Subclass Parameter Annotation" Warning Eradicate
~user_documentation:
[%blob "../../documentation/issues/ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION.md"]
let eradicate_inconsistent_subclass_return_annotation =
register_from_string ~id:"ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION"
~hum:"Inconsistent Subclass Return Annotation" Warning Eradicate
~user_documentation:
[%blob "../../documentation/issues/ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION.md"]
let eradicate_redundant_nested_class_annotation =
@ -447,17 +499,20 @@ let eradicate_nullable_dereference =
let eradicate_parameter_not_nullable =
register_from_string ~id:"ERADICATE_PARAMETER_NOT_NULLABLE" ~hum:"Parameter Not Nullable" Warning
Eradicate
~user_documentation:[%blob "../../documentation/issues/ERADICATE_PARAMETER_NOT_NULLABLE.md"]
let eradicate_return_not_nullable =
register_from_string ~id:"ERADICATE_RETURN_NOT_NULLABLE" ~hum:"Return Not Nullable" Warning
Eradicate
~user_documentation:[%blob "../../documentation/issues/ERADICATE_RETURN_NOT_NULLABLE.md"]
(* Very non-precise issue. Should be actually turned off unless for experimental purposes. *)
let eradicate_return_over_annotated =
register_from_string ~id:"ERADICATE_RETURN_OVER_ANNOTATED" ~hum:"Return Over Annotated" Advice
Eradicate
~user_documentation:[%blob "../../documentation/issues/ERADICATE_RETURN_OVER_ANNOTATED.md"]
let eradicate_unchecked_usage_in_nullsafe =
@ -504,12 +559,18 @@ let exposed_insecure_intent_handling =
let failure_exe = register_from_string ~visibility:Silent ~id:"Failure_exe" Info Biabduction
let field_not_null_checked = register_from_string ~id:"IVAR_NOT_NULL_CHECKED" Warning Biabduction
let field_not_null_checked =
register_from_string ~id:"IVAR_NOT_NULL_CHECKED" Warning Biabduction
~user_documentation:[%blob "../../documentation/issues/IVAR_NOT_NULL_CHECKED.md"]
(* from AL default linters *)
let _global_variable_initialized_with_function_or_method_call =
register_from_string ~enabled:false ~id:"GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL"
Warning Linters
~user_documentation:
[%blob
"../../documentation/issues/GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL.md"]
let guardedby_violation_racerd =
@ -568,7 +629,10 @@ let integer_overflow_u5 =
register_from_string ~enabled:false ~id:"INTEGER_OVERFLOW_U5" Error BufferOverrunChecker
let interface_not_thread_safe = register_from_string Warning ~id:"INTERFACE_NOT_THREAD_SAFE" RacerD
let interface_not_thread_safe =
register_from_string Warning ~id:"INTERFACE_NOT_THREAD_SAFE" RacerD
~user_documentation:[%blob "../../documentation/issues/INTERFACE_NOT_THREAD_SAFE.md"]
let internal_error =
register_from_string ~visibility:Developer ~id:"Internal_error" Error Biabduction
@ -595,6 +659,7 @@ let leak_unknown_origin =
let lock_consistency_violation =
register_from_string Warning ~id:"LOCK_CONSISTENCY_VIOLATION" RacerD
~user_documentation:[%blob "../../documentation/issues/LOCK_CONSISTENCY_VIOLATION.md"]
let lockless_violation = register_from_string ~id:"LOCKLESS_VIOLATION" Error Starvation
@ -605,7 +670,10 @@ let expensive_loop_invariant_call =
register_from_string ~id:"EXPENSIVE_LOOP_INVARIANT_CALL" Error LoopHoisting
let memory_leak = register_from_string ~id:"MEMORY_LEAK" Error Biabduction
let memory_leak =
register_from_string ~id:"MEMORY_LEAK" Error Biabduction
~user_documentation:[%blob "../../documentation/issues/MEMORY_LEAK.md"]
let missing_fld =
register_from_string ~visibility:Developer ~id:"Missing_fld" ~hum:"Missing Field" Error
@ -618,14 +686,18 @@ let missing_required_prop =
let mixed_self_weakself =
register_from_string ~id:"MIXED_SELF_WEAKSELF" ~hum:"Mixed Self WeakSelf" Error SelfInBlock
~user_documentation:[%blob "../../documentation/issues/MIXED_SELF_WEAKSELF.md"]
let multiple_weakself =
register_from_string ~id:"MULTIPLE_WEAKSELF" ~hum:"Multiple WeakSelf Use" Error SelfInBlock
~user_documentation:[%blob "../../documentation/issues/MULTIPLE_WEAKSELF.md"]
let mutable_local_variable_in_component_file =
register_from_string ~id:"MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE" Advice Linters
~user_documentation:
[%blob "../../documentation/issues/MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE.md"]
let null_dereference =
@ -641,10 +713,16 @@ let nullptr_dereference = register_from_string ~enabled:false ~id:"NULLPTR_DEREF
let parameter_not_null_checked =
register_from_string ~id:"PARAMETER_NOT_NULL_CHECKED" Warning Biabduction
~user_documentation:[%blob "../../documentation/issues/PARAMETER_NOT_NULL_CHECKED.md"]
let pointer_size_mismatch = register_from_string ~id:"POINTER_SIZE_MISMATCH" Error Biabduction
let _pointer_to_const_objc_class =
register_from_string ~id:"POINTER_TO_CONST_OBJC_CLASS" Warning Linters
~user_documentation:[%blob "../../documentation/issues/POINTER_TO_CONST_OBJC_CLASS.md"]
let precondition_not_found =
register_from_string ~visibility:Developer ~id:"PRECONDITION_NOT_FOUND" Error Biabduction
@ -655,6 +733,7 @@ let precondition_not_met =
let premature_nil_termination =
register_from_string ~id:"PREMATURE_NIL_TERMINATION_ARGUMENT" Warning Biabduction
~user_documentation:[%blob "../../documentation/issues/PREMATURE_NIL_TERMINATION_ARGUMENT.md"]
let pulse_memory_leak = register_from_string ~enabled:false ~id:"PULSE_MEMORY_LEAK" Error Pulse
@ -665,9 +744,21 @@ let quandary_taint_error =
register_from_string ~hum:"Taint Error" ~id:"QUANDARY_TAINT_ERROR" Error Quandary
let resource_leak = register_from_string ~id:"RESOURCE_LEAK" Error Biabduction
let _registered_observer_being_deallocated =
register_from_string ~id:"REGISTERED_OBSERVER_BEING_DEALLOCATED" Warning Linters
~user_documentation:
[%blob "../../documentation/issues/REGISTERED_OBSERVER_BEING_DEALLOCATED.md"]
let resource_leak =
register_from_string ~id:"RESOURCE_LEAK" Error Biabduction
~user_documentation:[%blob "../../documentation/issues/RESOURCE_LEAK.md"]
let retain_cycle =
register_from_string ~enabled:true ~id:"RETAIN_CYCLE" Error Biabduction
~user_documentation:[%blob "../../documentation/issues/RETAIN_CYCLE.md"]
let retain_cycle = register_from_string ~enabled:true ~id:"RETAIN_CYCLE" Error Biabduction
let skip_function =
register_from_string ~visibility:Developer ~enabled:false ~id:"SKIP_FUNCTION" Info Biabduction
@ -689,7 +780,10 @@ let stack_variable_address_escape =
register_from_string ~id:"STACK_VARIABLE_ADDRESS_ESCAPE" Error Pulse
let starvation = register_from_string ~id:"STARVATION" ~hum:"UI Thread Starvation" Error Starvation
let starvation =
register_from_string ~id:"STARVATION" ~hum:"UI Thread Starvation" Error Starvation
~user_documentation:[%blob "../../documentation/issues/STARVATION.md"]
let static_initialization_order_fiasco =
register_from_string ~id:"STATIC_INITIALIZATION_ORDER_FIASCO" Error SIOF
@ -698,10 +792,17 @@ let static_initialization_order_fiasco =
let strict_mode_violation =
register_from_string ~id:"STRICT_MODE_VIOLATION" ~hum:"Strict Mode Violation" Error Starvation
~user_documentation:[%blob "../../documentation/issues/STRICT_MODE_VIOLATION.md"]
let _strong_delegate_warning =
register_from_string ~id:"STRONG_DELEGATE_WARNING" Warning Linters
~user_documentation:[%blob "../../documentation/issues/STRONG_DELEGATE_WARNING.md"]
let strong_self_not_checked =
register_from_string ~id:"STRONG_SELF_NOT_CHECKED" ~hum:"StrongSelf Not Checked" Error SelfInBlock
~user_documentation:[%blob "../../documentation/issues/STRONG_SELF_NOT_CHECKED.md"]
let symexec_memory_error =
@ -709,7 +810,10 @@ let symexec_memory_error =
~hum:"Symbolic Execution Memory Error" Error Biabduction
let thread_safety_violation = register_from_string Warning ~id:"THREAD_SAFETY_VIOLATION" RacerD
let thread_safety_violation =
register_from_string Warning ~id:"THREAD_SAFETY_VIOLATION" RacerD
~user_documentation:[%blob "../../documentation/issues/THREAD_SAFETY_VIOLATION.md"]
let complexity_increase ~kind ~is_on_ui_thread =
register_from_cost_string ~kind ~is_on_ui_thread "%s_COMPLEXITY_INCREASE"
@ -722,6 +826,11 @@ let unary_minus_applied_to_unsigned_expression =
Biabduction
let _unavailable_api_in_supported_ios_sdk =
register_from_string ~id:"UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK" Warning Linters
~user_documentation:[%blob "../../documentation/issues/UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK.md"]
let uninitialized_value = register_from_string ~id:"UNINITIALIZED_VALUE" Error Uninit
let unreachable_code_after = register_from_string ~id:"UNREACHABLE_CODE" Error BufferOverrunChecker
@ -768,6 +877,7 @@ let vector_invalidation = register_from_string ~id:"VECTOR_INVALIDATION" Error P
let weak_self_in_noescape_block =
register_from_string ~id:"WEAK_SELF_IN_NO_ESCAPE_BLOCK" Error SelfInBlock
~user_documentation:[%blob "../../documentation/issues/WEAK_SELF_IN_NO_ESCAPE_BLOCK.md"]
let wrong_argument_number =

@ -211,7 +211,7 @@ class B extends A {
A consistent use of @Nullable on the return type across subtyping should prevent
runtime issue like in:
````java
```java
class Main {
int foo(A a) {
@ -269,4 +269,3 @@ public class Main {
}
}
```
````

@ -211,7 +211,7 @@ class B extends A {
A consistent use of @Nullable on the return type across subtyping should prevent
runtime issue like in:
````java
```java
class Main {
int foo(A a) {
@ -269,4 +269,4 @@ public class Main {
}
}
```
````

Loading…
Cancel
Save