private void checkForBrokenFieldAccess(
      CheckerState state,
      Artifact artifact,
      DeclaredClass clazz,
      DeclaredMethod method,
      ImmutableList.Builder<Conflict> builder) {
    for (AccessedField field : method.fieldAccesses()) {
      final ClassTypeDescriptor owningClass = field.owner();
      final DeclaredClass calledClass = state.knownClasses().get(owningClass);

      DeclaredField declaredField =
          new DeclaredFieldBuilder().descriptor(field.descriptor()).name(field.name()).build();

      if (calledClass == null) {
        builder.add(
            conflict(
                ConflictCategory.CLASS_NOT_FOUND,
                "Class not found: " + owningClass,
                dependency(clazz, method, field),
                artifact.name(),
                state.sourceMappings().get(owningClass)));
      } else if (missingField(declaredField, calledClass, state.knownClasses())) {
        builder.add(
            conflict(
                ConflictCategory.FIELD_NOT_FOUND,
                "Field not found: " + field.name(),
                dependency(clazz, method, field),
                artifact.name(),
                state.sourceMappings().get(owningClass)));
      } else {
        // Everything is ok!

      }
    }
  }
  private void checkForBrokenMethodCalls(
      CheckerState state,
      Artifact artifact,
      DeclaredClass clazz,
      DeclaredMethod method,
      ImmutableList.Builder<Conflict> builder) {
    for (CalledMethod calledMethod : method.methodCalls()) {
      final ClassTypeDescriptor owningClass = calledMethod.owner();
      final DeclaredClass calledClass = state.knownClasses().get(owningClass);

      if (calledClass == null) {
        builder.add(
            conflict(
                ConflictCategory.CLASS_NOT_FOUND,
                "Class not found: " + owningClass,
                dependency(clazz, method, calledMethod),
                artifact.name(),
                state.sourceMappings().get(owningClass)));
      } else if (missingMethod(calledMethod, calledClass, state.knownClasses())) {
        builder.add(
            conflict(
                ConflictCategory.METHOD_SIGNATURE_NOT_FOUND,
                "Method not found: " + calledMethod.pretty(),
                dependency(clazz, method, calledMethod),
                artifact.name(),
                state.sourceMappings().get(owningClass)));
      }
    }
  }
  /**
   * @param projectArtifact the main artifact of the project we're verifying (this is considered the
   *     entry point for reachability)
   * @param artifactsToCheck all artifacts that are on the runtime classpath
   * @param allArtifacts all artifacts, including implicit artifacts (runtime provided artifacts)
   * @return a list of conflicts
   */
  public ImmutableList<Conflict> check(
      Artifact projectArtifact, List<Artifact> artifactsToCheck, List<Artifact> allArtifacts) {

    final CheckerStateBuilder stateBuilder = new CheckerStateBuilder();

    createCanonicalClassMapping(stateBuilder, allArtifacts);
    CheckerState state = stateBuilder.build();

    // brute-force reachability analysis
    Set<TypeDescriptor> reachableClasses =
        reachableFrom(projectArtifact.classes().values(), state.knownClasses());

    final ImmutableList.Builder<Conflict> builder = ImmutableList.builder();

    // Then go through everything in the classpath to make sure all the method calls / field
    // references
    // are satisfied.
    for (Artifact artifact : artifactsToCheck) {
      for (DeclaredClass clazz : artifact.classes().values()) {
        if (!reachableClasses.contains(clazz.className())) {
          continue;
        }

        for (DeclaredMethod method : clazz.methods().values()) {
          checkForBrokenMethodCalls(state, artifact, clazz, method, builder);
          checkForBrokenFieldAccess(state, artifact, clazz, method, builder);
        }
      }
    }
    return builder.build();
  }
 /**
  * Create a canonical mapping of which classes are kept. First come first serve in the classpath
  *
  * @param stateBuilder conflict checker state we're populating
  * @param allArtifacts maven artifacts to populate checker state with
  */
 private void createCanonicalClassMapping(
     CheckerStateBuilder stateBuilder, List<Artifact> allArtifacts) {
   for (Artifact artifact : allArtifacts) {
     for (DeclaredClass clazz : artifact.classes().values()) {
       if (stateBuilder.knownClasses().putIfAbsent(clazz.className(), clazz) == null) {
         stateBuilder.putSourceMapping(clazz.className(), artifact.name());
       }
     }
   }
 }