<commit_before>/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.uiDesigner.compiler;

import com.intellij.uiDesigner.UIFormXmlConstants;
import com.intellij.uiDesigner.lw.*;
import com.intellij.uiDesigner.shared.BorderType;
import org.objectweb.asm.*;
import org.objectweb.asm.Label;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @author yole
 */
public class AsmCodeGenerator {
  private final LwRootContainer myRootContainer;
  private final ClassLoader myLoader;
  private final ArrayList myErrors;
  private final ArrayList myWarnings;

  private final Map myIdToLocalMap = new HashMap();

  private static final String CONSTRUCTOR_NAME = "<init>";
  private String myClassToBind;
  private byte[] myPatchedData;

  private static final Map myContainerLayoutCodeGenerators = new HashMap();
  private static final Map myComponentLayoutCodeGenerators = new HashMap();
  private static final Map myPropertyCodeGenerators = new HashMap();
  public static final String SETUP_METHOD_NAME = "$$$setupUI$$$";
  public static final String GET_ROOT_COMPONENT_METHOD_NAME = "$$$getRootComponent$$$";
  public static final String CREATE_COMPONENTS_METHOD_NAME = "createUIComponents";
  public static final String LOAD_LABEL_TEXT_METHOD = "$$$loadLabelText$$$";
  public static final String LOAD_BUTTON_TEXT_METHOD = "$$$loadButtonText$$$";

  private static final Type ourButtonGroupType = Type.getType(ButtonGroup.class);
  private static final Type ourBorderFactoryType = Type.getType(BorderFactory.class);
  private static final Type ourBorderType = Type.getType(Border.class);
  private static final Method ourCreateTitledBorderMethod = Method.getMethod(
    "javax.swing.border.TitledBorder createTitledBorder(javax.swing.border.Border,java.lang.String,int,int,java.awt.Font,java.awt.Color)");

  private static final String ourBorderFactoryClientProperty = "BorderFactoryClass";

  private final NestedFormLoader myFormLoader;
  private final boolean myIgnoreCustomCreation;
  private final ClassWriter myClassWriter;

