All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rx.errorprone.DanglingSubscriptionCheck Maven / Gradle / Ivy

The newest version!
package com.rx.errorprone;

import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.util.ASTHelpers;
import com.rx.errorprone.utils.AbstractReturnValueIgnored;
import com.rx.errorprone.utils.MatcherUtils;
import com.sun.source.tree.ExpressionTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import java.util.Objects;

import static com.google.errorprone.BugPattern.Category.JDK;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.util.ASTHelpers.hasAnnotation;

/** @author [email protected] (Harshit Bangar) */
@AutoService(BugChecker.class)
@BugPattern(
  name = "DanglingSubscriptionCheck",
  summary = "Subscription should be assigned to a disposable.",
  explanation =
      "Observable's subscription should be assigned to a disposable for cleanup, otherwise it may lead to a leak",
  category = JDK,
  severity = WARNING
)
public class DanglingSubscriptionCheck extends AbstractReturnValueIgnored {

  private static final Matcher ON_SUBSCRIBE = MatcherUtils.subscribeWithForRx2();

  // Check for return type Disposable.
  // It is not able to detect correct type in subscribeWith so ON_SUBSCRIBE matcher is combined.
  // public final > E subscribeWith(E observer)
  private static final Matcher MATCHER =
      Matchers.anyOf(
          ON_SUBSCRIBE,
          new Matcher() {
            @Override
            public boolean matches(ExpressionTree tree, VisitorState state) {
              Type disposableType =
                  Objects.requireNonNull(state.getTypeFromString("io.reactivex.disposables.Disposable"));
              Symbol untypedSymbol = ASTHelpers.getSymbol(tree);
              if (!(untypedSymbol instanceof Symbol.MethodSymbol)) {
                return false;
              }
              Symbol.MethodSymbol sym = (Symbol.MethodSymbol) untypedSymbol;
              if (hasAnnotation(sym, CanIgnoreReturnValue.class, state)) {
                return false;
              }
              Type returnType = sym.getReturnType();
              return ASTHelpers.isSubtype(
                  ASTHelpers.getUpperBound(returnType, state.getTypes()), disposableType, state);
            }
          });

  @Override
  public Matcher specializedMatcher() {
    return MATCHER;
  }

  @Override
  public String linkUrl() {
    return "https://bitbucket.org/littlerobots/rxlint";
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy