content: package com.alibaba.testable.processor.util;
  
  import com.sun.tools.javac.processing.JavacProcessingEnvironment;
  
  import java.lang.reflect.Field;
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Proxy;
  
  /**
   * @author flin
   */
  public class JavacUtil {
  
      /**
       * Refer from Lombok `LombokProcessor.java`
       * This class casts the given processing environment to a JavacProcessingEnvironment. In case of
       * gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned.
       */
      public static JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) {
          if (procEnv instanceof JavacProcessingEnvironment) {
              return (JavacProcessingEnvironment) procEnv;
          }
          // try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment
          for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) {
              Object delegate = tryGetDelegateField(procEnvClass, procEnv);
              if (delegate == null) {
                  delegate = tryGetProxyDelegateToField(procEnvClass, procEnv);
              }
              if (delegate == null) {
                  delegate = tryGetProcessingEnvField(procEnvClass, procEnv);
              }
              if (delegate != null) {
                  return getJavacProcessingEnvironment(delegate);
              }
              // delegate field was not found, try on superclass
          }
          return null;
      }
  
      /**
       * InteliJ >= 2020.3
       */
      private static Object tryGetProxyDelegateToField(Class<?> delegateClass, Object instance) {
          try {
              InvocationHandler handler = Proxy.getInvocationHandler(instance);
              return getField(handler.getClass(), "val$delegateTo").get(handler);
          } catch (Exception e) {
              return null;
          }
      }
  
      /**
       * Gradle incremental processing
       */
      private static Object tryGetDelegateField(Class<?> delegateClass, Object instance) {
          try {
              return getField(delegateClass, "delegate").get(instance);
          } catch (Exception e) {
              return null;
          }
      }
  
      /**
       * Kotlin incremental processing
       */
      private static Object tryGetProcessingEnvField(Class<?> delegateClass, Object instance) {
          try {
              return getField(delegateClass, "processingEnv").get(instance);
          } catch (Exception e) {
              return null;
          }
      }
  
      private static Field getField(Class<?> c, String fName) throws NoSuchFieldException {
          Field f = null;
          Class<?> oc = c;
          while (c != null) {
              try {
                  f = c.getDeclaredField(fName);
                  break;
              } catch (NoSuchFieldException e) {}
              c = c.getSuperclass();
          }
          if (f == null) {
              throw new NoSuchFieldException(oc.getName() + " :: " + fName);
          }
          f.setAccessible(true);
          return f;
      }
  }
  