  static {
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_INTELLIJ, new GridLayoutCodeGenerator());
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_GRIDBAG, new GridBagLayoutCodeGenerator());
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_BORDER, new SimpleLayoutCodeGenerator(Type.getType(BorderLayout.class)));
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_CARD, new SimpleLayoutCodeGenerator(Type.getType(CardLayout.class)));
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_FLOW, new FlowLayoutCodeGenerator());

    myComponentLayoutCodeGenerators.put(LwSplitPane.class, new SplitPaneLayoutCodeGenerator());
    myComponentLayoutCodeGenerators.put(LwTabbedPane.class, new TabbedPaneLayoutCodeGenerator());
    myComponentLayoutCodeGenerators.put(LwScrollPane.class, new ScrollPaneLayoutCodeGenerator());
    myComponentLayoutCodeGenerators.put(LwToolBar.class, new ToolBarLayoutCodeGenerator());

    myPropertyCodeGenerators.put(String.class.getName(), new StringPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Dimension.class.getName(), new DimensionPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Insets.class.getName(), new InsetsPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Rectangle.class.getName(), new RectanglePropertyCodeGenerator());
    myPropertyCodeGenerators.put(Color.class.getName(), new ColorPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Font.class.getName(), new FontPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Icon.class.getName(), new IconPropertyCodeGenerator());
    myPropertyCodeGenerators.put(ListModel.class.getName(), new ListModelPropertyCodeGenerator(DefaultListModel.class));
    myPropertyCodeGenerators.put(ComboBoxModel.class.getName(), new ListModelPropertyCodeGenerator(DefaultComboBoxModel.class));
    myPropertyCodeGenerators.put("java.lang.Enum", new EnumPropertyCodeGenerator());
  }

  public AsmCodeGenerator(LwRootContainer rootContainer,
                          ClassLoader loader,
                          NestedFormLoader formLoader,
                          final boolean ignoreCustomCreation,
                          final ClassWriter classWriter) {
    myFormLoader = formLoader;
    myIgnoreCustomCreation = ignoreCustomCreation;
    if (loader == null){
      throw new IllegalArgumentException("loader cannot be null");
    }
    if (rootContainer == null){
      throw new IllegalArgumentException("rootContainer cannot be null");
    }
    myRootContainer = rootContainer;
    myLoader = loader;

    myErrors = new ArrayList();
    myWarnings = new ArrayList();
    myClassWriter = classWriter;
  }

  public void patchFile(final File classFile) {
    if (!classFile.exists()) {
      myErrors.add(new FormErrorInfo(null, "Class to bind does not exist: " + myRootContainer.getClassToBind()));
      return;
    }

    FileInputStream fis;
    try {
      byte[] patchedData;
      fis = new FileInputStream(classFile);
      try {
        patchedData = patchClass(fis);
        if (patchedData == null) {
          return;
        }
      }
      finally {
        fis.close();
      }

      FileOutputStream fos = new FileOutputStream(classFile);
      try {
        fos.write(patchedData);
      }
      finally {
        fos.close();
      }
    }
    catch (IOException e) {
      myErrors.add(new FormErrorInfo(null, "Cannot read or write class file " + classFile.getPath() + ": " + e.toString()));
    }
    catch(IllegalStateException e) {
      myErrors.add(new FormErrorInfo(null, "Unexpected data in form file when patching class " + classFile.getPath() + ": " + e.toString()));
    }
  }

  public byte[] patchClass(InputStream classStream) {
    myClassToBind = myRootContainer.getClassToBind();
    if (myClassToBind == null){
      myWarnings.add(new FormErrorInfo(null, "No class to bind specified"));
      return null;
    }

    if (myRootContainer.getComponentCount() != 1) {
      myErrors.add(new FormErrorInfo(null, "There should be only one component at the top level"));
      return null;
    }

    String nonEmptyPanel = Utils.findNotEmptyPanelWithXYLayout(myRootContainer.getComponent(0));
    if (nonEmptyPanel != null) {
      myErrors.add(new FormErrorInfo(nonEmptyPanel,
                                     "There are non empty panels with XY layout. Please lay them out in a grid."));
      return null;
    }

    ClassReader reader;
    try {
      reader = new ClassReader(classStream);
    }
    catch (IOException e) {
      myErrors.add(new FormErrorInfo(null, "Error reading class data stream"));
      return null;
    }<commit_msg>expose patchClass(ClassReader) method<commit_after>/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.uiDesigner.compiler;

import com.intellij.uiDesigner.UIFormXmlConstants;
import com.intellij.uiDesigner.lw.*;
import com.intellij.uiDesigner.shared.BorderType;
import org.objectweb.asm.*;
import org.objectweb.asm.Label;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author yole
 */
public class AsmCodeGenerator {
  private final LwRootContainer myRootContainer;
  private final ClassLoader myLoader;
  private final ArrayList myErrors;
  private final ArrayList myWarnings;

  private final Map myIdToLocalMap = new HashMap();

  private static final String CONSTRUCTOR_NAME = "<init>";
  private String myClassToBind;
  private byte[] myPatchedData;

  private static final Map myContainerLayoutCodeGenerators = new HashMap();
  private static final Map myComponentLayoutCodeGenerators = new HashMap();
  private static final Map myPropertyCodeGenerators = new HashMap();
  public static final String SETUP_METHOD_NAME = "$$$setupUI$$$";
  public static final String GET_ROOT_COMPONENT_METHOD_NAME = "$$$getRootComponent$$$";
  public static final String CREATE_COMPONENTS_METHOD_NAME = "createUIComponents";
  public static final String LOAD_LABEL_TEXT_METHOD = "$$$loadLabelText$$$";
  public static final String LOAD_BUTTON_TEXT_METHOD = "$$$loadButtonText$$$";

  private static final Type ourButtonGroupType = Type.getType(ButtonGroup.class);
  private static final Type ourBorderFactoryType = Type.getType(BorderFactory.class);
  private static final Type ourBorderType = Type.getType(Border.class);
  private static final Method ourCreateTitledBorderMethod = Method.getMethod(
    "javax.swing.border.TitledBorder createTitledBorder(javax.swing.border.Border,java.lang.String,int,int,java.awt.Font,java.awt.Color)");

  private static final String ourBorderFactoryClientProperty = "BorderFactoryClass";

  private final NestedFormLoader myFormLoader;
  private final boolean myIgnoreCustomCreation;
  private final ClassWriter myClassWriter;

  static {
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_INTELLIJ, new GridLayoutCodeGenerator());
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_GRIDBAG, new GridBagLayoutCodeGenerator());
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_BORDER, new SimpleLayoutCodeGenerator(Type.getType(BorderLayout.class)));
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_CARD, new SimpleLayoutCodeGenerator(Type.getType(CardLayout.class)));
    myContainerLayoutCodeGenerators.put(UIFormXmlConstants.LAYOUT_FLOW, new FlowLayoutCodeGenerator());

    myComponentLayoutCodeGenerators.put(LwSplitPane.class, new SplitPaneLayoutCodeGenerator());
    myComponentLayoutCodeGenerators.put(LwTabbedPane.class, new TabbedPaneLayoutCodeGenerator());
    myComponentLayoutCodeGenerators.put(LwScrollPane.class, new ScrollPaneLayoutCodeGenerator());
    myComponentLayoutCodeGenerators.put(LwToolBar.class, new ToolBarLayoutCodeGenerator());

    myPropertyCodeGenerators.put(String.class.getName(), new StringPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Dimension.class.getName(), new DimensionPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Insets.class.getName(), new InsetsPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Rectangle.class.getName(), new RectanglePropertyCodeGenerator());
    myPropertyCodeGenerators.put(Color.class.getName(), new ColorPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Font.class.getName(), new FontPropertyCodeGenerator());
    myPropertyCodeGenerators.put(Icon.class.getName(), new IconPropertyCodeGenerator());
    myPropertyCodeGenerators.put(ListModel.class.getName(), new ListModelPropertyCodeGenerator(DefaultListModel.class));
    myPropertyCodeGenerators.put(ComboBoxModel.class.getName(), new ListModelPropertyCodeGenerator(DefaultComboBoxModel.class));
    myPropertyCodeGenerators.put("java.lang.Enum", new EnumPropertyCodeGenerator());
  }

  public AsmCodeGenerator(LwRootContainer rootContainer,
                          ClassLoader loader,
                          NestedFormLoader formLoader,
                          final boolean ignoreCustomCreation,
                          final ClassWriter classWriter) {
    myFormLoader = formLoader;
    myIgnoreCustomCreation = ignoreCustomCreation;
    if (loader == null){
      throw new IllegalArgumentException("loader cannot be null");
    }
    if (rootContainer == null){
      throw new IllegalArgumentException("rootContainer cannot be null");
    }
    myRootContainer = rootContainer;
    myLoader = loader;

    myErrors = new ArrayList();
    myWarnings = new ArrayList();
    myClassWriter = classWriter;
  }

  public void patchFile(final File classFile) {
    if (!classFile.exists()) {
      myErrors.add(new FormErrorInfo(null, "Class to bind does not exist: " + myRootContainer.getClassToBind()));
      return;
    }

    FileInputStream fis;
    try {
      byte[] patchedData;
      fis = new FileInputStream(classFile);
      try {
        patchedData = patchClass(fis);
        if (patchedData == null) {
          return;
        }
      }
      finally {
        fis.close();
      }

      FileOutputStream fos = new FileOutputStream(classFile);
      try {
        fos.write(patchedData);
      }
      finally {
        fos.close();
      }
    }
    catch (IOException e) {
      myErrors.add(new FormErrorInfo(null, "Cannot read or write class file " + classFile.getPath() + ": " + e.toString()));
    }
    catch(IllegalStateException e) {
      myErrors.add(new FormErrorInfo(null, "Unexpected data in form file when patching class " + classFile.getPath() + ": " + e.toString()));
    }
  }

  public byte[] patchClass(InputStream classStream) {
    try {
      final ClassReader reader = new ClassReader(classStream);
      return patchClass(reader);
    }
    catch (IOException e) {
      myErrors.add(new FormErrorInfo(null, "Error reading class data stream"));
      return null;
    }
  }

  public byte[] patchClass(ClassReader reader) {
    myClassToBind = myRootContainer.getClassToBind();
    if (myClassToBind == null){
      myWarnings.add(new FormErrorInfo(null, "No class to bind specified"));
      return null;
    }

    if (myRootContainer.getComponentCount() != 1) {
      myErrors.add(new FormErrorInfo(null, "There should be only one component at the top level"));
      return null;
    }

    String nonEmptyPanel = Utils.findNotEmptyPanelWithXYLayout(myRootContainer.getComponent(0));
    if (nonEmptyPanel != null) {
      myErrors.add(new FormErrorInfo(nonEmptyPanel,
                                     "There are non empty panels with XY layout. Please lay them out in a grid."));
      return null;
    }
{'fraction_non_alphanumeric': 0.09347500162961997, 'fraction_numerical': 0.0018251743693370706, 'mean_word_length': 4.303145523677843, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2897343', 'n_tokens_mistral': 4134, 'n_tokens_neox': 4137, 'n_words': 1022}