private void analyzeFile()

in jar-infer/jar-infer-lib/src/main/java/com/uber/nullaway/jarinfer/DefinitelyDerefedParamsDriver.java [230:333]


  private void analyzeFile(String pkgName, String inPath, boolean includeNonPublicClasses)
      throws IOException, ClassHierarchyException {
    InputStream jarIS = null;
    if (inPath.endsWith(".jar") || inPath.endsWith(".aar")) {
      jarIS = getInputStream(inPath);
      if (jarIS == null) {
        return;
      }
    } else if (!new File(inPath).exists()) {
      return;
    }
    AnalysisScope scope = AnalysisScopeReader.instance.makeBasePrimordialScope(null);
    scope.setExclusions(
        new FileOfClasses(
            new ByteArrayInputStream(DEFAULT_EXCLUSIONS.getBytes(StandardCharsets.UTF_8))));
    if (jarIS != null) {
      scope.addInputStreamForJarToScope(ClassLoaderReference.Application, jarIS);
    } else {
      AnalysisScopeReader.instance.addClassPathToScope(
          inPath, scope, ClassLoaderReference.Application);
    }
    AnalysisOptions options = new AnalysisOptions(scope, null);
    AnalysisCache cache = new AnalysisCacheImpl();
    IClassHierarchy cha = ClassHierarchyFactory.makeWithRoot(scope);
    Warnings.clear();

    // Iterate over all classes:methods in the 'Application' and 'Extension' class loaders
    for (IClassLoader cldr : cha.getLoaders()) {
      if (!cldr.getName().toString().equals("Primordial")) {
        for (IClass cls : Iterator2Iterable.make(cldr.iterateAllClasses())) {
          if (cls instanceof PhantomClass) {
            continue;
          }
          // Only process classes in specified classpath and not its dependencies.
          // TODO: figure the right way to do this
          if (!pkgName.isEmpty() && !cls.getName().toString().startsWith(pkgName)) {
            continue;
          }
          // Skip non-public / ABI classes
          if (!cls.isPublic() && !includeNonPublicClasses) {
            continue;
          }
          LOG(DEBUG, "DEBUG", "analyzing class: " + cls.getName().toString());
          for (IMethod mtd : Iterator2Iterable.make(cls.getDeclaredMethods().iterator())) {
            // Skip methods without parameters, abstract methods, native methods
            // some Application classes are Primordial (why?)
            if (shouldCheckMethod(mtd)) {
              Preconditions.checkNotNull(mtd, "method not found");
              DefinitelyDerefedParams analysisDriver = null;
              String sign = "";
              try {
                // Parameter analysis
                boolean isStatic = mtd.isStatic();
                if (mtd.getNumberOfParameters() > (isStatic ? 0 : 1)) {
                  // For inferring parameter nullability, our criteria is based on finding
                  // unchecked dereferences of that parameter. We perform a quick bytecode
                  // check and skip methods containing no dereferences (i.e. method calls
                  // or field accesses) at all, avoiding the expensive IR/CFG generation
                  // step for these methods.
                  // Note that this doesn't apply to inferring return value nullability.
                  if (bytecodeHasAnyDereferences(mtd)) {
                    analysisDriver = getAnalysisDriver(mtd, options, cache);
                    Set<Integer> result = analysisDriver.analyze();
                    if (!isStatic) {
                      // subtract 1 from each parameter index to account for 'this' parameter
                      result =
                          result.stream().map(i -> i - 1).collect(ImmutableSet.toImmutableSet());
                    }
                    sign = getSignature(mtd);
                    LOG(DEBUG, "DEBUG", "analyzed method: " + sign);
                    if (!result.isEmpty() || DEBUG) {
                      nonnullParams.put(sign, result);
                      LOG(
                          DEBUG,
                          "DEBUG",
                          "Inferred Nonnull param for method: " + sign + " = " + result.toString());
                    }
                  }
                }
                // Return value analysis
                analyzeReturnValue(options, cache, mtd, analysisDriver, sign);
              } catch (Exception e) {
                LOG(
                    DEBUG,
                    "DEBUG",
                    "Exception while scanning bytecodes for " + mtd + " " + e.getMessage());
              }
            }
          }
        }
      }
    }
    long endTime = System.currentTimeMillis();
    LOG(
        VERBOSE,
        "Stats",
        inPath
            + " >> time(ms): "
            + (endTime - analysisStartTime)
            + ", bytecode size: "
            + analyzedBytes
            + ", rate (ms/KB): "
            + (analyzedBytes > 0 ? (((endTime - analysisStartTime) * 1000) / analyzedBytes) : 0));
  }