Add @Nullsafe(Nullsafe.Mode.LOCAL) to clean interfaces and classes#55568
Open
Nehgupta-1203 wants to merge 1 commit intofacebook:mainfrom
Open
Add @Nullsafe(Nullsafe.Mode.LOCAL) to clean interfaces and classes#55568Nehgupta-1203 wants to merge 1 commit intofacebook:mainfrom
Nehgupta-1203 wants to merge 1 commit intofacebook:mainfrom
Conversation
Summary: Add Nullsafe(Nullsafe.Mode.LOCAL) annotation to 10 un-annotated Java interfaces and classes across imagepipeline-base, drawee, and drawee-backends modules. These files require no NULLSAFE_FIXME suppressions — all null contracts are already correct. This is a compile-time annotation for Infer static analysis with zero runtime effect. Files: QualityInfo, HasImageMetadata, ImageInfo (imagepipeline-base); DraweeHierarchy, SettableDraweeHierarchy, DraweeController, SimpleDraweeControllerBuilder, ControllerViewportVisibilityListener, GenericDraweeHierarchy (drawee); ImageOriginListener (drawee-backends). Also adds infer-annotations dep to drawee/interfaces BUCK. **Context** What is Nullsafe? Nullsafe is a Meta annotation that enables static null checking via https://fbinfer.com/, Meta's static analysis tool. When you annotate a class with Nullsafe, Infer analyzes the code at compile time (not runtime) and flags any place where a null value could sneak in and cause a crash. Without Nullsafe, Infer ignores null issues in that class. With it, every field, parameter, and return value is assumed non-null by default unless explicitly marked Nullable. What does Nullsafe.Mode.LOCAL mean? There are different strictness levels: ┌────────┬─────────────────────────────────────────────────────────────────────────────────────────────┐ │ Mode │ What it checks │ ├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤ │ LOCAL │ Only checks code within this class. Trusts that other classes return correct values. │ ├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤ │ STRICT │ Checks this class AND requires all dependencies to also be Nullsafe. Much harder to adopt. │ └────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘ LOCAL is the safe starting point — it catches bugs in the annotated class without requiring the entire dependency tree to be annotated first. **Java-Kotlin Interop and Platform Types** When Kotlin calls unannotated Java code, Kotlin treats return types as platform types (shown as Type!). This means Kotlin doesn't know if it's nullable or not, and lets you treat it either way: // Java: public String getName() { ... } (no annotation) // Kotlin sees: String! (platform type — could be null or non-null) val name: String = controller.name // Kotlin allows this (treats as non-null) val name: String? = controller.name // Kotlin also allows this (treats as nullable) Once we add Nullsafe to the Java class, unannotated types become strictly non-null, and Nullable-annotated types become strictly nullable: Safety These changes are compile-time only. Nullsafe and Nullable are annotation-only — they produce zero bytecode changes, zero runtime overhead, and don't change any actual behavior. They just make the compiler and static analysis catch null bugs earlier. Reviewed By: cortinico Differential Revision: D93118745
cortinico
approved these changes
Feb 16, 2026
Contributor
cortinico
left a comment
There was a problem hiding this comment.
Review automatically exported from Phabricator review in Meta.
cortinico
approved these changes
Feb 16, 2026
Contributor
cortinico
left a comment
There was a problem hiding this comment.
Review automatically exported from Phabricator review in Meta.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
Add Nullsafe(Nullsafe.Mode.LOCAL) annotation to 10 un-annotated Java interfaces and classes across imagepipeline-base, drawee, and drawee-backends modules. These files require no NULLSAFE_FIXME suppressions — all null contracts are already correct. This is a compile-time annotation for Infer static analysis with zero runtime effect.
Files: QualityInfo, HasImageMetadata, ImageInfo (imagepipeline-base); DraweeHierarchy, SettableDraweeHierarchy, DraweeController, SimpleDraweeControllerBuilder, ControllerViewportVisibilityListener, GenericDraweeHierarchy (drawee); ImageOriginListener (drawee-backends). Also adds infer-annotations dep to drawee/interfaces BUCK.
Context
What is Nullsafe?
Nullsafe is a Meta annotation that enables static null checking via https://fbinfer.com/, Meta's static analysis tool. When you annotate a class
with Nullsafe, Infer analyzes the code at compile time (not runtime) and flags any place where a null value could sneak in and cause a crash.
Without Nullsafe, Infer ignores null issues in that class. With it, every field, parameter, and return value is assumed non-null by default unless
explicitly marked Nullable.
What does Nullsafe.Mode.LOCAL mean?
There are different strictness levels:
┌────────┬─────────────────────────────────────────────────────────────────────────────────────────────┐
│ Mode │ What it checks │
├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
│ LOCAL │ Only checks code within this class. Trusts that other classes return correct values. │
├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
│ STRICT │ Checks this class AND requires all dependencies to also be Nullsafe. Much harder to adopt. │
└────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘
LOCAL is the safe starting point — it catches bugs in the annotated class without requiring the entire dependency tree to be annotated first.
Java-Kotlin Interop and Platform Types
When Kotlin calls unannotated Java code, Kotlin treats return types as platform types (shown as Type!). This means Kotlin doesn't know if it's
nullable or not, and lets you treat it either way:
// Java: public String getName() { ... } (no annotation)
// Kotlin sees: String! (platform type — could be null or non-null)
val name: String = controller.name // Kotlin allows this (treats as non-null)
val name: String? = controller.name // Kotlin also allows this (treats as nullable)
Once we add Nullsafe to the Java class, unannotated types become strictly non-null, and Nullable-annotated types become strictly nullable:
Safety
These changes are compile-time only. Nullsafe and Nullable are annotation-only — they produce zero bytecode changes, zero runtime overhead, and
don't change any actual behavior. They just make the compiler and static analysis catch null bugs earlier.
Reviewed By: cortinico
Differential Revision: D93118745