Beispiel #1
0
  private void checkCompoundIds(Class<?> javaClass) throws IOException {
    String javaClassName = javaClass.getCanonicalName();
    PsiClass psiClass =
        myJavaPsiFacade.findClass(
            javaClassName, GlobalSearchScope.moduleWithLibrariesScope(myModule));
    assertNotNull(psiClass);

    for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
      Method method =
          new Method(
              Type.getType(javaClass).getInternalName(),
              javaMethod.getName(),
              Type.getMethodDescriptor(javaMethod));
      boolean noKey = javaMethod.getAnnotation(ExpectNoPsiKey.class) != null;
      PsiMethod psiMethod = psiClass.findMethodsByName(javaMethod.getName(), false)[0];
      checkCompoundId(method, psiMethod, noKey);
    }

    for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
      Method method =
          new Method(
              Type.getType(javaClass).getInternalName(),
              "<init>",
              Type.getConstructorDescriptor(constructor));
      boolean noKey = constructor.getAnnotation(ExpectNoPsiKey.class) != null;
      PsiMethod[] constructors = psiClass.getConstructors();
      PsiMethod psiMethod = constructors[0];
      checkCompoundId(method, psiMethod, noKey);
    }
  }
    public AnnotationTextCollector(@Nullable String desc, AnnotationResultCallback callback) {
      super(ASM_API);
      myCallback = callback;

      myDesc = desc;
      if (desc != null) {
        myBuilder.append('@').append(getTypeText(Type.getType(desc)));
      }
    }
 @Override
 public BasicValue naryOperation(AbstractInsnNode insn, List<? extends BasicValue> values)
     throws AnalyzerException {
   int opcode = insn.getOpcode();
   if (opcode == MULTIANEWARRAY) {
     return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
   } else if (opcode == INVOKEDYNAMIC) {
     return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc));
   } else {
     return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
   }
 }
 @NotNull
 private static TypeInfo fieldTypeViaDescription(@NotNull String desc) {
   Type type = Type.getType(desc);
   final int dim = type.getSort() == Type.ARRAY ? type.getDimensions() : 0;
   if (dim > 0) {
     type = type.getElementType();
   }
   return new TypeInfo(
       getTypeText(type),
       (byte) dim,
       false,
       PsiAnnotationStub.EMPTY_ARRAY); // todo read annos from .class file
 }
 // add assert startup code
 private void initAssertions(MethodVisitor mv) {
   mv.visitLdcInsn(Type.getType("L" + myClassName + ";"));
   mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false);
   Label l0 = new Label();
   mv.visitJumpInsn(IFNE, l0);
   mv.visitInsn(ICONST_1);
   Label l1 = new Label();
   mv.visitJumpInsn(GOTO, l1);
   mv.visitLabel(l0);
   mv.visitInsn(ICONST_0);
   mv.visitLabel(l1);
   mv.visitFieldInsn(PUTSTATIC, myClassName, ASSERTIONS_DISABLED_NAME, "Z");
 }
Beispiel #6
0
  private static void checkLeakingParameters(Class<?> jClass) throws IOException {
    final HashMap<Method, boolean[]> map = new HashMap<Method, boolean[]>();

    // collecting leakedParameters
    final ClassReader classReader =
        new ClassReader(
            new FileInputStream(
                jClass.getResource("/" + jClass.getName().replace('.', '/') + ".class").getFile()));
    classReader.accept(
        new ClassVisitor(Opcodes.ASM5) {
          @Override
          public MethodVisitor visitMethod(
              int access, String name, String desc, String signature, String[] exceptions) {
            final MethodNode node =
                new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions);
            final Method method = new Method(classReader.getClassName(), name, desc);
            return new MethodVisitor(Opcodes.ASM5, node) {
              @Override
              public void visitEnd() {
                super.visitEnd();
                try {
                  map.put(
                      method,
                      LeakingParameters.build(classReader.getClassName(), node, false).parameters);
                } catch (AnalyzerException ignore) {
                }
              }
            };
          }
        },
        ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);

    for (java.lang.reflect.Method jMethod : jClass.getDeclaredMethods()) {
      Method method =
          new Method(
              Type.getType(jClass).getInternalName(),
              jMethod.getName(),
              Type.getMethodDescriptor(jMethod));
      Annotation[][] annotations = jMethod.getParameterAnnotations();
      for (int i = 0; i < annotations.length; i++) {
        boolean isLeaking = false;
        Annotation[] parameterAnnotations = annotations[i];
        for (Annotation parameterAnnotation : parameterAnnotations) {
          if (parameterAnnotation.annotationType() == ExpectLeaking.class) {
            isLeaking = true;
          }
        }
        assertEquals(method.toString() + " #" + i, isLeaking, map.get(method)[i]);
      }
    }
  }
  private List<CapturedParamInfo> extractParametersMappingAndPatchConstructor(
      @NotNull MethodNode constructor,
      @NotNull ParametersBuilder capturedParamBuilder,
      @NotNull ParametersBuilder constructorParamBuilder,
      @NotNull final AnonymousObjectGeneration anonymousObjectGen,
      @NotNull FieldRemapper parentFieldRemapper) {

    CapturedParamOwner owner =
        new CapturedParamOwner() {
          @Override
          public Type getType() {
            return Type.getObjectType(anonymousObjectGen.getOwnerInternalName());
          }
        };

    Set<LambdaInfo> capturedLambdas =
        new LinkedHashSet<LambdaInfo>(); // captured var of inlined parameter
    List<CapturedParamInfo> constructorAdditionalFakeParams = new ArrayList<CapturedParamInfo>();
    Map<Integer, LambdaInfo> indexToLambda = anonymousObjectGen.getLambdasToInline();
    Set<Integer> capturedParams = new HashSet<Integer>();

    // load captured parameters and patch instruction list (NB: there is also could be object
    // fields)
    AbstractInsnNode cur = constructor.instructions.getFirst();
    while (cur != null) {
      if (cur instanceof FieldInsnNode) {
        FieldInsnNode fieldNode = (FieldInsnNode) cur;
        String fieldName = fieldNode.name;
        if (fieldNode.getOpcode() == Opcodes.PUTFIELD
            && InlineCodegenUtil.isCapturedFieldName(fieldName)) {

          boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
          boolean isPrevPrevVarNode =
              isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;

          if (isPrevPrevVarNode) {
            VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious();
            if (node.var == 0) {
              VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
              int varIndex = previous.var;
              LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
              String newFieldName =
                  isThis0(fieldName)
                          && shouldRenameThis0(parentFieldRemapper, indexToLambda.values())
                      ? getNewFieldName(fieldName, true)
                      : fieldName;
              CapturedParamInfo info =
                  capturedParamBuilder.addCapturedParam(
                      owner,
                      fieldName,
                      newFieldName,
                      Type.getType(fieldNode.desc),
                      lambdaInfo != null,
                      null);
              if (lambdaInfo != null) {
                info.setLambda(lambdaInfo);
                capturedLambdas.add(lambdaInfo);
              }
              constructorAdditionalFakeParams.add(info);
              capturedParams.add(varIndex);

              constructor.instructions.remove(previous.getPrevious());
              constructor.instructions.remove(previous);
              AbstractInsnNode temp = cur;
              cur = cur.getNext();
              constructor.instructions.remove(temp);
              continue;
            }
          }
        }
      }
      cur = cur.getNext();
    }

    constructorParamBuilder.addThis(oldObjectType, false);
    String constructorDesc = anonymousObjectGen.getConstructorDesc();

    if (constructorDesc == null) {
      // in case of anonymous object with empty closure
      constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE);
    }

    Type[] types = Type.getArgumentTypes(constructorDesc);
    for (Type type : types) {
      LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex());
      ParameterInfo parameterInfo =
          constructorParamBuilder.addNextParameter(type, info != null, null);
      parameterInfo.setLambda(info);
      if (capturedParams.contains(parameterInfo.getIndex())) {
        parameterInfo.setCaptured(true);
      } else {
        // otherwise it's super constructor parameter
      }
    }

    // For all inlined lambdas add their captured parameters
    // TODO: some of such parameters could be skipped - we should perform additional analysis
    Map<String, LambdaInfo> capturedLambdasToInline =
        new HashMap<String, LambdaInfo>(); // captured var of inlined parameter
    List<CapturedParamDesc> allRecapturedParameters = new ArrayList<CapturedParamDesc>();
    boolean addCapturedNotAddOuter =
        parentFieldRemapper.isRoot()
            || (parentFieldRemapper instanceof InlinedLambdaRemapper
                && parentFieldRemapper.getParent().isRoot());
    Map<String, CapturedParamInfo> alreadyAdded = new HashMap<String, CapturedParamInfo>();
    for (LambdaInfo info : capturedLambdas) {
      if (addCapturedNotAddOuter) {
        for (CapturedParamDesc desc : info.getCapturedVars()) {
          String key = desc.getFieldName() + "$$$" + desc.getType().getClassName();
          CapturedParamInfo alreadyAddedParam = alreadyAdded.get(key);

          CapturedParamInfo recapturedParamInfo =
              capturedParamBuilder.addCapturedParam(
                  desc,
                  alreadyAddedParam != null
                      ? alreadyAddedParam.getNewFieldName()
                      : getNewFieldName(desc.getFieldName(), false));
          StackValue composed =
              StackValue.field(
                  desc.getType(),
                  oldObjectType, /*TODO owner type*/
                  recapturedParamInfo.getNewFieldName(),
                  false,
                  StackValue.LOCAL_0);
          recapturedParamInfo.setRemapValue(composed);
          allRecapturedParameters.add(desc);

          constructorParamBuilder
              .addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName())
              .setRemapValue(composed);
          if (alreadyAddedParam != null) {
            recapturedParamInfo.setSkipInConstructor(true);
          }

          if (isThis0(desc.getFieldName())) {
            alreadyAdded.put(key, recapturedParamInfo);
          }
        }
      }
      capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info);
    }

    if (parentFieldRemapper instanceof InlinedLambdaRemapper
        && !capturedLambdas.isEmpty()
        && !addCapturedNotAddOuter) {
      // lambda with non InlinedLambdaRemapper already have outer
      FieldRemapper parent = parentFieldRemapper.getParent();
      assert parent instanceof RegeneratedLambdaFieldRemapper;
      final Type ownerType = Type.getObjectType(parent.getLambdaInternalName());

      CapturedParamDesc desc =
          new CapturedParamDesc(
              new CapturedParamOwner() {
                @Override
                public Type getType() {
                  return ownerType;
                }
              },
              InlineCodegenUtil.THIS,
              ownerType);
      CapturedParamInfo recapturedParamInfo =
          capturedParamBuilder.addCapturedParam(
              desc, InlineCodegenUtil.THIS$0 /*outer lambda/object*/);
      StackValue composed = StackValue.LOCAL_0;
      recapturedParamInfo.setRemapValue(composed);
      allRecapturedParameters.add(desc);

      constructorParamBuilder
          .addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName())
          .setRemapValue(composed);
    }

    anonymousObjectGen.setAllRecapturedParameters(allRecapturedParameters);
    anonymousObjectGen.setCapturedLambdasToInline(capturedLambdasToInline);

    return constructorAdditionalFakeParams;
  }
 public void generatePushValue(final GeneratorAdapter generator, final Object value) {
   final Type enumType = Type.getType(value.getClass());
   generator.getStatic(enumType, value.toString(), enumType);
 }
 @Override
 public void visitEnum(final String name, final String desc, final String value) {
   valuePairPrefix(name);
   myBuilder.append(getTypeText(Type.getType(desc))).append(".").append(value);
 }
  @Override
  public BasicValue newOperation(@NotNull AbstractInsnNode insn) throws AnalyzerException {
    if (insn.getOpcode() == Opcodes.ACONST_NULL) {
      return newValue(Type.getObjectType("java/lang/Object"));
    }

    switch (insn.getOpcode()) {
      case ACONST_NULL:
        return newValue(Type.getObjectType("null"));
      case ICONST_M1:
      case ICONST_0:
      case ICONST_1:
      case ICONST_2:
      case ICONST_3:
      case ICONST_4:
      case ICONST_5:
        return StrictBasicValue.INT_VALUE;
      case LCONST_0:
      case LCONST_1:
        return StrictBasicValue.LONG_VALUE;
      case FCONST_0:
      case FCONST_1:
      case FCONST_2:
        return StrictBasicValue.FLOAT_VALUE;
      case DCONST_0:
      case DCONST_1:
        return StrictBasicValue.DOUBLE_VALUE;
      case BIPUSH:
      case SIPUSH:
        return StrictBasicValue.INT_VALUE;
      case LDC:
        Object cst = ((LdcInsnNode) insn).cst;
        if (cst instanceof Integer) {
          return StrictBasicValue.INT_VALUE;
        } else if (cst instanceof Float) {
          return StrictBasicValue.FLOAT_VALUE;
        } else if (cst instanceof Long) {
          return StrictBasicValue.LONG_VALUE;
        } else if (cst instanceof Double) {
          return StrictBasicValue.DOUBLE_VALUE;
        } else if (cst instanceof String) {
          return newValue(Type.getObjectType("java/lang/String"));
        } else if (cst instanceof Type) {
          int sort = ((Type) cst).getSort();
          if (sort == Type.OBJECT || sort == Type.ARRAY) {
            return newValue(Type.getObjectType("java/lang/Class"));
          } else if (sort == Type.METHOD) {
            return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
          } else {
            throw new IllegalArgumentException("Illegal LDC constant " + cst);
          }
        } else if (cst instanceof Handle) {
          return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
        } else {
          throw new IllegalArgumentException("Illegal LDC constant " + cst);
        }
      case GETSTATIC:
        return newValue(Type.getType(((FieldInsnNode) insn).desc));
      case NEW:
        return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
      default:
        throw new Error("Internal error.");
    }
  }
 @Override
 public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value)
     throws AnalyzerException {
   switch (insn.getOpcode()) {
     case INEG:
     case IINC:
     case L2I:
     case F2I:
     case D2I:
     case I2B:
     case I2C:
     case I2S:
       return StrictBasicValue.INT_VALUE;
     case FNEG:
     case I2F:
     case L2F:
     case D2F:
       return StrictBasicValue.FLOAT_VALUE;
     case LNEG:
     case I2L:
     case F2L:
     case D2L:
       return StrictBasicValue.LONG_VALUE;
     case DNEG:
     case I2D:
     case L2D:
     case F2D:
       return StrictBasicValue.DOUBLE_VALUE;
     case IFEQ:
     case IFNE:
     case IFLT:
     case IFGE:
     case IFGT:
     case IFLE:
     case TABLESWITCH:
     case LOOKUPSWITCH:
     case IRETURN:
     case LRETURN:
     case FRETURN:
     case DRETURN:
     case ARETURN:
     case PUTSTATIC:
       return null;
     case GETFIELD:
       return newValue(Type.getType(((FieldInsnNode) insn).desc));
     case NEWARRAY:
       switch (((IntInsnNode) insn).operand) {
         case T_BOOLEAN:
           return newValue(Type.getType("[Z"));
         case T_CHAR:
           return newValue(Type.getType("[C"));
         case T_BYTE:
           return newValue(Type.getType("[B"));
         case T_SHORT:
           return newValue(Type.getType("[S"));
         case T_INT:
           return newValue(Type.getType("[I"));
         case T_FLOAT:
           return newValue(Type.getType("[F"));
         case T_DOUBLE:
           return newValue(Type.getType("[D"));
         case T_LONG:
           return newValue(Type.getType("[J"));
         default:
           throw new AnalyzerException(insn, "Invalid array type");
       }
     case ANEWARRAY:
       String desc = ((TypeInsnNode) insn).desc;
       return newValue(Type.getType("[" + Type.getObjectType(desc)));
     case ARRAYLENGTH:
       return StrictBasicValue.INT_VALUE;
     case ATHROW:
       return null;
     case CHECKCAST:
       desc = ((TypeInsnNode) insn).desc;
       return newValue(Type.getObjectType(desc));
     case INSTANCEOF:
       return StrictBasicValue.INT_VALUE;
     case MONITORENTER:
     case MONITOREXIT:
     case IFNULL:
     case IFNONNULL:
       return null;
     default:
       throw new Error("Internal error.");
   }
 }
/**
 * @author yole
 * @noinspection HardCodedStringLiteral
 */
public class FontPropertyCodeGenerator extends PropertyCodeGenerator {
  private static final Type ourFontType = Type.getType(Font.class);
  private static final Type ourUIManagerType = Type.getType("Ljavax/swing/UIManager;");
  private static final Type ourObjectType = Type.getType(Object.class);
  private static final Type ourStringType = Type.getType(String.class);

  private static final Method ourInitMethod =
      Method.getMethod("void <init>(java.lang.String,int,int)");
  private static final Method ourUIManagerGetFontMethod =
      new Method("getFont", ourFontType, new Type[] {ourObjectType});
  private static final Method ourGetNameMethod = new Method("getName", ourStringType, new Type[0]);
  private static final Method ourGetSizeMethod = new Method("getSize", Type.INT_TYPE, new Type[0]);
  private static final Method ourGetStyleMethod =
      new Method("getStyle", Type.INT_TYPE, new Type[0]);

  public boolean generateCustomSetValue(
      final LwComponent lwComponent,
      final InstrumentationClassFinder.PseudoClass componentClass,
      final LwIntrospectedProperty property,
      final GeneratorAdapter generator,
      final int componentLocal,
      final String formClassName) {
    FontDescriptor descriptor = (FontDescriptor) property.getPropertyValue(lwComponent);
    if (descriptor.isFixedFont() && !descriptor.isFullyDefinedFont()) {
      generator.loadLocal(componentLocal);
      generatePushFont(
          generator, componentLocal, lwComponent, descriptor, property.getReadMethodName());

      Method setFontMethod =
          new Method(property.getWriteMethodName(), Type.VOID_TYPE, new Type[] {ourFontType});
      Type componentType = AsmCodeGenerator.typeFromClassName(lwComponent.getComponentClassName());
      generator.invokeVirtual(componentType, setFontMethod);
      return true;
    }
    return false;
  }

  public static void generatePushFont(
      final GeneratorAdapter generator,
      final int componentLocal,
      final LwComponent lwComponent,
      final FontDescriptor descriptor,
      final String readMethodName) {
    final int fontLocal = generator.newLocal(ourFontType);

    generator.loadLocal(componentLocal);
    Type componentType = AsmCodeGenerator.typeFromClassName(lwComponent.getComponentClassName());
    Method getFontMethod = new Method(readMethodName, ourFontType, new Type[0]);
    generator.invokeVirtual(componentType, getFontMethod);
    generator.storeLocal(fontLocal);

    generator.newInstance(ourFontType);
    generator.dup();
    if (descriptor.getFontName() != null) {
      generator.push(descriptor.getFontName());
    } else {
      generator.loadLocal(fontLocal);
      generator.invokeVirtual(ourFontType, ourGetNameMethod);
    }

    if (descriptor.getFontStyle() >= 0) {
      generator.push(descriptor.getFontStyle());
    } else {
      generator.loadLocal(fontLocal);
      generator.invokeVirtual(ourFontType, ourGetStyleMethod);
    }

    if (descriptor.getFontSize() >= 0) {
      generator.push(descriptor.getFontSize());
    } else {
      generator.loadLocal(fontLocal);
      generator.invokeVirtual(ourFontType, ourGetSizeMethod);
    }
    generator.invokeConstructor(ourFontType, ourInitMethod);
  }

  public void generatePushValue(final GeneratorAdapter generator, final Object value) {
    FontDescriptor descriptor = (FontDescriptor) value;
    if (descriptor.isFixedFont()) {
      if (!descriptor.isFullyDefinedFont())
        throw new IllegalStateException("Unexpected font state");
      generator.newInstance(ourFontType);
      generator.dup();
      generator.push(descriptor.getFontName());
      generator.push(descriptor.getFontStyle());
      generator.push(descriptor.getFontSize());
      generator.invokeConstructor(ourFontType, ourInitMethod);
    } else if (descriptor.getSwingFont() != null) {
      generator.push(descriptor.getSwingFont());
      generator.invokeStatic(ourUIManagerType, ourUIManagerGetFontMethod);
    } else {
      throw new IllegalStateException("Unknown font type");
    }
  }
}