mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
Generated
+1
-1
@@ -11,7 +11,7 @@
|
||||
<element id="module-output" name="javac2" />
|
||||
<element id="module-output" name="forms-compiler" />
|
||||
<element id="module-output" name="forms_rt" />
|
||||
<element id="module-output" name="notNull" />
|
||||
<element id="module-output" name="instrumentation-util" />
|
||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/jna-utils.jar" path-in-jar="/" />
|
||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/jna.jar" path-in-jar="/" />
|
||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/jdom.jar" path-in-jar="/" />
|
||||
|
||||
Generated
+1
-1
@@ -51,6 +51,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/icons/icons.iml" filepath="$PROJECT_DIR$/platform/icons/icons.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/idea-ui/idea-ui.iml" filepath="$PROJECT_DIR$/java/idea-ui/idea-ui.iml" group="java" />
|
||||
<module fileurl="file://$PROJECT_DIR$/images/images.iml" filepath="$PROJECT_DIR$/images/images.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/compiler/instrumentation-util/instrumentation-util.iml" filepath="$PROJECT_DIR$/java/compiler/instrumentation-util/instrumentation-util.iml" group="java/compiler" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/java-i18n/java-i18n.iml" filepath="$PROJECT_DIR$/plugins/java-i18n/java-i18n.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/java-impl/java-impl.iml" filepath="$PROJECT_DIR$/java/java-impl/java-impl.iml" group="java" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/java-psi-api/java-psi-api.iml" filepath="$PROJECT_DIR$/java/java-psi-api/java-psi-api.iml" group="java" />
|
||||
@@ -80,7 +81,6 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/maven/maven-server-api/maven-server-api.iml" filepath="$PROJECT_DIR$/plugins/maven/maven-server-api/maven-server-api.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/maven/maven2-server-impl/maven2-server-impl.iml" filepath="$PROJECT_DIR$/plugins/maven/maven2-server-impl/maven2-server-impl.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/maven/maven3-server-impl/maven3-server-impl.iml" filepath="$PROJECT_DIR$/plugins/maven/maven3-server-impl/maven3-server-impl.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/compiler/notNull/notNull.iml" filepath="$PROJECT_DIR$/java/compiler/notNull/notNull.iml" group="java/compiler" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/openapi/openapi.iml" filepath="$PROJECT_DIR$/java/openapi/openapi.iml" group="java" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/platform-api/platform-api.iml" filepath="$PROJECT_DIR$/platform/platform-api/platform-api.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/platform-impl/platform-impl.iml" filepath="$PROJECT_DIR$/platform/platform-impl/platform-impl.iml" group="platform" />
|
||||
|
||||
@@ -43,7 +43,7 @@ public abstract class BaseParseTestcase extends UsefulTestCase{
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> builder = fixtureFactory.createFixtureBuilder();
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> builder = fixtureFactory.createFixtureBuilder(getName());
|
||||
|
||||
myFixture = fixtureFactory.createCodeInsightFixture(builder.getFixture());
|
||||
myFixture.setTestDataPath(getTestDataPath());
|
||||
|
||||
@@ -77,7 +77,7 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir
|
||||
|
||||
//noinspection GroovyAssignabilityCheck
|
||||
List<String> implementationModules = [platformImplementationModules(),
|
||||
"notNull",
|
||||
"instrumentation-util",
|
||||
"platform-main",
|
||||
"java-psi-impl",
|
||||
"java-impl",
|
||||
@@ -170,7 +170,7 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir
|
||||
module("javac2")
|
||||
module("forms-compiler")
|
||||
module("forms_rt")
|
||||
module("notNull")
|
||||
module("instrumentation-util")
|
||||
}
|
||||
|
||||
jar("jps-server.jar") {
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
<orderEntry type="module" module-name="lang-impl" />
|
||||
<orderEntry type="module" module-name="lvcs-api" />
|
||||
<orderEntry type="module" module-name="lvcs-impl" />
|
||||
<orderEntry type="module" module-name="notNull" />
|
||||
<orderEntry type="module" module-name="instrumentation-util" />
|
||||
<orderEntry type="module" module-name="openapi" />
|
||||
<orderEntry type="module" module-name="platform-api" />
|
||||
<orderEntry type="module" module-name="platform-impl" />
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit3" level="project" />
|
||||
<orderEntry type="library" name="jgoodies-forms" level="project" />
|
||||
<orderEntry type="module" module-name="instrumentation-util" exported="" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
+91
-61
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.uiDesigner.compiler;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.uiDesigner.UIFormXmlConstants;
|
||||
import com.intellij.uiDesigner.lw.*;
|
||||
import com.intellij.uiDesigner.shared.BorderType;
|
||||
@@ -28,7 +29,6 @@ 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;
|
||||
@@ -40,7 +40,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class AsmCodeGenerator {
|
||||
private final LwRootContainer myRootContainer;
|
||||
private final ClassLoader myLoader;
|
||||
private final InstrumentationClassFinder myFinder;
|
||||
private final ArrayList myErrors;
|
||||
private final ArrayList myWarnings;
|
||||
|
||||
@@ -96,20 +96,20 @@ public class AsmCodeGenerator {
|
||||
}
|
||||
|
||||
public AsmCodeGenerator(LwRootContainer rootContainer,
|
||||
ClassLoader loader,
|
||||
InstrumentationClassFinder finder,
|
||||
NestedFormLoader formLoader,
|
||||
final boolean ignoreCustomCreation,
|
||||
final ClassWriter classWriter) {
|
||||
myFormLoader = formLoader;
|
||||
myIgnoreCustomCreation = ignoreCustomCreation;
|
||||
if (loader == null){
|
||||
if (finder == null){
|
||||
throw new IllegalArgumentException("loader cannot be null");
|
||||
}
|
||||
if (rootContainer == null){
|
||||
throw new IllegalArgumentException("rootContainer cannot be null");
|
||||
}
|
||||
myRootContainer = rootContainer;
|
||||
myLoader = loader;
|
||||
myFinder = finder;
|
||||
|
||||
myErrors = new ArrayList();
|
||||
myWarnings = new ArrayList();
|
||||
@@ -210,9 +210,9 @@ public class AsmCodeGenerator {
|
||||
codeGen.generatePushValue(generator, value);
|
||||
}
|
||||
|
||||
static Class getComponentClass(String className, final ClassLoader classLoader) throws CodeGenerationException {
|
||||
static InstrumentationClassFinder.PseudoClass getComponentClass(String className, final InstrumentationClassFinder finder) throws CodeGenerationException {
|
||||
try {
|
||||
return Class.forName(className, false, classLoader);
|
||||
return finder.loadClass(className);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new CodeGenerationException(null, "Class not found: " + className);
|
||||
@@ -220,6 +220,9 @@ public class AsmCodeGenerator {
|
||||
catch(UnsupportedClassVersionError e) {
|
||||
throw new CodeGenerationException(null, "Unsupported class version error: " + className);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new CodeGenerationException(null, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Type typeFromClassName(final String className) {
|
||||
@@ -252,7 +255,7 @@ public class AsmCodeGenerator {
|
||||
|
||||
for (Iterator iterator = myPropertyCodeGenerators.values().iterator(); iterator.hasNext();) {
|
||||
PropertyCodeGenerator propertyCodeGenerator = (PropertyCodeGenerator)iterator.next();
|
||||
propertyCodeGenerator.generateClassStart(this, name, myLoader);
|
||||
propertyCodeGenerator.generateClassStart(this, name, myFinder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,28 +397,30 @@ public class AsmCodeGenerator {
|
||||
|
||||
myIdToLocalMap.put(lwComponent.getId(), new Integer(componentLocal));
|
||||
|
||||
Class componentClass = getComponentClass(className, myLoader);
|
||||
InstrumentationClassFinder.PseudoClass componentClass = getComponentClass(className, myFinder);
|
||||
validateFieldBinding(lwComponent, componentClass);
|
||||
|
||||
if (myIgnoreCustomCreation) {
|
||||
boolean creatable = true;
|
||||
if ((componentClass.getModifiers() & (Modifier.PRIVATE | Modifier.ABSTRACT)) != 0) {
|
||||
creatable = false;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
final Constructor constructor = componentClass.getConstructor(new Class[0]);
|
||||
if ((constructor.getModifiers() & Modifier.PUBLIC) == 0) {
|
||||
try {
|
||||
boolean creatable = true;
|
||||
if ((componentClass.getModifiers() & (Modifier.PRIVATE | Modifier.ABSTRACT)) != 0) {
|
||||
creatable = false;
|
||||
}
|
||||
else {
|
||||
if (!componentClass.hasDefaultPublicConstructor()) {
|
||||
creatable = false;
|
||||
}
|
||||
}
|
||||
catch(NoSuchMethodException ex) {
|
||||
creatable = false;
|
||||
if (!creatable) {
|
||||
componentClass = Utils.suggestReplacementClass(componentClass);
|
||||
componentType = Type.getType(componentClass.getDescriptor());
|
||||
}
|
||||
}
|
||||
if (!creatable) {
|
||||
componentClass = Utils.suggestReplacementClass(componentClass);
|
||||
componentType = Type.getType(componentClass);
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,12 +473,11 @@ public class AsmCodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private int getNestedFormComponent(GeneratorAdapter generator, Class componentClass, int formLocal) throws CodeGenerationException {
|
||||
private int getNestedFormComponent(GeneratorAdapter generator, InstrumentationClassFinder.PseudoClass componentClass, int formLocal) throws CodeGenerationException {
|
||||
final Type componentType = Type.getType(JComponent.class);
|
||||
int componentLocal = generator.newLocal(componentType);
|
||||
generator.loadLocal(formLocal);
|
||||
generator.invokeVirtual(Type.getType(componentClass),
|
||||
new Method(GET_ROOT_COMPONENT_METHOD_NAME, componentType, new Type[0]));
|
||||
generator.invokeVirtual(Type.getType(componentClass.getDescriptor()), new Method(GET_ROOT_COMPONENT_METHOD_NAME, componentType, new Type[0]));
|
||||
generator.storeLocal(componentLocal);
|
||||
return componentLocal;
|
||||
}
|
||||
@@ -502,7 +506,7 @@ public class AsmCodeGenerator {
|
||||
}
|
||||
|
||||
private void generateComponentProperties(final LwComponent lwComponent,
|
||||
final Class componentClass,
|
||||
final InstrumentationClassFinder.PseudoClass componentClass,
|
||||
final GeneratorAdapter generator,
|
||||
final int componentLocal) throws CodeGenerationException {
|
||||
// introspected properties
|
||||
@@ -543,7 +547,12 @@ public class AsmCodeGenerator {
|
||||
else {
|
||||
setterClass = Class.forName(propertyClass);
|
||||
}
|
||||
componentClass.getMethod(property.getWriteMethodName(), new Class[] { setterClass } );
|
||||
//componentClass.getMethod(property.getWriteMethodName(), new Class[] { setterClass } );
|
||||
final String descriptor = "(L"+setterClass.getName().replace('.', '/') + ";)V";
|
||||
final InstrumentationClassFinder.PseudoMethod setter = componentClass.findMethod(property.getWriteMethodName(), descriptor);
|
||||
if (setter == null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
continue;
|
||||
@@ -551,9 +560,16 @@ public class AsmCodeGenerator {
|
||||
}
|
||||
final PropertyCodeGenerator propGen = (PropertyCodeGenerator) myPropertyCodeGenerators.get(propertyClass);
|
||||
|
||||
if (propGen != null && propGen.generateCustomSetValue(lwComponent, componentClass, property,
|
||||
generator, componentLocal, myClassName)) {
|
||||
continue;
|
||||
try {
|
||||
if (propGen != null && propGen.generateCustomSetValue(lwComponent, componentClass, property, generator, componentLocal, myClassName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
|
||||
}
|
||||
|
||||
generator.loadLocal(componentLocal);
|
||||
@@ -602,7 +618,7 @@ public class AsmCodeGenerator {
|
||||
|
||||
Type declaringType = (property.getDeclaringClassName() != null)
|
||||
? typeFromClassName(property.getDeclaringClassName())
|
||||
: Type.getType(componentClass);
|
||||
: Type.getType(componentClass.getDescriptor());
|
||||
generator.invokeVirtual(declaringType, new Method(property.getWriteMethodName(),
|
||||
Type.VOID_TYPE, new Type[] { setterArgType } ));
|
||||
}
|
||||
@@ -611,7 +627,7 @@ public class AsmCodeGenerator {
|
||||
}
|
||||
|
||||
private void generateClientProperties(final LwComponent lwComponent,
|
||||
final Class componentClass,
|
||||
final InstrumentationClassFinder.PseudoClass componentClass,
|
||||
final GeneratorAdapter generator,
|
||||
final int componentLocal) throws CodeGenerationException {
|
||||
HashMap props = lwComponent.getDelegeeClientProperties();
|
||||
@@ -652,7 +668,7 @@ public class AsmCodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
Type componentType = Type.getType(componentClass);
|
||||
Type componentType = Type.getType(componentClass.getDescriptor());
|
||||
Type objectType = Type.getType(Object.class);
|
||||
generator.invokeVirtual(componentType, new Method("putClientProperty",
|
||||
Type.VOID_TYPE, new Type[] { objectType, objectType } ));
|
||||
@@ -664,7 +680,7 @@ public class AsmCodeGenerator {
|
||||
if (component instanceof LwNestedForm) return;
|
||||
int componentLocal = ((Integer) myIdToLocalMap.get(component.getId())).intValue();
|
||||
final LayoutCodeGenerator layoutCodeGenerator = getComponentCodeGenerator(component.getParent());
|
||||
Class componentClass = getComponentClass(layoutCodeGenerator.mapComponentClass(component.getComponentClassName()), myLoader);
|
||||
InstrumentationClassFinder.PseudoClass componentClass = getComponentClass(layoutCodeGenerator.mapComponentClass(component.getComponentClassName()), myFinder);
|
||||
|
||||
final LwIntrospectedProperty[] introspectedProperties = component.getAssignedIntrospectedProperties();
|
||||
for (int i = 0; i < introspectedProperties.length; i++) {
|
||||
@@ -681,7 +697,7 @@ public class AsmCodeGenerator {
|
||||
generator.loadLocal(targetLocal);
|
||||
Type declaringType = (property.getDeclaringClassName() != null)
|
||||
? typeFromClassName(property.getDeclaringClassName())
|
||||
: Type.getType(componentClass);
|
||||
: Type.getType(componentClass.getDescriptor());
|
||||
generator.invokeVirtual(declaringType,
|
||||
new Method(property.getWriteMethodName(),
|
||||
Type.VOID_TYPE, new Type[] { typeFromClassName(property.getPropertyClassName()) } ));
|
||||
@@ -702,33 +718,45 @@ public class AsmCodeGenerator {
|
||||
private void generateButtonGroups(final LwRootContainer rootContainer, final GeneratorAdapter generator) throws CodeGenerationException {
|
||||
IButtonGroup[] groups = rootContainer.getButtonGroups();
|
||||
if (groups.length > 0) {
|
||||
int groupLocal = generator.newLocal(ourButtonGroupType);
|
||||
for(int groupIndex=0; groupIndex<groups.length; groupIndex++) {
|
||||
String[] ids = groups [groupIndex].getComponentIds();
|
||||
try {
|
||||
InstrumentationClassFinder.PseudoClass buttonGroupClass = null; // cached
|
||||
int groupLocal = generator.newLocal(ourButtonGroupType);
|
||||
for(int groupIndex=0; groupIndex<groups.length; groupIndex++) {
|
||||
String[] ids = groups [groupIndex].getComponentIds();
|
||||
|
||||
if (ids.length > 0) {
|
||||
generator.newInstance(ourButtonGroupType);
|
||||
generator.dup();
|
||||
generator.invokeConstructor(ourButtonGroupType, Method.getMethod("void <init>()"));
|
||||
generator.storeLocal(groupLocal);
|
||||
if (ids.length > 0) {
|
||||
generator.newInstance(ourButtonGroupType);
|
||||
generator.dup();
|
||||
generator.invokeConstructor(ourButtonGroupType, Method.getMethod("void <init>()"));
|
||||
generator.storeLocal(groupLocal);
|
||||
|
||||
if (groups [groupIndex].isBound() && !myIgnoreCustomCreation) {
|
||||
validateFieldClass(groups [groupIndex].getName(), ButtonGroup.class, null);
|
||||
generator.loadThis();
|
||||
generator.loadLocal(groupLocal);
|
||||
generator.putField(getMainClassType(), groups [groupIndex].getName(), ourButtonGroupType);
|
||||
}
|
||||
|
||||
for(int i = 0; i<ids.length; i++) {
|
||||
Integer localInt = (Integer) myIdToLocalMap.get(ids [i]);
|
||||
if (localInt != null) {
|
||||
if (groups [groupIndex].isBound() && !myIgnoreCustomCreation) {
|
||||
if (buttonGroupClass == null) {
|
||||
buttonGroupClass = myFinder.loadClass(ButtonGroup.class.getName());
|
||||
}
|
||||
validateFieldClass(groups [groupIndex].getName(), buttonGroupClass, null);
|
||||
generator.loadThis();
|
||||
generator.loadLocal(groupLocal);
|
||||
generator.loadLocal(localInt.intValue());
|
||||
generator.invokeVirtual(ourButtonGroupType, Method.getMethod("void add(javax.swing.AbstractButton)"));
|
||||
generator.putField(getMainClassType(), groups [groupIndex].getName(), ourButtonGroupType);
|
||||
}
|
||||
|
||||
for(int i = 0; i<ids.length; i++) {
|
||||
Integer localInt = (Integer) myIdToLocalMap.get(ids [i]);
|
||||
if (localInt != null) {
|
||||
generator.loadLocal(groupLocal);
|
||||
generator.loadLocal(localInt.intValue());
|
||||
generator.invokeVirtual(ourButtonGroupType, Method.getMethod("void add(javax.swing.AbstractButton)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new CodeGenerationException(rootContainer.getId(), e.getMessage(), e);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new CodeGenerationException(rootContainer.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,14 +784,14 @@ public class AsmCodeGenerator {
|
||||
return Type.getType("L" + myClassName + ";");
|
||||
}
|
||||
|
||||
private void validateFieldBinding(LwComponent component, final Class componentClass) throws CodeGenerationException {
|
||||
private void validateFieldBinding(LwComponent component, final InstrumentationClassFinder.PseudoClass componentClass) throws CodeGenerationException {
|
||||
String binding = component.getBinding();
|
||||
if (binding == null) return;
|
||||
|
||||
validateFieldClass(binding, componentClass, component.getId());
|
||||
}
|
||||
|
||||
private void validateFieldClass(String binding, Class componentClass, String componentId) throws CodeGenerationException {
|
||||
private void validateFieldClass(String binding, InstrumentationClassFinder.PseudoClass componentClass, String componentId) throws CodeGenerationException {
|
||||
if (!myFieldDescMap.containsKey(binding)) {
|
||||
throw new CodeGenerationException(componentId, "Cannot bind: field does not exist: " + myClassToBind + "." + binding);
|
||||
}
|
||||
@@ -773,15 +801,17 @@ public class AsmCodeGenerator {
|
||||
throw new CodeGenerationException(componentId, "Cannot bind: field is of primitive type: " + myClassToBind + "." + binding);
|
||||
}
|
||||
|
||||
Class fieldClass;
|
||||
try {
|
||||
fieldClass = myLoader.loadClass(fieldType.getClassName());
|
||||
final InstrumentationClassFinder.PseudoClass fieldClass = myFinder.loadClass(fieldType.getClassName());
|
||||
if (!fieldClass.isAssignableFrom(componentClass)) {
|
||||
throw new CodeGenerationException(componentId, "Cannot bind: Incompatible types. Cannot assign " + componentClass.getName().replace('/', '.') + " to field " + myClassToBind + "." + binding);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new CodeGenerationException(componentId, "Class not found: " + fieldType.getClassName());
|
||||
}
|
||||
if (!fieldClass.isAssignableFrom(componentClass)) {
|
||||
throw new CodeGenerationException(componentId, "Cannot bind: Incompatible types. Cannot assign " + componentClass.getName() + " to field " + myClassToBind + "." + binding);
|
||||
catch (IOException e) {
|
||||
throw new CodeGenerationException(componentId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.uiDesigner.compiler;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.uiDesigner.lw.FontDescriptor;
|
||||
import com.intellij.uiDesigner.lw.LwComponent;
|
||||
import com.intellij.uiDesigner.lw.LwIntrospectedProperty;
|
||||
@@ -41,7 +42,7 @@ public class FontPropertyCodeGenerator extends PropertyCodeGenerator {
|
||||
private static final Method ourGetStyleMethod = new Method("getStyle", Type.INT_TYPE, new Type[0] );
|
||||
|
||||
public boolean generateCustomSetValue(final LwComponent lwComponent,
|
||||
final Class componentClass,
|
||||
final InstrumentationClassFinder.PseudoClass componentClass,
|
||||
final LwIntrospectedProperty property,
|
||||
final GeneratorAdapter generator,
|
||||
final int componentLocal, final String formClassName) {
|
||||
|
||||
+6
-3
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package com.intellij.uiDesigner.compiler;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.uiDesigner.lw.LwComponent;
|
||||
import com.intellij.uiDesigner.lw.LwIntrospectedProperty;
|
||||
import org.objectweb.asm.commons.GeneratorAdapter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -26,13 +29,13 @@ public abstract class PropertyCodeGenerator {
|
||||
public abstract void generatePushValue(final GeneratorAdapter generator, final Object value);
|
||||
|
||||
public boolean generateCustomSetValue(final LwComponent lwComponent,
|
||||
final Class componentClass, final LwIntrospectedProperty property,
|
||||
final InstrumentationClassFinder.PseudoClass componentClass, final LwIntrospectedProperty property,
|
||||
final GeneratorAdapter generator,
|
||||
final int componentLocal, final String formClassName) {
|
||||
final int componentLocal, final String formClassName) throws IOException, ClassNotFoundException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void generateClassStart(AsmCodeGenerator.FormClassVisitor visitor, final String name, final ClassLoader loader) {
|
||||
public void generateClassStart(AsmCodeGenerator.FormClassVisitor visitor, final String name, final InstrumentationClassFinder classFinder) {
|
||||
}
|
||||
|
||||
public void generateClassEnd(AsmCodeGenerator.FormClassVisitor visitor) {
|
||||
|
||||
+16
-12
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.uiDesigner.compiler;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.uiDesigner.core.SupportCode;
|
||||
import com.intellij.uiDesigner.lw.LwComponent;
|
||||
import com.intellij.uiDesigner.lw.LwIntrospectedProperty;
|
||||
@@ -27,9 +28,10 @@ import org.objectweb.asm.commons.GeneratorAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -47,12 +49,12 @@ public class StringPropertyCodeGenerator extends PropertyCodeGenerator implement
|
||||
private final Set myClassesRequiringLoadButtonText = new HashSet();
|
||||
private boolean myHaveSetDisplayedMnemonicIndex = false;
|
||||
|
||||
public void generateClassStart(AsmCodeGenerator.FormClassVisitor visitor, final String name, final ClassLoader loader) {
|
||||
public void generateClassStart(AsmCodeGenerator.FormClassVisitor visitor, final String name, final InstrumentationClassFinder classFinder) {
|
||||
myClassesRequiringLoadLabelText.remove(name);
|
||||
myClassesRequiringLoadButtonText.remove(name);
|
||||
try {
|
||||
Class c = loader.loadClass(AbstractButton.class.getName());
|
||||
if (c.getMethod("getDisplayedMnemonicIndex", new Class[0]) != null) {
|
||||
InstrumentationClassFinder.PseudoClass pseudo = classFinder.loadClass(AbstractButton.class.getName());
|
||||
if (!pseudo.findMethods("getDisplayedMnemonicIndex").isEmpty()) {
|
||||
myHaveSetDisplayedMnemonicIndex = true;
|
||||
}
|
||||
}
|
||||
@@ -62,25 +64,27 @@ public class StringPropertyCodeGenerator extends PropertyCodeGenerator implement
|
||||
}
|
||||
|
||||
public boolean generateCustomSetValue(final LwComponent lwComponent,
|
||||
final Class componentClass,
|
||||
final InstrumentationClassFinder.PseudoClass componentClass,
|
||||
final LwIntrospectedProperty property,
|
||||
final GeneratorAdapter generator,
|
||||
final int componentLocal,
|
||||
final String formClassName) {
|
||||
final String formClassName) throws IOException, ClassNotFoundException {
|
||||
final InstrumentationClassFinder.PseudoClass abstractButtonClass = componentClass.getFinder().loadClass(AbstractButton.class.getName());
|
||||
final InstrumentationClassFinder.PseudoClass jLabelClass = componentClass.getFinder().loadClass(JLabel.class.getName());
|
||||
if ("text".equals(property.getName()) &&
|
||||
(AbstractButton.class.isAssignableFrom(componentClass) || JLabel.class.isAssignableFrom(componentClass))) {
|
||||
(abstractButtonClass.isAssignableFrom(componentClass) || jLabelClass.isAssignableFrom(componentClass))) {
|
||||
final StringDescriptor propertyValue = (StringDescriptor)lwComponent.getPropertyValue(property);
|
||||
if (propertyValue.getValue() != null) {
|
||||
final SupportCode.TextWithMnemonic textWithMnemonic = SupportCode.parseText(propertyValue.getValue());
|
||||
if (textWithMnemonic.myMnemonicIndex >= 0) {
|
||||
generator.loadLocal(componentLocal);
|
||||
generator.push(textWithMnemonic.myText);
|
||||
generator.invokeVirtual(Type.getType(componentClass),
|
||||
generator.invokeVirtual(Type.getType(componentClass.getDescriptor()),
|
||||
new Method(property.getWriteMethodName(),
|
||||
Type.VOID_TYPE, new Type[] { Type.getType(String.class) } ));
|
||||
|
||||
String setMnemonicMethodName;
|
||||
if (AbstractButton.class.isAssignableFrom(componentClass)) {
|
||||
if (abstractButtonClass.isAssignableFrom(componentClass)) {
|
||||
setMnemonicMethodName = "setMnemonic";
|
||||
}
|
||||
else {
|
||||
@@ -89,14 +93,14 @@ public class StringPropertyCodeGenerator extends PropertyCodeGenerator implement
|
||||
|
||||
generator.loadLocal(componentLocal);
|
||||
generator.push(textWithMnemonic.getMnemonicChar());
|
||||
generator.invokeVirtual(Type.getType(componentClass),
|
||||
generator.invokeVirtual(Type.getType(componentClass.getDescriptor()),
|
||||
new Method(setMnemonicMethodName,
|
||||
Type.VOID_TYPE, new Type[] { Type.CHAR_TYPE } ));
|
||||
|
||||
if (myHaveSetDisplayedMnemonicIndex) {
|
||||
generator.loadLocal(componentLocal);
|
||||
generator.push(textWithMnemonic.myMnemonicIndex);
|
||||
generator.invokeVirtual(Type.getType(componentClass),
|
||||
generator.invokeVirtual(Type.getType(componentClass.getDescriptor()),
|
||||
new Method("setDisplayedMnemonicIndex",
|
||||
Type.VOID_TYPE, new Type[] { Type.INT_TYPE } ));
|
||||
}
|
||||
@@ -105,7 +109,7 @@ public class StringPropertyCodeGenerator extends PropertyCodeGenerator implement
|
||||
}
|
||||
else {
|
||||
Method method;
|
||||
if (AbstractButton.class.isAssignableFrom(componentClass)) {
|
||||
if (abstractButtonClass.isAssignableFrom(componentClass)) {
|
||||
myClassesRequiringLoadButtonText.add(formClassName);
|
||||
method = myLoadButtonTextMethod;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.uiDesigner.compiler;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.uiDesigner.core.GridConstraints;
|
||||
import com.intellij.uiDesigner.lw.*;
|
||||
import org.jdom.Document;
|
||||
@@ -28,6 +29,7 @@ import javax.swing.*;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -43,306 +45,323 @@ import java.util.Set;
|
||||
* NOTE: the class must be compilable with JDK 1.3, so any methods and filds introduced in 1.4 or later must not be used
|
||||
*/
|
||||
public final class Utils {
|
||||
public static final String FORM_NAMESPACE = "http://www.intellij.com/uidesigner/form/";
|
||||
private static final SAXParser SAX_PARSER = createParser();
|
||||
public static final String FORM_NAMESPACE = "http://www.intellij.com/uidesigner/form/";
|
||||
private static final SAXParser SAX_PARSER = createParser();
|
||||
|
||||
private Utils() {
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
private static SAXParser createParser() {
|
||||
try {
|
||||
return SAXParserFactory.newInstance().newSAXParser();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param provider if null, no classes loaded and no properties read
|
||||
*/
|
||||
public static LwRootContainer getRootContainer(final String formFileContent, final PropertiesProvider provider) throws Exception {
|
||||
if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
|
||||
throw new AlienFormFileException();
|
||||
}
|
||||
|
||||
private static SAXParser createParser() {
|
||||
try {
|
||||
return SAXParserFactory.newInstance().newSAXParser();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
final Document document = new SAXBuilder().build(new StringReader(formFileContent), "UTF-8");
|
||||
|
||||
return getRootContainerFromDocument(document, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get root from the url
|
||||
*
|
||||
* @param formFile the document URL
|
||||
* @param provider the provider
|
||||
* @return the root container
|
||||
* @throws Exception if there is a problem with parsing DOM
|
||||
*/
|
||||
public static LwRootContainer getRootContainer(final URL formFile, final PropertiesProvider provider) throws Exception {
|
||||
final Document document = new SAXBuilder().build(formFile);
|
||||
return getRootContainerFromDocument(document, provider);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get root from the document
|
||||
*
|
||||
* @param document the parsed document
|
||||
* @param provider the provider
|
||||
* @return the root container
|
||||
* @throws Exception if there is a problem with parsing DOM
|
||||
*/
|
||||
private static LwRootContainer getRootContainerFromDocument(Document document, PropertiesProvider provider) throws Exception {
|
||||
final LwRootContainer root = new LwRootContainer();
|
||||
root.read(document.getRootElement(), provider);
|
||||
return root;
|
||||
}
|
||||
|
||||
public static LwRootContainer getRootContainer(final InputStream stream, final PropertiesProvider provider) throws Exception {
|
||||
final Document document = new SAXBuilder().build(stream, "UTF-8");
|
||||
|
||||
return getRootContainerFromDocument(document, provider);
|
||||
}
|
||||
|
||||
public synchronized static String getBoundClassName(final String formFileContent) throws Exception {
|
||||
if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
|
||||
throw new AlienFormFileException();
|
||||
}
|
||||
|
||||
final String[] className = new String[]{null};
|
||||
try {
|
||||
SAX_PARSER.parse(new InputSource(new StringReader(formFileContent)), new DefaultHandler() {
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if ("form".equals(qName)) {
|
||||
className[0] = attributes.getValue("", "bind-to-class");
|
||||
throw new SAXException("stop parsing");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param provider if null, no classes loaded and no properties read
|
||||
*/
|
||||
public static LwRootContainer getRootContainer(final String formFileContent, final PropertiesProvider provider) throws Exception {
|
||||
if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
|
||||
throw new AlienFormFileException();
|
||||
}
|
||||
return className[0];
|
||||
}
|
||||
|
||||
final Document document = new SAXBuilder().build(new StringReader(formFileContent), "UTF-8");
|
||||
|
||||
return getRootContainerFromDocument(document, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get root from the url
|
||||
*
|
||||
* @param formFile the document URL
|
||||
* @param provider the provider
|
||||
* @return the root container
|
||||
* @throws Exception if there is a problem with parsing DOM
|
||||
*/
|
||||
public static LwRootContainer getRootContainer(final URL formFile, final PropertiesProvider provider) throws Exception {
|
||||
final Document document = new SAXBuilder().build(formFile);
|
||||
return getRootContainerFromDocument(document, provider);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get root from the document
|
||||
*
|
||||
* @param document the parsed document
|
||||
* @param provider the provider
|
||||
* @return the root container
|
||||
* @throws Exception if there is a problem with parsing DOM
|
||||
*/
|
||||
private static LwRootContainer getRootContainerFromDocument(Document document, PropertiesProvider provider) throws Exception {
|
||||
final LwRootContainer root = new LwRootContainer();
|
||||
root.read(document.getRootElement(), provider);
|
||||
return root;
|
||||
}
|
||||
|
||||
public static LwRootContainer getRootContainer(final InputStream stream, final PropertiesProvider provider) throws Exception {
|
||||
final Document document = new SAXBuilder().build(stream, "UTF-8");
|
||||
|
||||
return getRootContainerFromDocument(document, provider);
|
||||
}
|
||||
|
||||
public synchronized static String getBoundClassName(final String formFileContent) throws Exception {
|
||||
if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
|
||||
throw new AlienFormFileException();
|
||||
}
|
||||
|
||||
final String[] className = new String[]{null};
|
||||
try {
|
||||
SAX_PARSER.parse(new InputSource(new StringReader(formFileContent)), new DefaultHandler() {
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if ("form".equals(qName)) {
|
||||
className[0] = attributes.getValue("", "bind-to-class");
|
||||
throw new SAXException("stop parsing");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
return className[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that specified class represents {@link javax.swing.JComponent} with
|
||||
* empty constructor.
|
||||
*
|
||||
* @return descriptive human readable error message or <code>null</code> if
|
||||
* no errors were detected.
|
||||
*/
|
||||
/**
|
||||
* Validates that specified class represents {@link javax.swing.JComponent} with
|
||||
* empty constructor.
|
||||
*
|
||||
* @return descriptive human readable error message or <code>null</code> if
|
||||
* no errors were detected.
|
||||
*/
|
||||
public static String validateJComponentClass(final ClassLoader loader, final String className, final boolean validateConstructor) {
|
||||
if (loader == null) {
|
||||
throw new IllegalArgumentException("loader cannot be null");
|
||||
}
|
||||
if (className == null) {
|
||||
throw new IllegalArgumentException("className cannot be null");
|
||||
}
|
||||
throw new IllegalArgumentException("loader cannot be null");
|
||||
}
|
||||
if (className == null) {
|
||||
throw new IllegalArgumentException("className cannot be null");
|
||||
}
|
||||
|
||||
// These classes are not visible for passed class loader!
|
||||
if ("com.intellij.uiDesigner.HSpacer".equals(className) || "com.intellij.uiDesigner.VSpacer".equals(className)) {
|
||||
return null;
|
||||
}
|
||||
// These classes are not visible for passed class loader!
|
||||
if ("com.intellij.uiDesigner.HSpacer".equals(className) || "com.intellij.uiDesigner.VSpacer".equals(className)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class aClass;
|
||||
try {
|
||||
try {
|
||||
aClass = Class.forName(className, false, loader);
|
||||
}
|
||||
catch (final ClassNotFoundException exc) {
|
||||
return "Class \"" + className + "\"not found";
|
||||
}
|
||||
catch (NoClassDefFoundError exc) {
|
||||
return "Cannot load class " + className + ": " + exc.getMessage();
|
||||
}
|
||||
catch (ExceptionInInitializerError exc) {
|
||||
return "Cannot initialize class " + className + ": " + exc.getMessage();
|
||||
}
|
||||
catch (UnsupportedClassVersionError exc) {
|
||||
return "Unsupported class version error: " + className;
|
||||
}
|
||||
}
|
||||
catch (final ClassNotFoundException exc) {
|
||||
return "Class \"" + className + "\"not found";
|
||||
}
|
||||
catch (NoClassDefFoundError exc) {
|
||||
return "Cannot load class " + className + ": " + exc.getMessage();
|
||||
}
|
||||
catch (ExceptionInInitializerError exc) {
|
||||
return "Cannot initialize class " + className + ": " + exc.getMessage();
|
||||
}
|
||||
catch (UnsupportedClassVersionError exc) {
|
||||
return "Unsupported class version error: " + className;
|
||||
}
|
||||
|
||||
if (validateConstructor) {
|
||||
if (validateConstructor) {
|
||||
try {
|
||||
final Constructor constructor = aClass.getConstructor(new Class[0]);
|
||||
if ((constructor.getModifiers() & Modifier.PUBLIC) == 0) {
|
||||
return "Class \"" + className + "\" does not have default public constructor";
|
||||
}
|
||||
}
|
||||
return "Class \"" + className + "\" does not have default public constructor";
|
||||
}
|
||||
}
|
||||
catch (final Exception exc) {
|
||||
return "Class \"" + className + "\" does not have default constructor";
|
||||
}
|
||||
}
|
||||
|
||||
// Check that JComponent is accessible via the loader
|
||||
// Check that JComponent is accessible via the loader
|
||||
|
||||
if (!JComponent.class.isAssignableFrom(aClass)) {
|
||||
return "Class \"" + className + "\" is not an instance of javax.swing.JComponent";
|
||||
}
|
||||
return "Class \"" + className + "\" is not an instance of javax.swing.JComponent";
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader)
|
||||
throws CodeGenerationException, RecursiveFormNestingException {
|
||||
validateNestedFormLoop(formName, nestedFormLoader, null);
|
||||
}
|
||||
|
||||
public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader, final String targetForm)
|
||||
throws CodeGenerationException, RecursiveFormNestingException {
|
||||
HashSet usedFormNames = new HashSet();
|
||||
if (targetForm != null) {
|
||||
usedFormNames.add(targetForm);
|
||||
}
|
||||
validateNestedFormLoop(usedFormNames, formName, nestedFormLoader);
|
||||
}
|
||||
|
||||
public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader)
|
||||
throws CodeGenerationException, RecursiveFormNestingException {
|
||||
validateNestedFormLoop(formName, nestedFormLoader, null);
|
||||
private static void validateNestedFormLoop(final Set usedFormNames, final String formName, final NestedFormLoader nestedFormLoader)
|
||||
throws CodeGenerationException, RecursiveFormNestingException {
|
||||
if (usedFormNames.contains(formName)) {
|
||||
throw new RecursiveFormNestingException();
|
||||
}
|
||||
|
||||
public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader, final String targetForm)
|
||||
throws CodeGenerationException, RecursiveFormNestingException {
|
||||
HashSet usedFormNames = new HashSet();
|
||||
if (targetForm != null) {
|
||||
usedFormNames.add(targetForm);
|
||||
}
|
||||
validateNestedFormLoop(usedFormNames, formName, nestedFormLoader);
|
||||
usedFormNames.add(formName);
|
||||
final LwRootContainer rootContainer;
|
||||
try {
|
||||
rootContainer = nestedFormLoader.loadForm(formName);
|
||||
}
|
||||
|
||||
private static void validateNestedFormLoop(final Set usedFormNames, final String formName, final NestedFormLoader nestedFormLoader)
|
||||
throws CodeGenerationException, RecursiveFormNestingException {
|
||||
if (usedFormNames.contains(formName)) {
|
||||
throw new RecursiveFormNestingException();
|
||||
}
|
||||
usedFormNames.add(formName);
|
||||
final LwRootContainer rootContainer;
|
||||
try {
|
||||
rootContainer = nestedFormLoader.loadForm(formName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CodeGenerationException(null, "Error loading nested form: " + e.getMessage(), e);
|
||||
}
|
||||
final Set thisFormNestedForms = new HashSet();
|
||||
final CodeGenerationException[] validateExceptions = new CodeGenerationException[1];
|
||||
final RecursiveFormNestingException[] recursiveNestingExceptions = new RecursiveFormNestingException[1];
|
||||
rootContainer.accept(new ComponentVisitor() {
|
||||
public boolean visit(final IComponent component) {
|
||||
if (component instanceof LwNestedForm) {
|
||||
LwNestedForm nestedForm = (LwNestedForm)component;
|
||||
if (!thisFormNestedForms.contains(nestedForm.getFormFileName())) {
|
||||
thisFormNestedForms.add(nestedForm.getFormFileName());
|
||||
try {
|
||||
validateNestedFormLoop(usedFormNames, nestedForm.getFormFileName(), nestedFormLoader);
|
||||
}
|
||||
catch (RecursiveFormNestingException e) {
|
||||
recursiveNestingExceptions[0] = e;
|
||||
return false;
|
||||
}
|
||||
catch (CodeGenerationException e) {
|
||||
validateExceptions[0] = e;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (recursiveNestingExceptions[0] != null) {
|
||||
throw recursiveNestingExceptions[0];
|
||||
}
|
||||
if (validateExceptions[0] != null) {
|
||||
throw validateExceptions[0];
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CodeGenerationException(null, "Error loading nested form: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
public static String findNotEmptyPanelWithXYLayout(final IComponent component) {
|
||||
if (!(component instanceof IContainer)) {
|
||||
return null;
|
||||
}
|
||||
final IContainer container = (IContainer)component;
|
||||
if (container.getComponentCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (container.isXY()) {
|
||||
return container.getId();
|
||||
}
|
||||
for (int i = 0; i < container.getComponentCount(); i++) {
|
||||
String id = findNotEmptyPanelWithXYLayout(container.getComponent(i));
|
||||
if (id != null) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getHGap(LayoutManager layout) {
|
||||
if (layout instanceof BorderLayout) {
|
||||
return ((BorderLayout)layout).getHgap();
|
||||
}
|
||||
if (layout instanceof CardLayout) {
|
||||
return ((CardLayout)layout).getHgap();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getVGap(LayoutManager layout) {
|
||||
if (layout instanceof BorderLayout) {
|
||||
return ((BorderLayout)layout).getVgap();
|
||||
}
|
||||
if (layout instanceof CardLayout) {
|
||||
return ((CardLayout)layout).getVgap();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getCustomCreateComponentCount(final IContainer container) {
|
||||
final int[] result = new int[1];
|
||||
result[0] = 0;
|
||||
container.accept(new ComponentVisitor() {
|
||||
public boolean visit(IComponent c) {
|
||||
if (c.isCustomCreate()) {
|
||||
result[0]++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
}
|
||||
|
||||
public static Class suggestReplacementClass(Class componentClass) {
|
||||
while (true) {
|
||||
componentClass = componentClass.getSuperclass();
|
||||
if (componentClass.equals(JComponent.class)) {
|
||||
return JPanel.class;
|
||||
}
|
||||
if ((componentClass.getModifiers() & (Modifier.ABSTRACT | Modifier.PRIVATE)) != 0) {
|
||||
continue;
|
||||
}
|
||||
final Set thisFormNestedForms = new HashSet();
|
||||
final CodeGenerationException[] validateExceptions = new CodeGenerationException[1];
|
||||
final RecursiveFormNestingException[] recursiveNestingExceptions = new RecursiveFormNestingException[1];
|
||||
rootContainer.accept(new ComponentVisitor() {
|
||||
public boolean visit(final IComponent component) {
|
||||
if (component instanceof LwNestedForm) {
|
||||
LwNestedForm nestedForm = (LwNestedForm)component;
|
||||
if (!thisFormNestedForms.contains(nestedForm.getFormFileName())) {
|
||||
thisFormNestedForms.add(nestedForm.getFormFileName());
|
||||
try {
|
||||
componentClass.getConstructor(new Class[]{});
|
||||
validateNestedFormLoop(usedFormNames, nestedForm.getFormFileName(), nestedFormLoader);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
continue;
|
||||
catch (RecursiveFormNestingException e) {
|
||||
recursiveNestingExceptions[0] = e;
|
||||
return false;
|
||||
}
|
||||
return componentClass;
|
||||
catch (CodeGenerationException e) {
|
||||
validateExceptions[0] = e;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (recursiveNestingExceptions[0] != null) {
|
||||
throw recursiveNestingExceptions[0];
|
||||
}
|
||||
if (validateExceptions[0] != null) {
|
||||
throw validateExceptions[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static int alignFromConstraints(final GridConstraints gc, final boolean horizontal) {
|
||||
int anchor = gc.getAnchor();
|
||||
int fill = gc.getFill();
|
||||
int leftMask = horizontal ? GridConstraints.ANCHOR_WEST : GridConstraints.ANCHOR_NORTH;
|
||||
int rightMask = horizontal ? GridConstraints.ANCHOR_EAST : GridConstraints.ANCHOR_SOUTH;
|
||||
int fillMask = horizontal ? GridConstraints.FILL_HORIZONTAL : GridConstraints.FILL_VERTICAL;
|
||||
if ((fill & fillMask) != 0) return GridConstraints.ALIGN_FILL;
|
||||
if ((anchor & rightMask) != 0) return GridConstraints.ALIGN_RIGHT;
|
||||
if ((anchor & leftMask) != 0) return GridConstraints.ALIGN_LEFT;
|
||||
return GridConstraints.ALIGN_CENTER;
|
||||
public static String findNotEmptyPanelWithXYLayout(final IComponent component) {
|
||||
if (!(component instanceof IContainer)) {
|
||||
return null;
|
||||
}
|
||||
final IContainer container = (IContainer)component;
|
||||
if (container.getComponentCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (container.isXY()) {
|
||||
return container.getId();
|
||||
}
|
||||
for (int i = 0; i < container.getComponentCount(); i++) {
|
||||
String id = findNotEmptyPanelWithXYLayout(container.getComponent(i));
|
||||
if (id != null) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isBoundField(IComponent component, String fieldName) {
|
||||
if (fieldName.equals(component.getBinding())) {
|
||||
return true;
|
||||
}
|
||||
if (component instanceof IContainer) {
|
||||
IContainer container = (IContainer)component;
|
||||
for (int i = 0; i < container.getComponentCount(); i++) {
|
||||
if (isBoundField(container.getComponent(i), fieldName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public static int getHGap(LayoutManager layout) {
|
||||
if (layout instanceof BorderLayout) {
|
||||
return ((BorderLayout)layout).getHgap();
|
||||
}
|
||||
if (layout instanceof CardLayout) {
|
||||
return ((CardLayout)layout).getHgap();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getVGap(LayoutManager layout) {
|
||||
if (layout instanceof BorderLayout) {
|
||||
return ((BorderLayout)layout).getVgap();
|
||||
}
|
||||
if (layout instanceof CardLayout) {
|
||||
return ((CardLayout)layout).getVgap();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getCustomCreateComponentCount(final IContainer container) {
|
||||
final int[] result = new int[1];
|
||||
result[0] = 0;
|
||||
container.accept(new ComponentVisitor() {
|
||||
public boolean visit(IComponent c) {
|
||||
if (c.isCustomCreate()) {
|
||||
result[0]++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
}
|
||||
|
||||
public static Class suggestReplacementClass(Class componentClass) {
|
||||
while (true) {
|
||||
componentClass = componentClass.getSuperclass();
|
||||
if (componentClass.equals(JComponent.class)) {
|
||||
return JPanel.class;
|
||||
}
|
||||
if ((componentClass.getModifiers() & (Modifier.ABSTRACT | Modifier.PRIVATE)) != 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
componentClass.getConstructor(new Class[]{});
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
continue;
|
||||
}
|
||||
return componentClass;
|
||||
}
|
||||
}
|
||||
|
||||
public static InstrumentationClassFinder.PseudoClass suggestReplacementClass(InstrumentationClassFinder.PseudoClass componentClass) throws ClassNotFoundException, IOException {
|
||||
final InstrumentationClassFinder.PseudoClass jComponentClass = componentClass.getFinder().loadClass(JComponent.class.getName());
|
||||
while (true) {
|
||||
componentClass = componentClass.getSuperClass();
|
||||
if (componentClass.equals(jComponentClass)) {
|
||||
return componentClass.getFinder().loadClass(JPanel.class.getName());
|
||||
}
|
||||
if ((componentClass.getModifiers() & (Modifier.ABSTRACT | Modifier.PRIVATE)) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (!componentClass.hasDefaultPublicConstructor()) {
|
||||
continue;
|
||||
}
|
||||
return componentClass;
|
||||
}
|
||||
}
|
||||
|
||||
public static int alignFromConstraints(final GridConstraints gc, final boolean horizontal) {
|
||||
int anchor = gc.getAnchor();
|
||||
int fill = gc.getFill();
|
||||
int leftMask = horizontal ? GridConstraints.ANCHOR_WEST : GridConstraints.ANCHOR_NORTH;
|
||||
int rightMask = horizontal ? GridConstraints.ANCHOR_EAST : GridConstraints.ANCHOR_SOUTH;
|
||||
int fillMask = horizontal ? GridConstraints.FILL_HORIZONTAL : GridConstraints.FILL_VERTICAL;
|
||||
if ((fill & fillMask) != 0) return GridConstraints.ALIGN_FILL;
|
||||
if ((anchor & rightMask) != 0) return GridConstraints.ALIGN_RIGHT;
|
||||
if ((anchor & leftMask) != 0) return GridConstraints.ALIGN_LEFT;
|
||||
return GridConstraints.ALIGN_CENTER;
|
||||
}
|
||||
|
||||
public static boolean isBoundField(IComponent component, String fieldName) {
|
||||
if (fieldName.equals(component.getBinding())) {
|
||||
return true;
|
||||
}
|
||||
if (component instanceof IContainer) {
|
||||
IContainer container = (IContainer)component;
|
||||
for (int i = 0; i < container.getComponentCount(); i++) {
|
||||
if (isBoundField(container.getComponent(i), fieldName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<orderEntry type="module" module-name="openapi" />
|
||||
<orderEntry type="library" name="Trove4j" level="project" />
|
||||
<orderEntry type="module" module-name="java-runtime" />
|
||||
<orderEntry type="module" module-name="notNull" />
|
||||
<orderEntry type="module" module-name="instrumentation-util" />
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="library" name="Eclipse" level="project" />
|
||||
<orderEntry type="module" module-name="platform-api" />
|
||||
|
||||
@@ -70,8 +70,7 @@ import org.jetbrains.jps.client.CompileServerClient;
|
||||
import org.jetbrains.jps.server.ClasspathBootstrap;
|
||||
import org.jetbrains.jps.server.Server;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -586,6 +585,10 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
cmdLine.addParameter("-XX:ReservedCodeCacheSize=64m");
|
||||
cmdLine.addParameter("-Xmx" + Registry.intValue("compiler.server.heap.size") + "m");
|
||||
cmdLine.addParameter("-Djava.awt.headless=true");
|
||||
final String shouldGenerateIndex = System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION);
|
||||
if (shouldGenerateIndex != null) {
|
||||
cmdLine.addParameter("-D"+ GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION +"=" + shouldGenerateIndex);
|
||||
}
|
||||
//noinspection ConstantConditions
|
||||
if (pingInterval > 0L) {
|
||||
cmdLine.addParameter("-D" + GlobalOptions.PING_INTERVAL_MS_OPTION + "=" + pingInterval);
|
||||
|
||||
@@ -27,6 +27,7 @@ import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
@@ -145,6 +146,18 @@ class CompAPIDriver {
|
||||
assert !processing;
|
||||
//assert myCompilationResults.isEmpty() : myCompilationResults;
|
||||
myCompilationResults.clear();
|
||||
cleanupInternalFields();
|
||||
}
|
||||
|
||||
private static void cleanupInternalFields() {
|
||||
try {
|
||||
Field freelist = Class.forName("com.sun.tools.javac.util.SharedNameTable").getDeclaredField("freelist");
|
||||
freelist.setAccessible(true);
|
||||
freelist.set(null, com.sun.tools.javac.util.List.nil());
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void offerClassFile(URI uri, byte[] bytes) {
|
||||
|
||||
+194
-37
@@ -1,10 +1,7 @@
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
package com.intellij.compiler.instrumentation;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.EmptyVisitor;
|
||||
import sun.misc.Resource;
|
||||
@@ -12,6 +9,7 @@ import sun.misc.Resource;
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
@@ -23,22 +21,81 @@ import java.util.zip.ZipFile;
|
||||
public class InstrumentationClassFinder {
|
||||
private static final PseudoClass[] EMPTY_PSEUDOCLASS_ARRAY = new PseudoClass[0];
|
||||
private static final String CLASS_RESOURCE_EXTENSION = ".class";
|
||||
private static final URL[] URL_EMPTY_ARRAY = new URL[0];
|
||||
private final Map<String, PseudoClass> myLoaded = new HashMap<String, PseudoClass>(); // className -> class object
|
||||
private final ClassFinderClasspath myPlatformClasspath;
|
||||
private final ClassFinderClasspath myClasspath;
|
||||
private final URL[] myPlatformUrls;
|
||||
private final URL[] myClasspathUrls;
|
||||
private ClassLoader myLoader;
|
||||
private byte[] myBuffer;
|
||||
|
||||
public InstrumentationClassFinder(final URL[] platformClasspath, final URL[] classpath) {
|
||||
myPlatformClasspath = new ClassFinderClasspath(platformClasspath);
|
||||
myClasspath = new ClassFinderClasspath(classpath);
|
||||
public InstrumentationClassFinder(final URL[] cp) {
|
||||
this(URL_EMPTY_ARRAY, cp);
|
||||
}
|
||||
|
||||
public InstrumentationClassFinder(final URL[] platformUrls, final URL[] classpathUrls) {
|
||||
myPlatformUrls = platformUrls;
|
||||
myClasspathUrls = classpathUrls;
|
||||
myPlatformClasspath = new ClassFinderClasspath(platformUrls);
|
||||
myClasspath = new ClassFinderClasspath(classpathUrls);
|
||||
}
|
||||
|
||||
// compatibility with legacy code requiring ClassLoader
|
||||
public ClassLoader getLoader() {
|
||||
ClassLoader loader = myLoader;
|
||||
if (loader != null) {
|
||||
return loader;
|
||||
}
|
||||
final URLClassLoader platformLoader = myPlatformUrls.length > 0 ? new URLClassLoader(myPlatformUrls, null) : null;
|
||||
final ClassLoader cpLoader = new URLClassLoader(myClasspathUrls, platformLoader);
|
||||
loader = new ClassLoader(cpLoader) {
|
||||
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
InputStream is = null;
|
||||
is = super.getResourceAsStream(name);
|
||||
if (is == null) {
|
||||
try {
|
||||
is = InstrumentationClassFinder.this.getResourceAsStream(name);
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
protected Class findClass(String name) throws ClassNotFoundException {
|
||||
final InputStream is = lookupClassBeforeClasspath(name.replace('.', '/'));
|
||||
if (is == null) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
try {
|
||||
final byte[] bytes = loadBytes(is);
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
is.close();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
myLoader = loader;
|
||||
return loader;
|
||||
}
|
||||
|
||||
public void releaseResources() {
|
||||
myPlatformClasspath.releaseResources();
|
||||
myClasspath.releaseResources();
|
||||
myLoaded.clear();
|
||||
myBuffer = null;
|
||||
myLoader = null;
|
||||
}
|
||||
|
||||
public PseudoClass loadClass(final String internalName) throws IOException, ClassNotFoundException{
|
||||
public PseudoClass loadClass(final String name) throws IOException, ClassNotFoundException{
|
||||
final String internalName = name.replace('.', '/'); // normalize
|
||||
final PseudoClass aClass = myLoaded.get(internalName);
|
||||
if (aClass != null) {
|
||||
return aClass;
|
||||
@@ -81,12 +138,28 @@ public class InstrumentationClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InputStream getResourceAsStream(String resourceName) throws IOException {
|
||||
InputStream is = null;
|
||||
|
||||
Resource resource = myPlatformClasspath.getResource(resourceName, false);
|
||||
if (resource != null) {
|
||||
is = resource.getInputStream();
|
||||
}
|
||||
|
||||
if (is == null) {
|
||||
resource = myClasspath.getResource(resourceName, false);
|
||||
if (resource != null) {
|
||||
is = resource.getInputStream();
|
||||
}
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
protected InputStream lookupClassBeforeClasspath(final String internalClassName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected InputStream lookupClassAfterClasspath(final String internalClassName) {
|
||||
return null;
|
||||
}
|
||||
@@ -97,20 +170,61 @@ public class InstrumentationClassFinder {
|
||||
|
||||
reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
|
||||
return new PseudoClass(visitor.myName, visitor.mySuperclassName, visitor.myInterfaces, visitor.myIsInterface);
|
||||
return new PseudoClass(visitor.myName, visitor.mySuperclassName, visitor.myInterfaces, visitor.myModifiers, visitor.myMethods);
|
||||
}
|
||||
|
||||
public final class PseudoClass {
|
||||
private final String myName;
|
||||
private final String mySuperClass;
|
||||
private final String[] myInterfaces;
|
||||
private final boolean isInterface;
|
||||
private final int myModifiers;
|
||||
private final List<PseudoMethod> myMethods;
|
||||
|
||||
private PseudoClass(final String name, final String superClass, final String[] interfaces, final boolean anInterface) {
|
||||
private PseudoClass(final String name, final String superClass, final String[] interfaces, final int modifiers, List<PseudoMethod> methods) {
|
||||
myName = name;
|
||||
mySuperClass = superClass;
|
||||
myInterfaces = interfaces;
|
||||
isInterface = anInterface;
|
||||
myModifiers = modifiers;
|
||||
myMethods = methods;
|
||||
}
|
||||
|
||||
public int getModifiers() {
|
||||
return myModifiers;
|
||||
}
|
||||
|
||||
public boolean isInterface() {
|
||||
return (myModifiers & Opcodes.ACC_INTERFACE) > 0;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public List<PseudoMethod> getMethods() {
|
||||
return myMethods;
|
||||
}
|
||||
|
||||
public List<PseudoMethod> findMethods(String name) {
|
||||
final List<PseudoMethod> result = new ArrayList<PseudoMethod>();
|
||||
for (PseudoMethod method : myMethods) {
|
||||
if (method.getName().equals(name)){
|
||||
result.add(method);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public PseudoMethod findMethod(String name, String descriptor) {
|
||||
for (PseudoMethod method : myMethods) {
|
||||
if (method.getName().equals(name) && method.getSignature().equals(descriptor)){
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public InstrumentationClassFinder getFinder() {
|
||||
return InstrumentationClassFinder.this;
|
||||
}
|
||||
|
||||
public PseudoClass getSuperClass() throws IOException, ClassNotFoundException {
|
||||
@@ -173,36 +287,69 @@ public class InstrumentationClassFinder {
|
||||
if (x.implementsInterface(this)) {
|
||||
return true;
|
||||
}
|
||||
if (x.isInterface() && getName().equals("java/lang/Object")) {
|
||||
if (x.isInterface() && "java/lang/Object".equals(getName())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isInterface() {
|
||||
return isInterface;
|
||||
public boolean hasDefaultPublicConstructor() {
|
||||
for (PseudoMethod method : myMethods) {
|
||||
if ("<init>".equals(method.getName()) && "()V".equals(method.getSignature())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return "L" + myName + ";";
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PseudoMethod {
|
||||
private final int myAccess;
|
||||
private final String myName;
|
||||
private final String mySignature;
|
||||
|
||||
public PseudoMethod(int access, String name, String signature) {
|
||||
myAccess = access;
|
||||
myName = name;
|
||||
mySignature = signature;
|
||||
}
|
||||
|
||||
public int getModifiers() {
|
||||
return myAccess;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return mySignature;
|
||||
}
|
||||
}
|
||||
|
||||
private static class V extends EmptyVisitor {
|
||||
public String mySuperclassName = null;
|
||||
public String[] myInterfaces = null;
|
||||
public String myName = null;
|
||||
public boolean myIsInterface = false;
|
||||
public int myModifiers;
|
||||
private final List<PseudoMethod> myMethods = new ArrayList<PseudoMethod>();
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
super.visitAttribute(attr);
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if ((access & Opcodes.ACC_PUBLIC) > 0) {
|
||||
myMethods.add(new PseudoMethod(access, name, desc));
|
||||
}
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
public void visit(int version, int access, String pName, String signature, String pSuperName, String[] pInterfaces) {
|
||||
mySuperclassName = pSuperName;
|
||||
myInterfaces = pInterfaces;
|
||||
myName = pName;
|
||||
myIsInterface = (access & Opcodes.ACC_INTERFACE) > 0;
|
||||
myModifiers = access;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +368,6 @@ public class InstrumentationClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Resource getResource(String s, boolean flag) {
|
||||
int i = 0;
|
||||
for (Loader loader; (loader = getLoader(i)) != null; i++) {
|
||||
@@ -242,7 +388,6 @@ public class InstrumentationClassFinder {
|
||||
myLoadersMap.clear();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private synchronized Loader getLoader(int i) {
|
||||
while (myLoaders.size() < i + 1) {
|
||||
URL url;
|
||||
@@ -275,7 +420,6 @@ public class InstrumentationClassFinder {
|
||||
return myLoaders.get(i);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Loader getLoader(final URL url, int index) throws IOException {
|
||||
String s;
|
||||
try {
|
||||
@@ -317,7 +461,6 @@ public class InstrumentationClassFinder {
|
||||
return myURL;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract Resource getResource(final String name, boolean flag);
|
||||
|
||||
public abstract void releaseResources();
|
||||
@@ -345,7 +488,6 @@ public class InstrumentationClassFinder {
|
||||
public void releaseResources() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Resource getResource(final String name, boolean check) {
|
||||
URL url = null;
|
||||
File file = null;
|
||||
@@ -410,7 +552,6 @@ public class InstrumentationClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
return "FileLoader [" + myRootDir + "]";
|
||||
}
|
||||
@@ -438,7 +579,6 @@ public class InstrumentationClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ZipFile acquireZipFile() throws IOException {
|
||||
ZipFile zipFile = myZipFile;
|
||||
if (zipFile == null) {
|
||||
@@ -448,7 +588,6 @@ public class InstrumentationClassFinder {
|
||||
return zipFile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ZipFile doGetZipFile() throws IOException {
|
||||
if (FILE_PROTOCOL.equals(myURL.getProtocol())) {
|
||||
String s = unescapePercentSequences(myURL.getFile().replace('/', File.separatorChar));
|
||||
@@ -463,7 +602,6 @@ public class InstrumentationClassFinder {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Resource getResource(String name, boolean flag) {
|
||||
try {
|
||||
final ZipFile file = acquireZipFile();
|
||||
@@ -501,11 +639,9 @@ public class InstrumentationClassFinder {
|
||||
return myURL;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InputStream getInputStream() throws IOException {
|
||||
ZipFile file = null;
|
||||
try {
|
||||
file = acquireZipFile();
|
||||
final ZipFile file = acquireZipFile();
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -527,7 +663,6 @@ public class InstrumentationClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
return "JarLoader [" + myURL + "]";
|
||||
}
|
||||
@@ -535,8 +670,7 @@ public class InstrumentationClassFinder {
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static String unescapePercentSequences(@NotNull String s) {
|
||||
private static String unescapePercentSequences(String s) {
|
||||
if (s.indexOf('%') == -1) {
|
||||
return s;
|
||||
}
|
||||
@@ -591,4 +725,27 @@ public class InstrumentationClassFinder {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public byte[] loadBytes(InputStream stream) {
|
||||
byte[] buf = myBuffer;
|
||||
if (buf == null) {
|
||||
buf = new byte[512];
|
||||
myBuffer = buf;
|
||||
}
|
||||
|
||||
final ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try {
|
||||
while (true) {
|
||||
int n = stream.read(buf, 0, buf.length);
|
||||
if (n <= 0) {
|
||||
break;
|
||||
}
|
||||
result.write(buf, 0, n);
|
||||
}
|
||||
result.close();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.intellij.compiler.instrumentation;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 3/27/12
|
||||
*/
|
||||
public class InstrumenterClassWriter extends ClassWriter {
|
||||
private final InstrumentationClassFinder myFinder;
|
||||
|
||||
public InstrumenterClassWriter(int flags, final InstrumentationClassFinder finder) {
|
||||
super(flags);
|
||||
myFinder = finder;
|
||||
}
|
||||
|
||||
protected String getCommonSuperClass(final String type1, final String type2) {
|
||||
try {
|
||||
final InstrumentationClassFinder.PseudoClass cls1 = myFinder.loadClass(type1);
|
||||
final InstrumentationClassFinder.PseudoClass cls2 = myFinder.loadClass(type2);
|
||||
if (cls1.isAssignableFrom(cls2)) {
|
||||
return cls1.getName();
|
||||
}
|
||||
if (cls2.isAssignableFrom(cls1)) {
|
||||
return cls2.getName();
|
||||
}
|
||||
if (cls1.isInterface() || cls2.isInterface()) {
|
||||
return "java/lang/Object";
|
||||
}
|
||||
else {
|
||||
InstrumentationClassFinder.PseudoClass c = cls1;
|
||||
do {
|
||||
c = c.getSuperClass();
|
||||
}
|
||||
while (!c.isAssignableFrom(cls2));
|
||||
return c.getName();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<orderEntry type="module" module-name="forms-compiler" />
|
||||
<orderEntry type="module" module-name="forms_rt" />
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="module" module-name="notNull" />
|
||||
<orderEntry type="module" module-name="instrumentation-util" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.ant;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class AntClassWriter extends ClassWriter {
|
||||
private final PseudoClassLoader myPseudoClassLoader;
|
||||
|
||||
public AntClassWriter(int flags, final PseudoClassLoader pseudoLoader) {
|
||||
super(flags);
|
||||
myPseudoClassLoader = pseudoLoader;
|
||||
}
|
||||
|
||||
public AntClassWriter(ClassReader classReader, int flags, final PseudoClassLoader pseudoLoader) {
|
||||
super(classReader, flags);
|
||||
myPseudoClassLoader = pseudoLoader;
|
||||
}
|
||||
|
||||
protected String getCommonSuperClass(final String type1, final String type2) {
|
||||
try {
|
||||
PseudoClassLoader.PseudoClass p1 = myPseudoClassLoader.loadClass(type1);
|
||||
PseudoClassLoader.PseudoClass p2 = myPseudoClassLoader.loadClass(type2);
|
||||
|
||||
return p1.getCommonSuperClassName(p2);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.ant;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
|
||||
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
|
||||
import com.intellij.uiDesigner.compiler.*;
|
||||
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
|
||||
@@ -39,14 +41,14 @@ import java.util.*;
|
||||
*/
|
||||
|
||||
public class InstrumentationUtil {
|
||||
public static PseudoClassLoader createPseudoClassLoader(final String classPath) throws MalformedURLException {
|
||||
public static InstrumentationClassFinder createInstrumentationClassFinder(final String classPath) throws MalformedURLException {
|
||||
final ArrayList urls = new ArrayList();
|
||||
for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
|
||||
final String s = tokenizer.nextToken();
|
||||
urls.add(new File(s).toURL());
|
||||
}
|
||||
final URL[] urlsArr = (URL[])urls.toArray(new URL[urls.size()]);
|
||||
return new PseudoClassLoader(urlsArr);
|
||||
return new InstrumentationClassFinder(urlsArr);
|
||||
}
|
||||
|
||||
public static int getClassFileVersion(ClassReader reader) {
|
||||
@@ -108,12 +110,12 @@ public class InstrumentationUtil {
|
||||
}
|
||||
|
||||
private class AntNestedFormLoader implements NestedFormLoader {
|
||||
private final PseudoClassLoader myLoader;
|
||||
private final InstrumentationClassFinder myClassFinder;
|
||||
private final List myNestedFormPathList;
|
||||
private final HashMap myFormCache = new HashMap();
|
||||
|
||||
public AntNestedFormLoader(final PseudoClassLoader loader, List nestedFormPathList) {
|
||||
myLoader = loader;
|
||||
public AntNestedFormLoader(final InstrumentationClassFinder classFinder, List nestedFormPathList) {
|
||||
myClassFinder = classFinder;
|
||||
myNestedFormPathList = nestedFormPathList;
|
||||
}
|
||||
|
||||
@@ -143,7 +145,7 @@ public class InstrumentationUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
InputStream resourceStream = myLoader.getLoader ().getResourceAsStream(formFilePath);
|
||||
InputStream resourceStream = myClassFinder.getResourceAsStream(formFilePath);
|
||||
if (resourceStream != null) {
|
||||
return loadForm(formFilePath, resourceStream);
|
||||
}
|
||||
@@ -164,11 +166,11 @@ public class InstrumentationUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public void instrumentForm(final File file, final PseudoClassLoader loader) {
|
||||
public void instrumentForm(final File file, final InstrumentationClassFinder classFinder) {
|
||||
log("compiling form " + file.getAbsolutePath(), Project.MSG_VERBOSE);
|
||||
final LwRootContainer rootContainer;
|
||||
try {
|
||||
rootContainer = Utils.getRootContainer(file.toURL(), new CompiledClassPropertiesProvider(loader.getLoader ()));
|
||||
rootContainer = Utils.getRootContainer(file.toURL(), new CompiledClassPropertiesProvider(classFinder.getLoader()));
|
||||
}
|
||||
catch (AlienFormFileException e) {
|
||||
// ignore non-IDEA forms
|
||||
@@ -216,9 +218,9 @@ public class InstrumentationUtil {
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
AntNestedFormLoader formLoader = new AntNestedFormLoader(loader, myNestedFormPathList);
|
||||
AntClassWriter classWriter = new AntClassWriter(InstrumentationUtil.getAsmClassWriterFlags(version), loader);
|
||||
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader.getLoader(), formLoader, false, classWriter);
|
||||
AntNestedFormLoader formLoader = new AntNestedFormLoader(classFinder, myNestedFormPathList);
|
||||
InstrumenterClassWriter classWriter = new InstrumenterClassWriter(InstrumentationUtil.getAsmClassWriterFlags(version), classFinder);
|
||||
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, classFinder, formLoader, false, classWriter);
|
||||
codeGenerator.patchFile(classFile);
|
||||
final FormErrorInfo[] warnings = codeGenerator.getWarnings();
|
||||
|
||||
@@ -243,15 +245,15 @@ public class InstrumentationUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] instrumentNotNull(final byte[] buffer, final PseudoClassLoader loader) {
|
||||
public static byte[] instrumentNotNull(final byte[] buffer, final InstrumentationClassFinder loader) {
|
||||
return instrumentNotNull(new ClassReader (buffer), loader);
|
||||
}
|
||||
|
||||
private static byte[] instrumentNotNull(final ClassReader reader, final PseudoClassLoader loader) {
|
||||
private static byte[] instrumentNotNull(final ClassReader reader, final InstrumentationClassFinder loader) {
|
||||
int version = getClassFileVersion(reader);
|
||||
|
||||
if (version >= Opcodes.V1_5) {
|
||||
ClassWriter writer = new AntClassWriter(getAsmClassWriterFlags(version), loader);
|
||||
ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), loader);
|
||||
|
||||
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
|
||||
reader.accept(instrumenter, 0);
|
||||
@@ -264,7 +266,7 @@ public class InstrumentationUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int instrumentNotNull(final File file, final PseudoClassLoader loader) throws IOException {
|
||||
public static int instrumentNotNull(final File file, final InstrumentationClassFinder loader) throws IOException {
|
||||
int instrumented = 0;
|
||||
final String path = file.getPath();
|
||||
final FileInputStream inputStream = new FileInputStream(file);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.ant;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
|
||||
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
|
||||
import com.intellij.uiDesigner.compiler.*;
|
||||
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
|
||||
@@ -201,26 +203,34 @@ public class Javac2 extends Javac {
|
||||
* class files.
|
||||
*/
|
||||
protected void compile() {
|
||||
// compile java
|
||||
if (areJavaClassesCompiled()) {
|
||||
super.compile();
|
||||
}
|
||||
// compile java
|
||||
if (areJavaClassesCompiled()) {
|
||||
super.compile();
|
||||
}
|
||||
|
||||
PseudoClassLoader loader = buildClasspathClassLoader();
|
||||
if (loader == null) return;
|
||||
instrumentForms(loader);
|
||||
InstrumentationClassFinder finder = buildClasspathClassLoader();
|
||||
if (finder == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
instrumentForms(finder);
|
||||
|
||||
//NotNull instrumentation
|
||||
final int instrumented = instrumentNotNull(getDestdir(), loader);
|
||||
final int instrumented = instrumentNotNull(getDestdir(), finder);
|
||||
|
||||
log("Added @NotNull assertions to " + instrumented + " files", Project.MSG_INFO);
|
||||
}
|
||||
finally {
|
||||
finder.releaseResources();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Instrument forms
|
||||
*
|
||||
* @param loader a classloader to use
|
||||
* @param finder a classloader to use
|
||||
*/
|
||||
private void instrumentForms(final PseudoClassLoader loader) {
|
||||
private void instrumentForms(final InstrumentationClassFinder finder) {
|
||||
// we instrument every file, because we cannot find which files should not be instrumented without dependency storage
|
||||
final ArrayList formsToInstrument = myFormFiles;
|
||||
|
||||
@@ -237,7 +247,7 @@ public class Javac2 extends Javac {
|
||||
log("compiling form " + formFile.getAbsolutePath(), Project.MSG_VERBOSE);
|
||||
final LwRootContainer rootContainer;
|
||||
try {
|
||||
rootContainer = Utils.getRootContainer(formFile.toURL(), new CompiledClassPropertiesProvider(loader.getLoader()));
|
||||
rootContainer = Utils.getRootContainer(formFile.toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
|
||||
}
|
||||
catch (AlienFormFileException e) {
|
||||
// ignore non-IDEA forms
|
||||
@@ -283,9 +293,9 @@ public class Javac2 extends Javac {
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
AntNestedFormLoader formLoader = new AntNestedFormLoader(loader.getLoader(), myNestedFormPathList);
|
||||
AntClassWriter classWriter = new AntClassWriter(getAsmClassWriterFlags(version), loader);
|
||||
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader.getLoader(), formLoader, false, classWriter);
|
||||
AntNestedFormLoader formLoader = new AntNestedFormLoader(finder.getLoader(), myNestedFormPathList);
|
||||
InstrumenterClassWriter classWriter = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
|
||||
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, formLoader, false, classWriter);
|
||||
codeGenerator.patchFile(classFile);
|
||||
final FormErrorInfo[] warnings = codeGenerator.getWarnings();
|
||||
|
||||
@@ -322,7 +332,7 @@ public class Javac2 extends Javac {
|
||||
*
|
||||
* @return a URL classloader
|
||||
*/
|
||||
private PseudoClassLoader buildClasspathClassLoader() {
|
||||
private InstrumentationClassFinder buildClasspathClassLoader() {
|
||||
final StringBuffer classPathBuffer = new StringBuffer();
|
||||
final Path cp = new Path(getProject());
|
||||
appendPath(cp, getBootclasspath());
|
||||
@@ -349,7 +359,7 @@ public class Javac2 extends Javac {
|
||||
log("classpath=" + classPath, Project.MSG_VERBOSE);
|
||||
|
||||
try {
|
||||
return InstrumentationUtil.createPseudoClassLoader(classPath);
|
||||
return InstrumentationUtil.createInstrumentationClassFinder(classPath);
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
fireError(e.getMessage());
|
||||
@@ -373,10 +383,10 @@ public class Javac2 extends Javac {
|
||||
* Instrument classes with NotNull annotations
|
||||
*
|
||||
* @param dir the directory with classes to instrument (the directory is processed recursively)
|
||||
* @param loader the classloader to use
|
||||
* @param finder the classloader to use
|
||||
* @return the amount of classes actually affected by instrumentation
|
||||
*/
|
||||
private int instrumentNotNull(File dir, final PseudoClassLoader loader) {
|
||||
private int instrumentNotNull(File dir, final InstrumentationClassFinder finder) {
|
||||
int instrumented = 0;
|
||||
final File[] files = dir.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
@@ -393,7 +403,7 @@ public class Javac2 extends Javac {
|
||||
int version = getClassFileVersion(reader);
|
||||
|
||||
if (version >= Opcodes.V1_5) {
|
||||
ClassWriter writer = new AntClassWriter(getAsmClassWriterFlags(version), loader);
|
||||
ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
|
||||
|
||||
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
|
||||
reader.accept(instrumenter, 0);
|
||||
@@ -421,7 +431,7 @@ public class Javac2 extends Javac {
|
||||
}
|
||||
}
|
||||
else if (file.isDirectory()) {
|
||||
instrumented += instrumentNotNull(file, loader);
|
||||
instrumented += instrumentNotNull(file, finder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.ant;
|
||||
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.EmptyVisitor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* @author db
|
||||
* Date: 06.06.11
|
||||
*/
|
||||
public class PseudoClassLoader {
|
||||
static final WeakHashMap myCache = new WeakHashMap();
|
||||
|
||||
final Map myDefinedClasses = new HashMap ();
|
||||
final Map myDefinedClassesData = new HashMap ();
|
||||
|
||||
private class MemoryClassLoader extends ClassLoader {
|
||||
public MemoryClassLoader(URLClassLoader classpathLoader) {
|
||||
super(classpathLoader);
|
||||
}
|
||||
|
||||
protected Class findClass(String name) throws ClassNotFoundException {
|
||||
final byte[] data = (byte[])myDefinedClassesData.get(name);
|
||||
if (data == null) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return defineClass(name, data, 0, data.length);
|
||||
}
|
||||
|
||||
public URL findResource(String name) {
|
||||
return super.findResource(name);
|
||||
}
|
||||
}
|
||||
|
||||
public class PseudoClass {
|
||||
final String myName;
|
||||
final String mySuperClass;
|
||||
final String[] myInterfaces;
|
||||
final boolean isInterface;
|
||||
|
||||
private PseudoClass(final Class repr) {
|
||||
final Class superclass = repr.getSuperclass();
|
||||
final Class[] interfaces = repr.getInterfaces();
|
||||
|
||||
myName = repr.getName().replace('.', '/');
|
||||
mySuperClass = superclass == null ? null : superclass.getName().replace('.', '/');
|
||||
myInterfaces = interfaces.length == 0 ? null : new String[interfaces.length];
|
||||
|
||||
for (int i=0; i<interfaces.length; i++) {
|
||||
myInterfaces[i] = interfaces[i].getName().replace('.', '/');
|
||||
}
|
||||
|
||||
isInterface = repr.isInterface();
|
||||
}
|
||||
|
||||
private PseudoClass(final String name, final String superClass, final String[] interfaces, final boolean anInterface) {
|
||||
myName = name;
|
||||
mySuperClass = superClass;
|
||||
myInterfaces = interfaces;
|
||||
isInterface = anInterface;
|
||||
}
|
||||
|
||||
private PseudoClass getSuperClass() throws IOException, ClassNotFoundException {
|
||||
if (mySuperClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return loadClass(mySuperClass);
|
||||
}
|
||||
|
||||
private PseudoClass[] getInterfaces() throws IOException, ClassNotFoundException {
|
||||
if (myInterfaces == null) {
|
||||
return new PseudoClass[0];
|
||||
}
|
||||
|
||||
final PseudoClass[] result = new PseudoClass[myInterfaces.length];
|
||||
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = loadClass(myInterfaces[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean equals (final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
return myName.equals(((PseudoClass)o).myName);
|
||||
}
|
||||
|
||||
private boolean isSubclassOf(final PseudoClass x) throws IOException, ClassNotFoundException {
|
||||
for (PseudoClass c = this; c != null; c = c.getSuperClass()) {
|
||||
final PseudoClass superClass = c.getSuperClass();
|
||||
|
||||
if (superClass != null && superClass.equals(x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean implementsInterface(final PseudoClass x) throws IOException, ClassNotFoundException {
|
||||
for (PseudoClass c = this; c != null; c = c.getSuperClass()) {
|
||||
final PseudoClass[] tis = c.getInterfaces();
|
||||
for (int i = 0; i < tis.length; ++i) {
|
||||
final PseudoClass ti = tis[i];
|
||||
if (ti.equals(x) || ti.implementsInterface(x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAssignableFrom(final PseudoClass x) throws IOException, ClassNotFoundException {
|
||||
if (this.equals(x)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x.isSubclassOf(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x.implementsInterface(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x.isInterface && myName.equals("java/lang/Object")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getCommonSuperClassName(final PseudoClass x) throws IOException, ClassNotFoundException {
|
||||
if (isAssignableFrom(x)) {
|
||||
return myName;
|
||||
}
|
||||
|
||||
if (x.isAssignableFrom(this)) {
|
||||
return x.myName;
|
||||
}
|
||||
|
||||
if (isInterface || x.isInterface) {
|
||||
return "java/lang/Object";
|
||||
}
|
||||
else {
|
||||
PseudoClass c = this;
|
||||
|
||||
do {
|
||||
c = c.getSuperClass();
|
||||
}
|
||||
while (!c.isAssignableFrom(x));
|
||||
|
||||
return c.myName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final MemoryClassLoader myLoader;
|
||||
|
||||
public PseudoClassLoader(final URL[] classpath) {
|
||||
final URLClassLoader classpathLoader = new URLClassLoader(classpath, null);
|
||||
myLoader = new MemoryClassLoader(classpathLoader);
|
||||
}
|
||||
|
||||
public ClassLoader getLoader () {
|
||||
return myLoader;
|
||||
}
|
||||
|
||||
public void defineClass (final String internalName, final byte[] data) {
|
||||
myDefinedClasses.put(internalName, createPseudoClass(new ClassReader(data)));
|
||||
myDefinedClassesData.put(internalName.replace('/', '.'), data);
|
||||
}
|
||||
|
||||
private static class V extends EmptyVisitor {
|
||||
public String superName = null;
|
||||
public String[] interfaces = null;
|
||||
public String name = null;
|
||||
public boolean isInterface = false;
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
public void visit(int version, int access, String pName, String signature, String pSuperName, String[] pInterfaces) {
|
||||
superName = pSuperName;
|
||||
interfaces = pInterfaces;
|
||||
name = pName;
|
||||
isInterface = (access & Opcodes.ACC_INTERFACE) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private PseudoClass createPseudoClass(final ClassReader r) {
|
||||
final V visitor = new V();
|
||||
|
||||
r.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
|
||||
return new PseudoClass(visitor.name, visitor.superName, visitor.interfaces, visitor.isInterface);
|
||||
}
|
||||
|
||||
private class Tag {
|
||||
final PseudoClass myClass;
|
||||
final long myStamp;
|
||||
|
||||
private Tag(PseudoClass aClass, long stamp) {
|
||||
myClass = aClass;
|
||||
myStamp = stamp;
|
||||
}
|
||||
}
|
||||
|
||||
public PseudoClass loadClass(final String internalName) throws IOException, ClassNotFoundException {
|
||||
final PseudoClass defined = (PseudoClass) myDefinedClasses.get(internalName);
|
||||
|
||||
if (defined != null) {
|
||||
return defined;
|
||||
}
|
||||
|
||||
final URL resource = myLoader.findResource(internalName + ".class");
|
||||
|
||||
if (resource == null) {
|
||||
final Class lastResort = myLoader.loadClass(internalName.replace('/', '.'));
|
||||
return new PseudoClass(lastResort);
|
||||
}
|
||||
|
||||
final String fileName = resource.getFile();
|
||||
final boolean isFile = fileName.length() > 0;
|
||||
final File file = new File(fileName);
|
||||
|
||||
if (isFile) {
|
||||
final Tag cached = (Tag)myCache.get(internalName);
|
||||
|
||||
if (cached != null && cached.myStamp == file.lastModified()) {
|
||||
return cached.myClass;
|
||||
}
|
||||
}
|
||||
|
||||
final InputStream content = (InputStream)resource.getContent();
|
||||
final ClassReader reader = new ClassReader(content);
|
||||
final PseudoClass result = createPseudoClass(reader);
|
||||
|
||||
if (isFile) {
|
||||
myCache.put(internalName, new Tag(result, file.lastModified()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -32,20 +32,13 @@ import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author lex
|
||||
*/
|
||||
class ReloadClassesWorker {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.ReloadClassesWorker");
|
||||
/**
|
||||
* number of clasess that will be reloaded in one go.
|
||||
* Such restriction is needed to deal with big number of classes being reloaded
|
||||
*/
|
||||
private static final int CLASSES_CHUNK_SIZE = 100;
|
||||
private final DebuggerSession myDebuggerSession;
|
||||
private final HotSwapProgress myProgress;
|
||||
|
||||
@@ -111,11 +104,12 @@ class ReloadClassesWorker {
|
||||
final Project project = debugProcess.getProject();
|
||||
final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
|
||||
breakpointManager.disableBreakpoints(debugProcess);
|
||||
|
||||
|
||||
//virtualMachineProxy.suspend();
|
||||
|
||||
|
||||
try {
|
||||
final Map<ReferenceType, byte[]> redefineMap = new HashMap<ReferenceType,byte[]>();
|
||||
RedefineProcessor redefineProcessor = new RedefineProcessor(virtualMachineProxy);
|
||||
|
||||
int processedClassesCount = 0;
|
||||
for (final String qualifiedName : modifiedClasses.keySet()) {
|
||||
processedClassesCount++;
|
||||
@@ -124,32 +118,30 @@ class ReloadClassesWorker {
|
||||
myProgress.setFraction(processedClassesCount / (double)modifiedClasses.size());
|
||||
}
|
||||
final HotSwapFile fileDescr = modifiedClasses.get(qualifiedName);
|
||||
final byte[] content;
|
||||
try {
|
||||
final byte[] buffer = FileUtil.loadFileBytes(fileDescr.file);
|
||||
final List<ReferenceType> classes = virtualMachineProxy.classesByName(qualifiedName);
|
||||
for (final ReferenceType reference : classes) {
|
||||
redefineMap.put(reference, buffer);
|
||||
}
|
||||
content = FileUtil.loadFileBytes(fileDescr.file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
reportProblem(qualifiedName, e);
|
||||
continue;
|
||||
}
|
||||
if (redefineMap.size() >= CLASSES_CHUNK_SIZE) {
|
||||
// reload this portion of clasess and clear the map to free memory
|
||||
try {
|
||||
virtualMachineProxy.redefineClasses(redefineMap);
|
||||
}
|
||||
finally {
|
||||
redefineMap.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (redefineMap.size() > 0) {
|
||||
virtualMachineProxy.redefineClasses(redefineMap);
|
||||
redefineProcessor.processClass(qualifiedName, content);
|
||||
}
|
||||
redefineProcessor.processPending();
|
||||
myProgress.setFraction(1);
|
||||
|
||||
myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION, DebuggerBundle.message("status.classes.reloaded", modifiedClasses.size()));
|
||||
|
||||
final int partiallyRedefinedClassesCount = redefineProcessor.getPartiallyRedefinedClassesCount();
|
||||
if (partiallyRedefinedClassesCount == 0) {
|
||||
myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION,
|
||||
DebuggerBundle.message("status.classes.reloaded", redefineProcessor.getProcessedClassesCount()));
|
||||
}
|
||||
else {
|
||||
final String message = DebuggerBundle.message("status.classes.not.all.versions.reloaded", partiallyRedefinedClassesCount,
|
||||
redefineProcessor.getProcessedClassesCount());
|
||||
myProgress.addMessage(myDebuggerSession, MessageCategory.WARNING, message);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("classes reloaded");
|
||||
}
|
||||
@@ -203,11 +195,10 @@ class ReloadClassesWorker {
|
||||
catch (Exception e) {
|
||||
processException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void reportProblem(final String qualifiedName, @Nullable Exception ex) {
|
||||
String reason = null;
|
||||
String reason = null;
|
||||
if (ex != null) {
|
||||
reason = ex.getLocalizedMessage();
|
||||
}
|
||||
@@ -223,4 +214,78 @@ class ReloadClassesWorker {
|
||||
StringBuilderSpinAllocator.dispose(buf);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RedefineProcessor {
|
||||
/**
|
||||
* number of classes that will be reloaded in one go.
|
||||
* Such restriction is needed to deal with big number of classes being reloaded
|
||||
*/
|
||||
private static final int CLASSES_CHUNK_SIZE = 100;
|
||||
private final VirtualMachineProxyImpl myVirtualMachineProxy;
|
||||
private final Map<ReferenceType, byte[]> myRedefineMap = new HashMap<ReferenceType, byte[]>();
|
||||
private int myProcessedClassesCount;
|
||||
private int myPartiallyRedefinedClassesCount;
|
||||
|
||||
public RedefineProcessor(VirtualMachineProxyImpl virtualMachineProxy) {
|
||||
myVirtualMachineProxy = virtualMachineProxy;
|
||||
}
|
||||
|
||||
public void processClass(String qualifiedName, byte[] content) throws Throwable {
|
||||
final List<ReferenceType> vmClasses = myVirtualMachineProxy.classesByName(qualifiedName);
|
||||
if (vmClasses.isEmpty()) return;
|
||||
|
||||
if (vmClasses.size() == 1) {
|
||||
myRedefineMap.put(vmClasses.get(0), content);
|
||||
if (myRedefineMap.size() >= CLASSES_CHUNK_SIZE) {
|
||||
processChunk();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int redefinedVersionsCount = 0;
|
||||
Throwable error = null;
|
||||
for (ReferenceType vmClass : vmClasses) {
|
||||
try {
|
||||
myVirtualMachineProxy.redefineClasses(Collections.singletonMap(vmClass, content));
|
||||
redefinedVersionsCount++;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
error = t;
|
||||
}
|
||||
}
|
||||
if (redefinedVersionsCount == 0) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (redefinedVersionsCount < vmClasses.size()) {
|
||||
myPartiallyRedefinedClassesCount++;
|
||||
}
|
||||
myProcessedClassesCount++;
|
||||
}
|
||||
|
||||
private void processChunk() throws Throwable {
|
||||
// reload this portion of classes and clear the map to free memory
|
||||
try {
|
||||
myVirtualMachineProxy.redefineClasses(myRedefineMap);
|
||||
myProcessedClassesCount += myRedefineMap.size();
|
||||
}
|
||||
finally {
|
||||
myRedefineMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void processPending() throws Throwable {
|
||||
if (myRedefineMap.size() > 0) {
|
||||
processChunk();
|
||||
}
|
||||
}
|
||||
|
||||
public int getProcessedClassesCount() {
|
||||
return myProcessedClassesCount;
|
||||
}
|
||||
|
||||
public int getPartiallyRedefinedClassesCount() {
|
||||
return myPartiallyRedefinedClassesCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -80,6 +80,7 @@ public class PackagingElementNode<E extends PackagingElement<?>> extends Artifac
|
||||
return myPackagingElements.size() == 1 ? myPackagingElements.get(0) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getEqualityObjects() {
|
||||
return ArrayUtil.toObjectArray(myPackagingElements);
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactEditorEx;
|
||||
import com.intellij.packaging.ui.ArtifactEditorContext;
|
||||
import com.intellij.packaging.ui.PackagingSourceItem;
|
||||
import com.intellij.ui.treeStructure.SimpleTree;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
import java.util.Collections;
|
||||
@@ -35,6 +36,7 @@ public class SourceItemNode extends SourceItemNodeBase {
|
||||
mySourceItem = sourceItem;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getEqualityObjects() {
|
||||
return new Object[]{mySourceItem};
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ public class SourceItemsTreeRoot extends SourceItemNodeBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getEqualityObjects() {
|
||||
return new Object[]{"root"};
|
||||
|
||||
+2
-1
@@ -27,6 +27,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileChooser.FileChooser;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
@@ -371,7 +372,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AttachItemActionBase extends AnAction {
|
||||
public abstract class AttachItemActionBase extends DumbAwareAction {
|
||||
private VirtualFile myLastChosen = null;
|
||||
|
||||
protected AttachItemActionBase(String text) {
|
||||
|
||||
+1
@@ -290,6 +290,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
|
||||
return myElement.equals(other.myElement) && (!other.myCheck || myCheck) && (!other.myCollectUsages || myCollectUsages);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getEqualityObjects() {
|
||||
return myEqualityObjects;
|
||||
|
||||
@@ -269,6 +269,7 @@ public abstract class ChooseLibrariesDialogBase extends DialogWrapper {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getEqualityObjects() {
|
||||
return new Object[] {myElement};
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class SuppressAllForClassFix extends SuppressFix {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(final Project project, final Editor editor, final PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
|
||||
final PsiDocCommentOwner container = getContainer(element);
|
||||
LOG.assertTrue(container != null);
|
||||
if (!CodeInsightUtilBase.preparePsiElementForWrite(container)) return;
|
||||
|
||||
@@ -105,7 +105,7 @@ public class SuppressFix extends SuppressIntentionAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(final Project project, final Editor editor, final PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
|
||||
PsiDocCommentOwner container = getContainer(element);
|
||||
assert container != null;
|
||||
if (!CodeInsightUtilBase.preparePsiElementForWrite(container)) return;
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class SuppressParameterFix extends SuppressIntentionAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(final Project project, final Editor editor, final PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
|
||||
PsiParameter container = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
|
||||
assert container != null;
|
||||
if (!CodeInsightUtilBase.preparePsiElementForWrite(container)) return;
|
||||
|
||||
+14
-44
@@ -26,6 +26,8 @@ import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersionUtil;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
@@ -505,7 +507,17 @@ public class GenericsHighlightUtil {
|
||||
|
||||
final PsiType retErasure1 = TypeConversionUtil.erasure(checkMethod.getReturnType());
|
||||
final PsiType retErasure2 = TypeConversionUtil.erasure(superMethod.getReturnType());
|
||||
if (!Comparing.equal(retErasure1, retErasure2) &&
|
||||
|
||||
boolean differentReturnTypeErasure = !Comparing.equal(retErasure1, retErasure2);
|
||||
if (checkEqualsSuper && JavaSdkVersionUtil.isAtLeast(checkMethod, JavaSdkVersion.JDK_1_7)) {
|
||||
if (retErasure1 != null && retErasure2 != null) {
|
||||
differentReturnTypeErasure = !TypeConversionUtil.isAssignable(retErasure1, retErasure2);
|
||||
} else {
|
||||
differentReturnTypeErasure = !(retErasure1 == null && retErasure2 == null);
|
||||
}
|
||||
}
|
||||
|
||||
if (differentReturnTypeErasure &&
|
||||
!TypeConversionUtil.isVoidType(retErasure1) &&
|
||||
!TypeConversionUtil.isVoidType(retErasure2) &&
|
||||
!(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes()))) {
|
||||
@@ -676,7 +688,7 @@ public class GenericsHighlightUtil {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (isUncheckedTypeArgumentConversion(lTypeArg, rTypeArg)) return true;
|
||||
if (!TypeConversionUtil.typesAgree(lTypeArg, rTypeArg, false)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -718,48 +730,6 @@ public class GenericsHighlightUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isUncheckedTypeArgumentConversion (PsiType lTypeArg, PsiType rTypeArg) {
|
||||
if (lTypeArg instanceof PsiPrimitiveType || rTypeArg instanceof PsiPrimitiveType) return false;
|
||||
if (lTypeArg.equals(rTypeArg)) return false;
|
||||
if (lTypeArg instanceof PsiCapturedWildcardType) {
|
||||
//ignore capture conversion
|
||||
return isUncheckedTypeArgumentConversion(((PsiCapturedWildcardType)lTypeArg).getWildcard(), rTypeArg);
|
||||
}
|
||||
if (rTypeArg instanceof PsiCapturedWildcardType) {
|
||||
//ignore capture conversion
|
||||
return isUncheckedTypeArgumentConversion(lTypeArg, ((PsiCapturedWildcardType)rTypeArg).getWildcard());
|
||||
}
|
||||
|
||||
if (lTypeArg instanceof PsiWildcardType || rTypeArg instanceof PsiWildcardType) {
|
||||
return !lTypeArg.isAssignableFrom(rTypeArg);
|
||||
}
|
||||
|
||||
if (lTypeArg instanceof PsiArrayType && rTypeArg instanceof PsiArrayType) {
|
||||
return isUncheckedTypeArgumentConversion(((PsiArrayType)rTypeArg).getComponentType(), ((PsiArrayType)lTypeArg).getComponentType());
|
||||
}
|
||||
if (lTypeArg instanceof PsiArrayType || rTypeArg instanceof PsiArrayType) return false;
|
||||
if (lTypeArg instanceof PsiIntersectionType) {
|
||||
for (PsiType type : ((PsiIntersectionType)lTypeArg).getConjuncts()) {
|
||||
if (!isUncheckedTypeArgumentConversion(type, rTypeArg)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!(lTypeArg instanceof PsiClassType)) {
|
||||
LOG.error("left: "+lTypeArg + "; "+lTypeArg.getClass());
|
||||
}
|
||||
if (rTypeArg instanceof PsiIntersectionType) {
|
||||
for (PsiType type : ((PsiIntersectionType)rTypeArg).getConjuncts()) {
|
||||
if (!isUncheckedTypeArgumentConversion(lTypeArg, type)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!(rTypeArg instanceof PsiClassType)) {
|
||||
LOG.error("right :"+rTypeArg + "; "+rTypeArg.getClass());
|
||||
}
|
||||
return ((PsiClassType)lTypeArg).resolve() instanceof PsiTypeParameter ||
|
||||
((PsiClassType)rTypeArg).resolve() instanceof PsiTypeParameter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkForeachLoopParameterType(PsiForeachStatement statement) {
|
||||
final PsiParameter parameter = statement.getIterationParameter();
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ public class DelegateWithDefaultParamValueIntentionAction extends PsiElementBase
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Project project, Editor editor, PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
|
||||
final PsiMethod method = (PsiMethod)parameter.getDeclarationScope();
|
||||
final PsiMethod prototype = (PsiMethod)method.getContainingClass().addBefore(generateMethodPrototype(method, parameter), method);
|
||||
|
||||
+3
-1
@@ -112,7 +112,9 @@ public class IterateOverIterableIntention implements IntentionAction {
|
||||
element = ((PsiExpressionStatement)element).getExpression().getLastChild();
|
||||
}
|
||||
while ((element = PsiTreeUtil.getParentOfType(element, PsiExpression.class, true)) != null) {
|
||||
if (element.getParent() instanceof PsiMethodCallExpression) continue;
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiMethodCallExpression) continue;
|
||||
if (!(parent instanceof PsiExpressionStatement)) return null;
|
||||
final PsiType type = ((PsiExpression)element).getType();
|
||||
if (type instanceof PsiArrayType || InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_ITERABLE)) return (PsiExpression)element;
|
||||
}
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class QualifyThisArgumentFix extends PsiElementBaseIntentionAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Project project, Editor editor, PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
myExpression.replace(RefactoringUtil.createThisExpression(PsiManager.getInstance(project), myPsiClass));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.folding.impl;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil;
|
||||
import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
|
||||
import com.intellij.codeInsight.generation.OverrideImplementUtil;
|
||||
import com.intellij.lang.ASTNode;
|
||||
@@ -47,7 +48,10 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAware {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.folding.impl.JavaFoldingBuilder");
|
||||
@@ -312,7 +316,9 @@ public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAwar
|
||||
if (importKeyword == null) return null;
|
||||
int startOffset = importKeyword.getTextRange().getEndOffset() + 1;
|
||||
int endOffset = statements[statements.length - 1].getTextRange().getEndOffset();
|
||||
return new TextRange(startOffset, endOffset);
|
||||
if (!hasErrorElementsNearby(element.getContainingFile(), startOffset, endOffset)) {
|
||||
return new TextRange(startOffset, endOffset);
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiDocComment) {
|
||||
return element.getTextRange();
|
||||
@@ -330,6 +336,16 @@ public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAwar
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasErrorElementsNearby(final PsiFile file, int startOffset, int endOffset) {
|
||||
endOffset = CharArrayUtil.shiftForward(file.getText(), endOffset, " \t\n");
|
||||
for (PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffset)) {
|
||||
if (element instanceof PsiErrorElement) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextRange getFileHeader(PsiJavaFile file) {
|
||||
PsiElement first = file.getFirstChild();
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class InsertLiteralUnderscoresAction extends PsiElementBaseIntentionActio
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(final Project project, final Editor editor, final PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
|
||||
final PsiLiteralExpression literalExpression = PsiTreeUtil.getParentOfType(element, PsiLiteralExpression.class, false);
|
||||
if (literalExpression == null) return;
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class RemoveLiteralUnderscoresAction extends PsiElementBaseIntentionActio
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(final Project project, final Editor editor, final PsiElement element) throws IncorrectOperationException {
|
||||
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
|
||||
final PsiLiteralExpression literalExpression = PsiTreeUtil.getParentOfType(element, PsiLiteralExpression.class, false);
|
||||
if (literalExpression == null) return;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ package com.intellij.codeInspection.javaDoc;
|
||||
|
||||
import com.intellij.ExtensionPoints;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
|
||||
@@ -1176,7 +1175,6 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
|
||||
final InspectionProfile inspectionProfile =
|
||||
InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
//correct save settings
|
||||
((ModifiableModel)inspectionProfile).isProperSetting(HighlightDisplayKey.find(SHORT_NAME));
|
||||
InspectionProfileManager.getInstance().fireProfileChanged(inspectionProfile);
|
||||
//TODO lesya
|
||||
|
||||
|
||||
@@ -16,14 +16,11 @@
|
||||
|
||||
package com.intellij.codeInspection.util;
|
||||
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInspection.InspectionProfile;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.ide.util.TreeClassChooser;
|
||||
@@ -209,7 +206,6 @@ public class SpecialAnnotationsUtil {
|
||||
Collections.sort(targetList);
|
||||
final InspectionProfile inspectionProfile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
//correct save settings
|
||||
((InspectionProfileImpl)inspectionProfile).isProperSetting(HighlightDisplayKey.find(UnusedSymbolLocalInspection.SHORT_NAME));
|
||||
|
||||
//TODO lesya
|
||||
InspectionProfileManager.getInstance().fireProfileChanged(inspectionProfile);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.openapi.projectRoots;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 3/28/12
|
||||
*/
|
||||
public class JavaVersionServiceImpl extends JavaVersionService {
|
||||
@Override
|
||||
public boolean isAtLeast(PsiElement element, JavaSdkVersion version) {
|
||||
return JavaSdkVersionUtil.isAtLeast(element, version);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.projectRoots.impl;
|
||||
|
||||
import com.intellij.execution.util.ExecUtil;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.projectRoots.*;
|
||||
@@ -154,33 +155,27 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
public String suggestHomePath() {
|
||||
if (SystemInfo.isMac) {
|
||||
if (new File("/usr/libexec/java_home").exists()) {
|
||||
try {
|
||||
final Process exec = Runtime.getRuntime().exec("/usr/libexec/java_home");
|
||||
final BufferedReader input = new BufferedReader(new InputStreamReader(exec.getInputStream()));
|
||||
try {
|
||||
final String path = input.readLine();
|
||||
if (new File(path).exists()) return path;
|
||||
}
|
||||
finally {
|
||||
input.close();
|
||||
}
|
||||
final String path = ExecUtil.execAndReadLine("/usr/libexec/java_home");
|
||||
if (path != null && new File(path).exists()) {
|
||||
return path;
|
||||
}
|
||||
catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
return "/System/Library/Frameworks/JavaVM.framework/Versions/";
|
||||
return "/System/Library/Frameworks/JavaVM.framework/Versions";
|
||||
}
|
||||
|
||||
if (SystemInfo.isLinux) {
|
||||
final String[] homes = {"/usr/java", "/opt/java", "/usr/lib/jvm/"};
|
||||
final String[] homes = {"/usr/java", "/opt/java", "/usr/lib/jvm"};
|
||||
for (String home : homes) {
|
||||
if (new File(home).isDirectory()) {
|
||||
return home;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SystemInfo.isSolaris) {
|
||||
return "/usr/jdk/";
|
||||
return "/usr/jdk";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -192,10 +192,14 @@ public class PullUpDialog extends RefactoringDialog {
|
||||
protected void doAction() {
|
||||
if (!myCallback.checkConflicts(this)) return;
|
||||
JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC = myJavaDocPanel.getPolicy();
|
||||
StatisticsManager
|
||||
.getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), getSuperClass().getQualifiedName()));
|
||||
final PsiClass superClass = getSuperClass();
|
||||
String name = superClass.getQualifiedName();
|
||||
if (name != null) {
|
||||
StatisticsManager
|
||||
.getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), name));
|
||||
}
|
||||
|
||||
invokeRefactoring(new PullUpHelper(myClass, getSuperClass(), getSelectedMemberInfos(),
|
||||
invokeRefactoring(new PullUpHelper(myClass, superClass, getSelectedMemberInfos(),
|
||||
new DocCommentPolicy(getJavaDocPolicy())));
|
||||
close(OK_EXIT_CODE);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
@@ -241,7 +242,8 @@ public class RefactoringConflictsUtil {
|
||||
if (resolved != null &&
|
||||
!reported.contains(resolved) &&
|
||||
!CommonRefactoringUtil.isAncestor(resolved, scopes) &&
|
||||
!PsiSearchScopeUtil.isInScope(resolveScope, resolved)) {
|
||||
!PsiSearchScopeUtil.isInScope(resolveScope, resolved) &&
|
||||
!(resolved instanceof LightElement)) {
|
||||
final String scopeDescription = RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true);
|
||||
final String message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.in.module.2",
|
||||
RefactoringUIUtil.getDescription(resolved, true),
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package com.intellij.refactoring.util;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.PsiElementProcessor;
|
||||
import com.intellij.psi.search.PsiElementProcessorAdapter;
|
||||
@@ -129,7 +130,13 @@ public class RefactoringHierarchyUtil {
|
||||
Collections.sort(
|
||||
basesList, new Comparator<PsiClass>() {
|
||||
public int compare(PsiClass c1, PsiClass c2) {
|
||||
return c1.getQualifiedName().compareTo(c2.getQualifiedName());
|
||||
final String fqn1 = c1.getQualifiedName();
|
||||
final String fqn2 = c2.getQualifiedName();
|
||||
if (fqn1 != null && fqn2 != null) return fqn1.compareTo(fqn2);
|
||||
if (fqn1 == null && fqn2 == null) {
|
||||
return Comparing.compare(c1.getName(), c2.getName());
|
||||
}
|
||||
return fqn1 == null ? 1 : -1;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -144,6 +144,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate
|
||||
@Override
|
||||
protected PresentationData createPresentation() {
|
||||
return new PresentationData(){
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getEqualityObjects() {
|
||||
return ArrayUtil.append(super.getEqualityObjects(), changed);
|
||||
|
||||
+1
@@ -70,4 +70,5 @@ public enum JavaSdkVersion {
|
||||
String.format("Can't map Java SDK by description (%s). Available values: %s", description, Arrays.toString(values()))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package com.intellij.openapi.projectRoots;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
|
||||
public class JavaVersionService {
|
||||
public static JavaVersionService getInstance() {
|
||||
return ServiceManager.getService(JavaVersionService.class);
|
||||
}
|
||||
|
||||
public boolean isAtLeast(PsiElement element, JavaSdkVersion version) {
|
||||
return PsiUtil.getLanguageLevel(element).isAtLeast(version.getMaxLanguageLevel());
|
||||
}
|
||||
}
|
||||
@@ -354,7 +354,7 @@ public class TypeConversionUtil {
|
||||
final PsiClass class1 = PsiUtil.resolveClassInType(typeArg1);
|
||||
if (class1 instanceof PsiTypeParameter) {
|
||||
for (PsiType type : class1.getExtendsListTypes()) {
|
||||
if (TypesDistinctProver.provablyDistinct(type, typeArg2)) return false;
|
||||
if (TypesDistinctProver.provablyDistinct(type, typeArg2) && !isAssignable(type, typeArg2)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,10 +656,10 @@ public class TypeConversionUtil {
|
||||
}
|
||||
|
||||
if (left instanceof PsiCapturedWildcardType) {
|
||||
return left.equals(right) || isAssignable(((PsiCapturedWildcardType)left).getLowerBound(), right, allowUncheckedConversion);
|
||||
return left.equals(right) || isAssignable(((PsiCapturedWildcardType)left).getLowerBound(), right, false);
|
||||
}
|
||||
if (right instanceof PsiCapturedWildcardType) {
|
||||
return isAssignable(left, ((PsiCapturedWildcardType)right).getUpperBound(), allowUncheckedConversion);
|
||||
return isAssignable(left, ((PsiCapturedWildcardType)right).getUpperBound(), false);
|
||||
}
|
||||
|
||||
if (left instanceof PsiWildcardType) {
|
||||
@@ -746,7 +746,7 @@ public class TypeConversionUtil {
|
||||
|
||||
private static boolean isAssignableToWildcard(PsiWildcardType wildcardType, PsiType right) {
|
||||
if (wildcardType.isSuper()) {
|
||||
return isAssignable(right, wildcardType.getSuperBound());
|
||||
return isAssignable(wildcardType.getSuperBound(), right);
|
||||
}
|
||||
return isAssignable(wildcardType.getExtendsBound(), right);
|
||||
}
|
||||
@@ -859,7 +859,7 @@ public class TypeConversionUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean typesAgree(PsiType typeLeft, PsiType typeRight, boolean allowUncheckedConversion) {
|
||||
public static boolean typesAgree(PsiType typeLeft, PsiType typeRight, boolean allowUncheckedConversion) {
|
||||
if (typeLeft instanceof PsiWildcardType) {
|
||||
final PsiWildcardType leftWildcard = (PsiWildcardType)typeLeft;
|
||||
final PsiType leftBound = leftWildcard.getBound();
|
||||
|
||||
@@ -92,7 +92,10 @@ public class TypesDistinctProver {
|
||||
for (PsiClassType type : parameter.getExtendsListTypes()) {
|
||||
if (!TypeConversionUtil.isAssignable(type, substitutedType1 != null ? substitutedType1 : substitutedType2, false)) return true;
|
||||
}
|
||||
} else if (provablyDistinct(substitutedType1, substitutedType2)) return true;
|
||||
} else {
|
||||
if (provablyDistinct(substitutedType1, substitutedType2)) return true;
|
||||
if (substitutedType1 instanceof PsiWildcardType && !((PsiWildcardType)substitutedType1).isBounded()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -100,8 +103,8 @@ public class TypesDistinctProver {
|
||||
final PsiClass boundClass1 = classResolveResult1.getElement();
|
||||
final PsiClass boundClass2 = classResolveResult2.getElement();
|
||||
return type2 != null && type1 != null && !type1.equals(type2) &&
|
||||
!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true) &&
|
||||
!InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true);
|
||||
(!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true) ||
|
||||
!InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true));
|
||||
}
|
||||
|
||||
public static boolean provablyDistinct(PsiWildcardType type1, PsiWildcardType type2) {
|
||||
|
||||
@@ -24,6 +24,8 @@ import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.lang.java.JavaParserDefinition;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.JavaVersionService;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.roots.PackageIndex;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -86,6 +88,7 @@ public class JavaCoreEnvironment extends CoreEnvironment {
|
||||
|
||||
myApplication.registerService(EmptySubstitutor.class, new EmptySubstitutorImpl());
|
||||
myApplication.registerService(JavaDirectoryService.class, new CoreJavaDirectoryService());
|
||||
myApplication.registerService(JavaVersionService.class, new JavaVersionService());
|
||||
}
|
||||
|
||||
public void addToClasspath(File path) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve;
|
||||
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.JavaVersionService;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
@@ -160,15 +162,20 @@ public class JavaResolveUtil {
|
||||
|
||||
private static PsiClass getTopLevelClass(@NotNull PsiElement place, PsiClass memberClass) {
|
||||
PsiClass lastClass = null;
|
||||
Boolean isAtLeast17 = null;
|
||||
for (PsiElement placeParent = place; placeParent != null; placeParent = placeParent.getContext()) {
|
||||
if (placeParent instanceof PsiClass &&
|
||||
!(placeParent instanceof PsiAnonymousClass) &&
|
||||
!(placeParent instanceof PsiTypeParameter)) {
|
||||
PsiClass aClass = (PsiClass)placeParent;
|
||||
|
||||
if (memberClass != null && aClass.isInheritor(memberClass, true)) return aClass;
|
||||
|
||||
lastClass = aClass;
|
||||
if (placeParent instanceof PsiClass && !(placeParent instanceof PsiAnonymousClass)) {
|
||||
final boolean isTypeParameter = placeParent instanceof PsiTypeParameter;
|
||||
if (isTypeParameter && isAtLeast17 == null) {
|
||||
isAtLeast17 = JavaVersionService.getInstance().isAtLeast(place, JavaSdkVersion.JDK_1_7);
|
||||
}
|
||||
if (!isTypeParameter || (isAtLeast17 != null && isAtLeast17)) {
|
||||
PsiClass aClass = (PsiClass)placeParent;
|
||||
|
||||
if (memberClass != null && aClass.isInheritor(memberClass, true)) return aClass;
|
||||
|
||||
lastClass = aClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
|
||||
|
||||
protected boolean isShadowed(final PsiMethod candidate) {
|
||||
if (myCurrentFileContext instanceof PsiImportStaticStatement) {
|
||||
for (JavaResolveResult result : getResult()) {
|
||||
for (JavaResolveResult result : getResults()) {
|
||||
if (result.getElement() != candidate &&
|
||||
result.isAccessible() &&
|
||||
!(result.getCurrentFileResolveScope() instanceof PsiImportStaticStatement)) return true;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<orderEntry type="module" module-name="java-i18n" />
|
||||
<orderEntry type="module" module-name="compiler-impl" />
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="module" module-name="notNull" />
|
||||
<orderEntry type="module" module-name="instrumentation-util" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
<orderEntry type="module" module-name="IntelliLang-java" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="IntelliLang-xml" scope="RUNTIME" />
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class Test {
|
||||
public static void bar() {
|
||||
<error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends java.util.Iterator>>', required: 'java.lang.Class<? extends java.util.Iterator<?>>'">Class<? extends Iterator<?>> c = foo();</error>
|
||||
}
|
||||
|
||||
public static Class<? extends Iterator> foo() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -7,7 +7,7 @@ interface Matcher<T> {
|
||||
}
|
||||
|
||||
interface ArgumentConstraintPhrases {
|
||||
<T> T with(Matcher<T> matcher);
|
||||
<error descr="'with(Matcher<T>)' clashes with 'with(Matcher<Boolean>)'; both methods have same erasure"><T> T with(Matcher<T> matcher)</error>;
|
||||
boolean with(Matcher<Boolean> matcher);
|
||||
byte with(Matcher<Byte> matcher);
|
||||
short with(Matcher<Short> matcher);
|
||||
@@ -19,7 +19,7 @@ interface ArgumentConstraintPhrases {
|
||||
|
||||
class ExpectationGroupBuilder implements ArgumentConstraintPhrases {
|
||||
|
||||
public <T> T with(final Matcher<T> matcher) {
|
||||
<error descr="'with(Matcher<T>)' clashes with 'with(Matcher<Boolean>)'; both methods have same erasure">public <T> T with(final Matcher<T> matcher)</error> {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/** @noinspection UnusedDeclaration*/
|
||||
interface Matcher<T> {
|
||||
|
||||
boolean matches(Object object);
|
||||
|
||||
void _dont_implement_Matcher___instead_extend_BaseMatcher_();
|
||||
}
|
||||
|
||||
interface ArgumentConstraintPhrases {
|
||||
<T> T with(Matcher<T> matcher);
|
||||
boolean with(Matcher<Boolean> matcher);
|
||||
byte with(Matcher<Byte> matcher);
|
||||
int with(Matcher<Integer> matcher);
|
||||
long with(Matcher<Long> matcher);
|
||||
float with(Matcher<Float> matcher);
|
||||
double with(Matcher<Double> matcher);
|
||||
}
|
||||
|
||||
class ExpectationGroupBuilder implements ArgumentConstraintPhrases {
|
||||
|
||||
public <T> T with(final Matcher<T> matcher) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean with(final Matcher<Boolean> matcher) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte with(final Matcher<Byte> matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int with(final Matcher<Integer> matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long with(final Matcher<Long> matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float with(final Matcher<Float> matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public double with(final Matcher<Double> matcher) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class A {
|
||||
private int value = 1;
|
||||
|
||||
static class B<T extends A> {
|
||||
void print(T t) {
|
||||
System.out.println(t.<error descr="'value' has private access in 'A'">value</error>);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class A {
|
||||
private int value = 1;
|
||||
|
||||
static class B<T extends A> {
|
||||
void print(T t) {
|
||||
System.out.println(t.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -172,4 +172,48 @@ class My<T> {
|
||||
public void test() {
|
||||
if (getSuperclass() == List.class);
|
||||
}
|
||||
}
|
||||
|
||||
class IDEA75178 {
|
||||
void test(Set<String> labels) {
|
||||
final Matcher<? super Object> empty = isEmpty();
|
||||
assertThat(labels, empty);
|
||||
assertAlsoThat(empty, labels);
|
||||
}
|
||||
|
||||
public static <T> void assertThat(T actual, Matcher<T> matcher) { throw new AssertionError(actual.toString() + matcher.toString());}
|
||||
public static <T> void assertAlsoThat(Matcher<T> matcher, T actual) { throw new AssertionError(actual.toString() + matcher.toString());}
|
||||
|
||||
public static <T> Matcher<? super T> isEmpty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
static class Matcher<<warning descr="Type parameter 'T' is never used">T</warning>>{}
|
||||
|
||||
class Foo {}
|
||||
void testComment() {
|
||||
Set<Foo> foos = Collections.emptySet();
|
||||
assertThatComment(foos, hasSize(0));
|
||||
}
|
||||
|
||||
<E> Matcher<? super Collection<? extends E>> hasSize(int size) {return size == 0 ? null : null;}
|
||||
<T> void assertThatComment(T actual, Matcher<? super T> matcher){ throw new AssertionError(actual.toString() + matcher.toString());}
|
||||
}
|
||||
|
||||
class IDEA66750 {
|
||||
public void test() {
|
||||
List<List<String>> data = new ArrayList<List<String>>();
|
||||
List<List<?>> y = <error descr="Inconvertible types; cannot cast 'java.util.List<java.util.List<java.lang.String>>' to 'java.util.List<java.util.List<?>>'">(List<List<?>>)data</error>;
|
||||
System.out.println(y);
|
||||
|
||||
ArrayList<Number> al = <error descr="Inconvertible types; cannot cast 'java.util.ArrayList<java.lang.Integer>' to 'java.util.ArrayList<java.lang.Number>'">(ArrayList<Number>) new ArrayList<Integer>(1)</error>;
|
||||
System.out.println(al);
|
||||
}
|
||||
}
|
||||
|
||||
class IDEA73377 {
|
||||
public Iterator<Map.Entry<Map.Entry<?, ?>, ?>> iterator(Map<?, ?> map) {
|
||||
//noinspection unchecked
|
||||
return <error descr="Inconvertible types; cannot cast 'java.util.Iterator<java.util.Map.Entry<capture<?>,capture<?>>>' to 'java.util.Iterator<java.util.Map.Entry<java.util.Map.Entry<?,?>,?>>'">(Iterator<Map.Entry<Map.Entry<?, ?>, ?>>)map.entrySet().iterator()</error>;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Iterate" "false"
|
||||
class Test {
|
||||
void foo() {
|
||||
final Annotation[] annotations = getClass().getAnnotat<caret>ions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Pull method 'foo' to 'Foo' and make it abstract" "true"
|
||||
public class Test {
|
||||
void bar() {
|
||||
abstract class Foo {
|
||||
abstract void foo();
|
||||
}
|
||||
class FooImpl extends Foo {
|
||||
@Override
|
||||
void foo(){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Pull method 'foo' to 'Foo' and make it abstract" "true"
|
||||
public class Test {
|
||||
void bar() {
|
||||
class Foo {}
|
||||
class FooImpl extends Foo {
|
||||
@Overr<caret>ide
|
||||
void foo(){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -3,7 +3,7 @@
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
public class ModuleSourceAsLibrarySource {
|
||||
<ref>ModuleSourceAsLibrarySourceDep field;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
public class ModuleSourceAsLibrarySourceDep {}
|
||||
@@ -37,7 +37,7 @@ public class SuppressExternalTest extends UsefulTestCase {
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> testFixtureBuilder = fixtureFactory.createFixtureBuilder();
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> testFixtureBuilder = fixtureFactory.createFixtureBuilder(getName());
|
||||
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(testFixtureBuilder.getFixture());
|
||||
myFixture.setTestDataPath(PathManagerEx.getTestDataPath() + "/codeInsight/externalAnnotations");
|
||||
final JavaModuleFixtureBuilder builder = testFixtureBuilder.addModule(JavaModuleFixtureBuilder.class);
|
||||
|
||||
+21
-1
@@ -4,6 +4,8 @@ import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection;
|
||||
import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection;
|
||||
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiClass;
|
||||
@@ -30,10 +32,24 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
LanguageLevel level = getTestName(false).contains("Level6") ? LanguageLevel.JDK_1_6 : LanguageLevel.JDK_1_5;
|
||||
LanguageLevel level;
|
||||
final String testName = getTestName(false);
|
||||
if (testName.contains("Level17")) {
|
||||
level = LanguageLevel.JDK_1_7;
|
||||
} else if (testName.contains("Level6")) {
|
||||
level = LanguageLevel.JDK_1_6;
|
||||
}
|
||||
else {
|
||||
level = LanguageLevel.JDK_1_5;
|
||||
}
|
||||
LanguageLevelProjectExtension.getInstance(getJavaFacade().getProject()).setLanguageLevel(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return getTestName(false).contains("Jdk14") ? JavaSdkImpl.getMockJdk14() : super.getProjectJDK();
|
||||
}
|
||||
|
||||
public void testReferenceTypeParams() throws Exception { doTest(false); }
|
||||
public void testOverridingMethods() throws Exception { doTest(false); }
|
||||
public void testTypeParameterBoundsList() throws Exception { doTest(false); }
|
||||
@@ -85,6 +101,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
|
||||
public void testGenericExtendException() throws Exception { doTest(false); }
|
||||
public void testSameErasureDifferentReturnTypes() throws Exception { doTest(false); }
|
||||
public void testSameErasureDifferentReturnTypesJdk14() throws Exception { doTest(false); }
|
||||
public void testDeepConflictingReturnTypes() throws Exception { doTest(false); }
|
||||
public void testInheritFromTypeParameter() throws Exception { doTest(false); }
|
||||
public void testAnnotationsAsPartOfModifierList() throws Exception { doTest(false); }
|
||||
@@ -98,6 +115,9 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testInnerClassRef() throws Exception { doTest(false); }
|
||||
public void testPrivateInnerClassRef() throws Exception { doTest(false); }
|
||||
public void testWideningCastToTypeParam() throws Exception { doTest(false); }
|
||||
public void testCapturedWildcardAssignments() throws Exception { doTest(false);}
|
||||
public void testTypeParameterBoundVisibility() throws Exception { doTest(false);}
|
||||
public void testTypeParameterBoundVisibilityJdk14() throws Exception { doTest(false);}
|
||||
|
||||
public void testJavaUtilCollections_NoVerify() throws Exception {
|
||||
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
|
||||
|
||||
+4
@@ -34,6 +34,10 @@ public class PullOverrideMethodUpFixTest extends LightQuickFixTestCase {
|
||||
doSingleTest("4.java");
|
||||
}
|
||||
|
||||
public void test6() throws Exception {
|
||||
doSingleTest("6.java");
|
||||
}
|
||||
|
||||
public void testRefactoringIntentionsAvailable() throws Exception {
|
||||
doTestActionAvailable(5, "Pull members up");
|
||||
doTestActionAvailable(5, "Extract interface");
|
||||
|
||||
+62
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 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.
|
||||
@@ -618,7 +618,7 @@ class Test {
|
||||
doTest(before, toPaste2, expected)
|
||||
}
|
||||
|
||||
def testPlainTextPaste() {
|
||||
void testPlainTextPaste() {
|
||||
def before = '''\
|
||||
line1
|
||||
line2
|
||||
@@ -628,7 +628,7 @@ class Test {
|
||||
def toPaste =
|
||||
'''\
|
||||
line to paste #1
|
||||
line to paste #2
|
||||
line to paste #2\
|
||||
'''
|
||||
|
||||
|
||||
@@ -641,10 +641,33 @@ line to paste #1
|
||||
doTest(before, toPaste, expected, StdFileTypes.PLAIN_TEXT)
|
||||
}
|
||||
|
||||
def testPlainTextPasteWithCompleteReplacement() {
|
||||
void "test plain text when pasted string ends by line feed"() {
|
||||
def before = '''\
|
||||
line1
|
||||
line2
|
||||
<caret>
|
||||
'''
|
||||
|
||||
def toPaste =
|
||||
'''\
|
||||
line to paste #1
|
||||
line to paste #2
|
||||
'''
|
||||
|
||||
def expected = '''\
|
||||
line1
|
||||
line2
|
||||
line to paste #1
|
||||
line to paste #2
|
||||
|
||||
'''
|
||||
doTest(before, toPaste, expected, StdFileTypes.PLAIN_TEXT)
|
||||
}
|
||||
|
||||
void "test plain text when caret is after selection"() {
|
||||
def before = '''\
|
||||
<selection> line1
|
||||
line2</selection>\
|
||||
</selection><caret>\
|
||||
'''
|
||||
|
||||
def toPaste =
|
||||
@@ -655,32 +678,14 @@ line to paste #2
|
||||
|
||||
|
||||
def expected = '''\
|
||||
line1
|
||||
line to paste #1
|
||||
line to paste #2
|
||||
'''
|
||||
doTest(before, toPaste, expected, StdFileTypes.PLAIN_TEXT)
|
||||
}
|
||||
|
||||
def testPlainTextMultilinePasteWithCaretAfterSelection() {
|
||||
def before = '''\
|
||||
<selection> line1</selection><caret>\
|
||||
'''
|
||||
|
||||
def toPaste =
|
||||
'''\
|
||||
line to paste #1
|
||||
line to paste #2
|
||||
'''
|
||||
|
||||
|
||||
def expected = '''\
|
||||
line to paste #1
|
||||
line to paste #2
|
||||
'''
|
||||
doTest(before, toPaste, expected, StdFileTypes.PLAIN_TEXT)
|
||||
}
|
||||
|
||||
def testPlainTextThatStartsByLineFeed() {
|
||||
void testPlainTextThatStartsByLineFeed() {
|
||||
def before = '''\
|
||||
line 1
|
||||
# item1<caret>
|
||||
@@ -715,6 +720,37 @@ line 1
|
||||
doTest(before, toPaste2, expected2, StdFileTypes.PLAIN_TEXT)
|
||||
}
|
||||
|
||||
void "test formatter-based paste that starts with white space"() {
|
||||
def before = '''\
|
||||
class Test {
|
||||
int i;
|
||||
int j;
|
||||
|
||||
void test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
def toPaste = '''\
|
||||
int i;
|
||||
int j;\
|
||||
'''
|
||||
|
||||
def expected = '''\
|
||||
class Test {
|
||||
int i;
|
||||
int j;
|
||||
|
||||
void test() {
|
||||
int i;
|
||||
int j;
|
||||
}
|
||||
}
|
||||
'''
|
||||
doTest(before, toPaste, expected)
|
||||
}
|
||||
|
||||
def doTest(String before, toPaste, expected, FileType fileType = StdFileTypes.JAVA) {
|
||||
myFixture.configureByText(fileType, before)
|
||||
|
||||
@@ -732,6 +768,7 @@ line 1
|
||||
finally {
|
||||
settings.REFORMAT_ON_PASTE = old
|
||||
}
|
||||
myFixture.editor.selectionModel.removeSelection()
|
||||
myFixture.checkResult(expected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,32 @@ class Test {
|
||||
assertEquals(2, closureFolds.size())
|
||||
}
|
||||
|
||||
public void "test closure folding doesn't expand when editing inside"() {
|
||||
def text = """\
|
||||
class Test {
|
||||
void test() {
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
System.out.println(<caret>);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
configure text
|
||||
def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl
|
||||
def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable"))
|
||||
assertNotNull closureStartFold
|
||||
assertFalse closureStartFold.expanded
|
||||
assert text.substring(closureStartFold.endOffset).startsWith('System') //one line closure
|
||||
|
||||
myFixture.type('2')
|
||||
myFixture.doHighlighting()
|
||||
closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable"))
|
||||
assert closureStartFold
|
||||
}
|
||||
|
||||
public void testFindInFolding() {
|
||||
def text = """\
|
||||
class Test {
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.profile.codeInspection.InspectionProfileManager;
|
||||
import com.intellij.testFramework.LightIdeaTestCase;
|
||||
@@ -25,6 +26,9 @@ import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.testFramework.PlatformTestUtil.assertElementsEqual;
|
||||
|
||||
@@ -171,4 +175,63 @@ public class InspectionProfileTest extends LightIdeaTestCase {
|
||||
profile.writeExternal(copy);
|
||||
assertElementsEqual(element, copy);
|
||||
}
|
||||
|
||||
public void testLockProfile() throws Exception {
|
||||
|
||||
final List<InspectionToolWrapper> list = new ArrayList<InspectionToolWrapper>();
|
||||
list.add(createTool("foo"));
|
||||
|
||||
InspectionToolRegistrar registrar = new InspectionToolRegistrar(null) {
|
||||
@Override
|
||||
public List<InspectionToolWrapper> createTools() {
|
||||
LocalInspectionEP foo = new LocalInspectionEP();
|
||||
foo.shortName = "foo";
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
InspectionProfileImpl profile = new InspectionProfileImpl("Foo", registrar, InspectionProfileManager.getInstance());
|
||||
profile.setBaseProfile(null);
|
||||
List<ScopeToolState> tools = profile.getAllTools();
|
||||
assertEquals(1, tools.size());
|
||||
ModifiableModel model = profile.getModifiableModel();
|
||||
model.lockProfile(true);
|
||||
model.commit();
|
||||
Element element = new Element("element");
|
||||
profile.writeExternal(element);
|
||||
|
||||
list.add(createTool("bar"));
|
||||
|
||||
profile = new InspectionProfileImpl("Foo", registrar, InspectionProfileManager.getInstance());
|
||||
profile.readExternal(element);
|
||||
|
||||
profile.setBaseProfile(null);
|
||||
tools = profile.getAllTools();
|
||||
assertEquals(2, tools.size());
|
||||
|
||||
assertTrue(profile.isProfileLocked());
|
||||
assertFalse(profile.isToolEnabled(HighlightDisplayKey.find("bar")));
|
||||
}
|
||||
|
||||
public void testGlobalInspectionContext() throws Exception {
|
||||
InspectionProfileImpl profile = new InspectionProfileImpl("Foo");
|
||||
profile.disableAllTools();
|
||||
profile.enableTool(new UnusedDeclarationInspection().getShortName());
|
||||
|
||||
GlobalInspectionContextImpl context = ((InspectionManagerEx)InspectionManager.getInstance(getProject())).createNewGlobalContext(false);
|
||||
context.setExternalProfile(profile);
|
||||
context.initializeTools(new ArrayList<Tools>(), new ArrayList<Tools>(), new ArrayList<Tools>());
|
||||
Map<String,Tools> tools = context.getTools();
|
||||
assertEquals(1, tools.size());
|
||||
}
|
||||
|
||||
private static LocalInspectionToolWrapper createTool(String s) {
|
||||
LocalInspectionEP foo = new LocalInspectionEP();
|
||||
foo.shortName = s;
|
||||
foo.displayName = s;
|
||||
foo.groupDisplayName = s;
|
||||
foo.level = "ERROR";
|
||||
foo.enabledByDefault = true;
|
||||
return new LocalInspectionToolWrapper(foo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.intellij.openapi.module.StdModuleTypes;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
@@ -155,6 +156,16 @@ public class ResolveClassTest extends ResolveTestCase {
|
||||
assertNull(target);
|
||||
}
|
||||
|
||||
public void testModuleSourceAsLibrarySource() throws Exception {
|
||||
final PsiReference ref = configure();
|
||||
final VirtualFile file = ref.getElement().getContainingFile().getVirtualFile();
|
||||
assertNotNull(file);
|
||||
createFile(myModule, file.getParent(), "ModuleSourceAsLibrarySourceDep.java", loadFile("class/ModuleSourceAsLibrarySourceDep.java"));
|
||||
addLibraryToRoots(file.getParent(), OrderRootType.SOURCES);
|
||||
|
||||
assertInstanceOf(ref.resolve(), PsiClass.class);
|
||||
}
|
||||
|
||||
public void testStaticImportInTheSameClass() throws Exception {
|
||||
PsiReference ref = configure();
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.psi.resolve
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class ResolveInLibrariesTest extends JavaCodeInsightFixtureTestCase {
|
||||
|
||||
public void "test prefer current library when navigation from its source"() {
|
||||
def lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib")
|
||||
def nanoJar = lib.children.find { it.name.startsWith("nanoxml") }
|
||||
def nanoSrc = lib.findChild("src").children.find { it.name.startsWith("nanoxml") }
|
||||
|
||||
def jarCopy = myFixture.copyFileToProject(nanoJar.path, 'lib/nanoJar.jar')
|
||||
def srcCopy = myFixture.copyFileToProject(nanoSrc.path, 'lib/nanoSrc.zip')
|
||||
|
||||
PsiTestUtil.addLibrary(myModule, 'nano1', lib.path, ["/$nanoJar.name!/"] as String[], ["/src/$nanoSrc.name!/"] as String[])
|
||||
PsiTestUtil.addLibrary(myModule, 'nano2', jarCopy.parent.path, ["/$jarCopy.name!/"] as String[], ["/$srcCopy.name!/"] as String[])
|
||||
|
||||
def parsers = JavaPsiFacade.getInstance(project).findClasses('net.n3.nanoxml.IXMLParser', GlobalSearchScope.allScope(project))
|
||||
assert parsers.size() == 2
|
||||
|
||||
def file0 = parsers[0].navigationElement.containingFile
|
||||
assert file0.virtualFile.path.startsWith(nanoSrc.path)
|
||||
assert file0.findReferenceAt(file0.text.indexOf('IXMLReader reader')).resolve().navigationElement.containingFile.virtualFile.path.startsWith(nanoSrc.path)
|
||||
|
||||
def file1 = parsers[1].navigationElement.containingFile
|
||||
assert file1.virtualFile.path.startsWith(srcCopy.path)
|
||||
assert file1.findReferenceAt(file1.text.indexOf('IXMLReader reader')).resolve().navigationElement.containingFile.virtualFile.path.startsWith(srcCopy.path)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.openapi.projectRoots;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 3/28/12
|
||||
*/
|
||||
public class JavaSdkVersionUtil {
|
||||
public static boolean isAtLeast(PsiElement element, JavaSdkVersion minVersion) {
|
||||
final Module module = ModuleUtil.findModuleForPsiElement(element);
|
||||
if (module != null) {
|
||||
final Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
|
||||
if (sdk != null && sdk.getSdkType() instanceof JavaSdk) {
|
||||
final JavaSdkVersion version = JavaSdk.getInstance().getVersion(sdk);
|
||||
return version != null && version.isAtLeast(minVersion);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +216,7 @@ public abstract class PsiTestCase extends ModuleTestCase {
|
||||
addLibraryToRoots(myModule, jarFile, rootType);
|
||||
}
|
||||
|
||||
protected static void addLibraryToRoots(final Module module, final VirtualFile jarFile, final OrderRootType rootType) {
|
||||
protected static void addLibraryToRoots(final Module module, final VirtualFile root, final OrderRootType rootType) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -224,7 +224,7 @@ public abstract class PsiTestCase extends ModuleTestCase {
|
||||
final ModifiableRootModel rootModel = manager.getModifiableModel();
|
||||
final Library jarLibrary = rootModel.getModuleLibraryTable().createLibrary();
|
||||
final Library.ModifiableModel libraryModel = jarLibrary.getModifiableModel();
|
||||
libraryModel.addRoot(jarFile, rootType);
|
||||
libraryModel.addRoot(root, rootType);
|
||||
libraryModel.commit();
|
||||
rootModel.commit();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<orderEntry type="module" module-name="util" exported="" />
|
||||
<orderEntry type="module" module-name="forms_rt" />
|
||||
<orderEntry type="module" module-name="forms-compiler" />
|
||||
<orderEntry type="module" module-name="notNull" />
|
||||
<orderEntry type="module" module-name="instrumentation-util" />
|
||||
<orderEntry type="library" exported="" name="asm" level="project" />
|
||||
<orderEntry type="library" name="JDOM" level="project" />
|
||||
<orderEntry type="library" name="NanoXML" level="project" />
|
||||
|
||||
@@ -9,4 +9,5 @@ public interface GlobalOptions {
|
||||
String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process";
|
||||
String HOSTNAME_OPTION = "localhost.name";
|
||||
String PING_INTERVAL_MS_OPTION = "server.ping.interval";
|
||||
String GENERATE_CLASSPATH_INDEX_OPTION = "generate.classpath.index";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.jetbrains.jps.api;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 3/29/12
|
||||
*/
|
||||
public class SharedThreadPool {
|
||||
public static final ExecutorService INSTANCE = Executors.newCachedThreadPool();
|
||||
public static final AsyncTaskExecutor ASYNC_EXEC = new AsyncTaskExecutor() {
|
||||
@Override
|
||||
public void submit(Runnable runnable) {
|
||||
INSTANCE.submit(runnable);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class SimpleProtobufClient<T extends ProtobufResponseHandler> {
|
||||
private final AtomicReference<State> myState = new AtomicReference<State>(State.DISCONNECTED);
|
||||
protected final ChannelPipelineFactory myPipelineFactory;
|
||||
protected final ChannelFactory myChannelFactory;
|
||||
protected ChannelFuture myConnectFuture;
|
||||
protected volatile ChannelFuture myConnectFuture;
|
||||
private final ProtobufClientMessageHandler<T> myMessageHandler;
|
||||
|
||||
public SimpleProtobufClient(final MessageLite msgDefaultInstance, final AsyncTaskExecutor asyncExec, final UUIDGetter uuidGetter) {
|
||||
@@ -146,8 +146,9 @@ public class SimpleProtobufClient<T extends ProtobufResponseHandler> {
|
||||
public final RequestFuture<T> sendMessage(final UUID messageId, MessageLite message, @Nullable final T responseHandler, @Nullable final RequestFuture.CancelAction<T> cancelAction) {
|
||||
final RequestFuture<T> requestFuture = new RequestFuture<T>(responseHandler, messageId, cancelAction);
|
||||
myMessageHandler.registerFuture(messageId, requestFuture);
|
||||
final Channel channel = myConnectFuture.getChannel();
|
||||
if (channel.isConnected()) {
|
||||
final ChannelFuture connectFuture = myConnectFuture;
|
||||
final Channel channel = connectFuture != null? connectFuture.getChannel() : null;
|
||||
if (channel != null && channel.isConnected()) {
|
||||
Channels.write(channel, message).addListener(new ChannelFutureListener() {
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (!future.isSuccess()) {
|
||||
|
||||
@@ -30,7 +30,7 @@ public class BuilderRegistry {
|
||||
myTasksExecutor = Executors.newFixedThreadPool(runtime.availableProcessors());
|
||||
runtime.addShutdownHook(new Thread() {
|
||||
public void run() {
|
||||
myTasksExecutor.shutdownNow();
|
||||
myTasksExecutor.shutdown();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ public class BuilderRegistry {
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
myTasksExecutor.shutdownNow();
|
||||
myTasksExecutor.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ import com.intellij.util.io.MappingFailedException;
|
||||
import com.intellij.util.io.PersistentEnumerator;
|
||||
import org.jetbrains.jps.*;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.api.GlobalOptions;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.api.SharedThreadPool;
|
||||
import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilder;
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilderLogger;
|
||||
@@ -21,10 +23,13 @@ import org.jetbrains.jps.incremental.storage.SourceToFormMapping;
|
||||
import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
|
||||
import org.jetbrains.jps.server.ProjectDescriptor;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -35,6 +40,8 @@ public class IncProjectBuilder {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder");
|
||||
|
||||
public static final String COMPILE_SERVER_NAME = "COMPILE SERVER";
|
||||
private static final String CLASSPATH_INDEX_FINE_NAME = "classpath.index";
|
||||
private static final boolean GENERATE_CLASSPATH_INDEX = "true".equals(System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION));
|
||||
|
||||
private final ProjectDescriptor myProjectDescriptor;
|
||||
private final BuilderRegistry myBuilderRegistry;
|
||||
@@ -54,6 +61,7 @@ public class IncProjectBuilder {
|
||||
private float myModulesProcessed = 0.0f;
|
||||
private final float myTotalModulesWork;
|
||||
private final int myTotalModuleLevelBuilderCount;
|
||||
private final List<Future> myAsyncTasks = new ArrayList<Future>();
|
||||
|
||||
public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry, Map<String, String> builderParams, CanceledStatus cs) {
|
||||
myProjectDescriptor = pd;
|
||||
@@ -131,6 +139,15 @@ public class IncProjectBuilder {
|
||||
finally {
|
||||
memWatcher.stop();
|
||||
flushContext(context);
|
||||
// wait for the async tasks
|
||||
for (Future task : myAsyncTasks) {
|
||||
try {
|
||||
task.get();
|
||||
}
|
||||
catch (Throwable th) {
|
||||
LOG.info(th);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,16 +326,18 @@ public class IncProjectBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildChunk(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
|
||||
private void buildChunk(CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
|
||||
boolean doneSomething = false;
|
||||
try {
|
||||
context.ensureFSStateInitialized(chunk);
|
||||
if (context.isMake()) {
|
||||
processDeletedPaths(context, chunk);
|
||||
doneSomething |= context.hasRemovedSources();
|
||||
}
|
||||
|
||||
context.onChunkBuildStart(chunk);
|
||||
|
||||
runModuleLevelBuilders(context, chunk);
|
||||
doneSomething = runModuleLevelBuilders(context, chunk);
|
||||
}
|
||||
catch (ProjectBuildException e) {
|
||||
throw e;
|
||||
@@ -343,11 +362,59 @@ public class IncProjectBuilder {
|
||||
}
|
||||
finally {
|
||||
Paths.CHUNK_REMOVED_SOURCES_KEY.set(context, null);
|
||||
if (doneSomething && GENERATE_CLASSPATH_INDEX) {
|
||||
final boolean forTests = context.isCompilingTests();
|
||||
final Future<?> future = SharedThreadPool.INSTANCE.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
createClasspathIndex(chunk, forTests);
|
||||
}
|
||||
});
|
||||
myAsyncTasks.add(future);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createClasspathIndex(final ModuleChunk chunk, boolean forTests) {
|
||||
final Set<File> outputPaths = new LinkedHashSet<File>();
|
||||
for (Module module : chunk.getModules()) {
|
||||
if (forTests) {
|
||||
outputPaths.add(new File(module.getTestOutputPath()));
|
||||
}
|
||||
else {
|
||||
outputPaths.add(new File(module.getOutputPath()));
|
||||
}
|
||||
}
|
||||
for (File outputRoot : outputPaths) {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outputRoot, CLASSPATH_INDEX_FINE_NAME)));
|
||||
try {
|
||||
writeIndex(writer, outputRoot, "");
|
||||
}
|
||||
finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore. Failed to create optional classpath index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeIndex(final BufferedWriter writer, final File file, final String path) throws IOException {
|
||||
writer.write(path);
|
||||
writer.write('\n');
|
||||
final File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File child : files) {
|
||||
writeIndex(writer, child, path + "/" + child.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processDeletedPaths(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
|
||||
try {
|
||||
// cleanup outputs
|
||||
@@ -420,13 +487,14 @@ public class IncProjectBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void runModuleLevelBuilders(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
|
||||
// return true if changed something, false otherwise
|
||||
private boolean runModuleLevelBuilders(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
|
||||
boolean doneSomething = false;
|
||||
boolean rebuildFromScratchRequested = false;
|
||||
float stageCount = myTotalModuleLevelBuilderCount;
|
||||
final int modulesInChunk = chunk.getModules().size();
|
||||
int buildersPassed = 0;
|
||||
boolean nextPassRequired;
|
||||
|
||||
do {
|
||||
nextPassRequired = false;
|
||||
context.beforeCompileRound(chunk);
|
||||
@@ -448,6 +516,8 @@ public class IncProjectBuilder {
|
||||
}
|
||||
final ModuleLevelBuilder.ExitCode buildResult = builder.build(context, chunk);
|
||||
|
||||
doneSomething |= (buildResult != ModuleLevelBuilder.ExitCode.NOTHING_DONE);
|
||||
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
|
||||
throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
|
||||
}
|
||||
@@ -492,6 +562,8 @@ public class IncProjectBuilder {
|
||||
}
|
||||
}
|
||||
while (nextPassRequired);
|
||||
|
||||
return doneSomething;
|
||||
}
|
||||
|
||||
private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException {
|
||||
|
||||
@@ -32,7 +32,7 @@ public abstract class ModuleLevelBuilder extends Builder {
|
||||
}
|
||||
|
||||
public static enum ExitCode {
|
||||
OK, ABORT, ADDITIONAL_PASS_REQUIRED, CHUNK_REBUILD_REQUIRED
|
||||
NOTHING_DONE, OK, ABORT, ADDITIONAL_PASS_REQUIRED, CHUNK_REBUILD_REQUIRED
|
||||
}
|
||||
|
||||
public abstract ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
|
||||
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
|
||||
import com.intellij.execution.process.BaseOSProcessHandler;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
@@ -31,13 +33,11 @@ import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.EmptyVisitor;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.*;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -238,7 +238,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
|
||||
private ExitCode compile(final CompileContext context, ModuleChunk chunk, Collection<File> files, Collection<File> forms)
|
||||
throws Exception {
|
||||
ExitCode exitCode = ExitCode.OK;
|
||||
ExitCode exitCode = ExitCode.NOTHING_DONE;
|
||||
|
||||
final boolean hasSourcesToCompile = !files.isEmpty() || !forms.isEmpty();
|
||||
|
||||
@@ -263,6 +263,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
DELTA_MAPPINGS_CALLBACK_KEY.set(context, delta.getCallback());
|
||||
try {
|
||||
if (hasSourcesToCompile) {
|
||||
exitCode = ExitCode.OK;
|
||||
final Set<File> sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.<File>emptySet());
|
||||
|
||||
final String chunkName = getChunkPresentableName(chunk);
|
||||
@@ -274,15 +275,14 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
context.checkCanceled();
|
||||
|
||||
if (!forms.isEmpty() || addNotNullAssertions) {
|
||||
final InstrumentationClassFinder finder = createInstrumentationClassFinder(platformCp, classpath, outputSink);
|
||||
final Map<File, String> chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests());
|
||||
final InstrumentationClassFinder finder = createInstrumentationClassFinder(platformCp, classpath, chunkSourcePath, outputSink);
|
||||
|
||||
try {
|
||||
if (!forms.isEmpty()) {
|
||||
try {
|
||||
context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]"));
|
||||
final Map<File, String> chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests());
|
||||
final ClassLoader loader = createInstrumentationClassLoader(platformCp, classpath, chunkSourcePath, outputSink);
|
||||
instrumentForms(context, chunk, chunkSourcePath, loader, finder, forms, outputSink);
|
||||
instrumentForms(context, chunk, chunkSourcePath, finder, forms, outputSink);
|
||||
}
|
||||
finally {
|
||||
context.processMessage(new ProgressMessage("Finished instrumenting forms [" + chunkName + "]"));
|
||||
@@ -529,22 +529,24 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
|
||||
private static InstrumentationClassFinder createInstrumentationClassFinder(Collection<File> platformCp,
|
||||
Collection<File> classpath,
|
||||
final OutputFilesSink outputSink) throws MalformedURLException {
|
||||
Map<File, String> chunkSourcePath, final OutputFilesSink outputSink) throws MalformedURLException {
|
||||
final URL[] platformUrls = new URL[platformCp.size()];
|
||||
int index = 0;
|
||||
for (File file : platformCp) {
|
||||
platformUrls[index++] = file.toURI().toURL();
|
||||
}
|
||||
|
||||
final URL[] urls = new URL[classpath.size() + 1];
|
||||
index = 0;
|
||||
final List<URL> urls = new ArrayList<URL>(classpath.size() + chunkSourcePath.size() + 1);
|
||||
for (File file : classpath) {
|
||||
urls[index++] = file.toURI().toURL();
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
urls[index++] = getResourcePath(GridConstraints.class).toURI().toURL(); // forms_rt.jar
|
||||
urls.add(getResourcePath(GridConstraints.class).toURI().toURL()); // forms_rt.jar
|
||||
//urls.add(getResourcePath(CellConstraints.class).toURI().toURL()); // jgoodies-forms
|
||||
|
||||
return new InstrumentationClassFinder(platformUrls, urls) {
|
||||
for (File file : chunkSourcePath.keySet()) { // sourcepath for loading forms resources
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
|
||||
return new InstrumentationClassFinder(platformUrls, urls.toArray(new URL[urls.size()])) {
|
||||
protected InputStream lookupClassBeforeClasspath(String internalClassName) {
|
||||
final OutputFileObject.Content content = outputSink.lookupClassBytes(internalClassName.replace("/", "."));
|
||||
if (content != null) {
|
||||
@@ -555,23 +557,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
};
|
||||
}
|
||||
|
||||
private static ClassLoader createInstrumentationClassLoader(Collection<File> platformCp, Collection<File> classpath,
|
||||
Map<File, String> chunkSourcePath,
|
||||
OutputFilesSink outputSink) throws MalformedURLException {
|
||||
final List<URL> urls = new ArrayList<URL>();
|
||||
for (Collection<File> cp : Arrays.asList(platformCp, classpath)) {
|
||||
for (File file : cp) {
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
}
|
||||
urls.add(getResourcePath(GridConstraints.class).toURI().toURL()); // forms_rt.jar
|
||||
//urls.add(getResourcePath(CellConstraints.class).toURI().toURL()); // jgoodies-forms
|
||||
for (File file : chunkSourcePath.keySet()) {
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
return new CompiledClassesLoader(outputSink, urls.toArray(new URL[urls.size()]));
|
||||
}
|
||||
|
||||
private static final Key<List<String>> JAVAC_OPTIONS = Key.create("_javac_options_");
|
||||
private static final Key<List<String>> JAVAC_VM_OPTIONS = Key.create("_javac_vm_options_");
|
||||
|
||||
@@ -713,7 +698,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
private static void instrumentForms(CompileContext context,
|
||||
ModuleChunk chunk,
|
||||
final Map<File, String> chunkSourcePath,
|
||||
final ClassLoader loader,
|
||||
final InstrumentationClassFinder finder, Collection<File> formsToInstrument,
|
||||
OutputFilesSink outputSink) throws ProjectBuildException {
|
||||
|
||||
@@ -731,7 +715,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
for (File formFile : formsToInstrument) {
|
||||
final LwRootContainer rootContainer;
|
||||
try {
|
||||
rootContainer = Utils.getRootContainer(formFile.toURI().toURL(), new CompiledClassPropertiesProvider(loader));
|
||||
rootContainer = Utils.getRootContainer(formFile.toURI().toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
|
||||
}
|
||||
catch (AlienFormFileException e) {
|
||||
// ignore non-IDEA forms
|
||||
@@ -774,7 +758,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
|
||||
final int version = getClassFileVersion(classReader);
|
||||
final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
|
||||
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader, nestedFormsLoader, false, classWriter);
|
||||
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, nestedFormsLoader, false, classWriter);
|
||||
final byte[] patchedBytes = codeGenerator.patchClass(classReader);
|
||||
if (patchedBytes != null) {
|
||||
outputClassFile.updateContent(patchedBytes);
|
||||
@@ -884,7 +868,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
myContext.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "OutOfMemoryError: insufficient memory"));
|
||||
}
|
||||
else {
|
||||
myContext.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, line));
|
||||
final BuildMessage.Kind kind = line.toLowerCase(Locale.US).contains("error")? BuildMessage.Kind.ERROR : BuildMessage.Kind.INFO;
|
||||
myContext.processMessage(new CompilerMessage(BUILDER_NAME, kind, line));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -923,42 +908,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstrumenterClassWriter extends ClassWriter {
|
||||
private final InstrumentationClassFinder myFinder;
|
||||
|
||||
public InstrumenterClassWriter(int flags, final InstrumentationClassFinder finder) {
|
||||
super(flags);
|
||||
myFinder = finder;
|
||||
}
|
||||
|
||||
protected String getCommonSuperClass(final String type1, final String type2) {
|
||||
try {
|
||||
final InstrumentationClassFinder.PseudoClass cls1 = myFinder.loadClass(type1);
|
||||
final InstrumentationClassFinder.PseudoClass cls2 = myFinder.loadClass(type2);
|
||||
if (cls1.isAssignableFrom(cls2)) {
|
||||
return cls1.getName();
|
||||
}
|
||||
if (cls2.isAssignableFrom(cls1)) {
|
||||
return cls2.getName();
|
||||
}
|
||||
if (cls1.isInterface() || cls2.isInterface()) {
|
||||
return "java/lang/Object";
|
||||
}
|
||||
else {
|
||||
InstrumentationClassFinder.PseudoClass c = cls1;
|
||||
do {
|
||||
c = c.getSuperClass();
|
||||
}
|
||||
while (!c.isAssignableFrom(cls2));
|
||||
return c.getName();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyNestedFormLoader implements NestedFormLoader {
|
||||
private final Map<File, String> mySourceRoots;
|
||||
private final Collection<File> myOutputRoots;
|
||||
@@ -1039,27 +988,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return new File(PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"));
|
||||
}
|
||||
|
||||
private static class CompiledClassesLoader extends URLClassLoader {
|
||||
private final OutputFilesSink mySink;
|
||||
|
||||
public CompiledClassesLoader(OutputFilesSink sink, URL[] urls) {
|
||||
super(urls, null);
|
||||
mySink = sink;
|
||||
}
|
||||
|
||||
protected Class findClass(String name) throws ClassNotFoundException {
|
||||
final OutputFileObject.Content content = mySink.lookupClassBytes(name);
|
||||
if (content != null) {
|
||||
return defineClass(name, content.getBuffer(), content.getOffset(), content.getLength());
|
||||
}
|
||||
return super.findClass(name);
|
||||
}
|
||||
|
||||
public URL findResource(String name) {
|
||||
return super.findResource(name);
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassProcessingConsumer implements OutputFileConsumer {
|
||||
private final CompileContext myCompileContext;
|
||||
private final OutputFileConsumer myDelegateOutputFileSink;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jps.incremental.resources;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import org.jetbrains.jps.Module;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
@@ -38,12 +39,14 @@ public class ResourcesBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
try {
|
||||
final ResourcePatterns finalPatterns = patterns;
|
||||
final Ref<Boolean> doneSomething = new Ref<Boolean>(false);
|
||||
context.processFilesToRecompile(chunk, new FileProcessor() {
|
||||
public boolean apply(final Module module, final File file, final String sourceRoot) throws IOException {
|
||||
if (finalPatterns.isResourceFile(file, sourceRoot)) {
|
||||
try {
|
||||
context.processMessage(new ProgressMessage("Copying " + file.getPath()));
|
||||
final String moduleName = module.getName().toLowerCase(Locale.US);
|
||||
doneSomething.set(true);
|
||||
copyResource(context, module, file, sourceRoot, context.getDataManager().getSourceToOutputMap(moduleName, context.isCompilingTests()));
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -56,7 +59,7 @@ public class ResourcesBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
});
|
||||
|
||||
return ExitCode.OK;
|
||||
return doneSomething.get()? ExitCode.OK : ExitCode.NOTHING_DONE;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ProjectBuildException(e.getMessage(), e);
|
||||
|
||||
@@ -2,31 +2,22 @@ package org.jetbrains.jps.javac;
|
||||
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.api.AsyncTaskExecutor;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.api.SharedThreadPool;
|
||||
import org.jetbrains.jps.client.SimpleProtobufClient;
|
||||
import org.jetbrains.jps.client.UUIDGetter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class JavacServerClient extends SimpleProtobufClient<JavacServerResponseHandler>{
|
||||
private static final ExecutorService ourExecutors = Executors.newCachedThreadPool();
|
||||
private static final AsyncTaskExecutor ASYNC_EXEC = new AsyncTaskExecutor() {
|
||||
@Override
|
||||
public void submit(Runnable runnable) {
|
||||
ourExecutors.submit(runnable);
|
||||
}
|
||||
};
|
||||
|
||||
public JavacServerClient() {
|
||||
super(JavacRemoteProto.Message.getDefaultInstance(), ASYNC_EXEC, new UUIDGetter() {
|
||||
super(JavacRemoteProto.Message.getDefaultInstance(), SharedThreadPool.ASYNC_EXEC, new UUIDGetter() {
|
||||
@NotNull
|
||||
public UUID getSessionUUID(@NotNull MessageEvent e) {
|
||||
final JavacRemoteProto.Message message = (JavacRemoteProto.Message)e.getMessage();
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module" module-name="instrumentation-util" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.jetbrains.jps
|
||||
|
||||
import com.intellij.ant.InstrumentationUtil.FormInstrumenter
|
||||
import com.intellij.ant.PseudoClassLoader
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder
|
||||
import org.jetbrains.ether.ProjectWrapper
|
||||
import org.jetbrains.ether.dependencyView.Callbacks.Backend
|
||||
|
||||
@@ -13,7 +13,7 @@ class ModuleBuildState {
|
||||
boolean tests
|
||||
Backend callback
|
||||
FormInstrumenter formInstrumenter
|
||||
PseudoClassLoader loader
|
||||
InstrumentationClassFinder loader
|
||||
ProjectWrapper projectWrapper
|
||||
List<File> sourceFiles
|
||||
List<String> sourceRoots
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jetbrains.jps.builders
|
||||
import com.intellij.ant.InstrumentationUtil
|
||||
import com.intellij.ant.InstrumentationUtil.FormInstrumenter
|
||||
import com.intellij.ant.PrefixedPath
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder
|
||||
import org.apache.tools.ant.BuildListener
|
||||
import org.jetbrains.ether.ProjectWrapper
|
||||
import org.jetbrains.ether.dependencyView.AntListener
|
||||
@@ -332,17 +333,13 @@ class JetBrainsInstrumentations implements ModuleBuilder {
|
||||
|
||||
def processModule(ModuleBuildState state, ModuleChunk moduleChunk, ProjectBuilder projectBuilder) {
|
||||
if (state.loader == null) {
|
||||
final StringBuilder cp = new StringBuilder()
|
||||
|
||||
cp.append(state.targetFolder)
|
||||
cp.append(File.pathSeparator)
|
||||
|
||||
final ArrayList urls = new ArrayList();
|
||||
urls.add(new File(state.targetFolder).toURL());
|
||||
state.classpath.each {
|
||||
cp.append(it)
|
||||
cp.append(File.pathSeparator)
|
||||
urls.add(new File(it).toURL());
|
||||
}
|
||||
|
||||
state.loader = InstrumentationUtil.createPseudoClassLoader(cp.toString())
|
||||
state.loader = new InstrumentationClassFinder((URL[])urls.toArray(new URL[urls.size()]))
|
||||
|
||||
final List<File> formFiles = new ArrayList<File>();
|
||||
final ProjectWrapper pw = state.projectWrapper;
|
||||
@@ -409,6 +406,9 @@ class JetBrainsInstrumentations implements ModuleBuilder {
|
||||
InstrumentationUtil.instrumentNotNull(new File(state.targetFolder + File.separator + it + ".class"), state.loader)
|
||||
}
|
||||
}
|
||||
if (state.loader != null) {
|
||||
state.loader.releaseResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package org.jetbrains.jps.builders.javacApi
|
||||
|
||||
import com.intellij.ant.InstrumentationUtil
|
||||
import javax.tools.JavaCompiler
|
||||
import javax.tools.JavaCompiler.CompilationTask
|
||||
import javax.tools.JavaFileObject
|
||||
import javax.tools.StandardLocation
|
||||
import javax.tools.ToolProvider
|
||||
import org.jetbrains.jps.ModuleBuildState
|
||||
import org.jetbrains.jps.ModuleChunk
|
||||
import org.jetbrains.jps.ProjectBuilder
|
||||
import org.jetbrains.jps.Sdk
|
||||
import org.jetbrains.jps.builders.JavaFileCollector
|
||||
|
||||
import javax.tools.JavaCompiler
|
||||
import javax.tools.JavaCompiler.CompilationTask
|
||||
import javax.tools.JavaFileObject
|
||||
import javax.tools.StandardLocation
|
||||
import javax.tools.ToolProvider
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
@@ -89,7 +89,7 @@ class Java16ApiCompiler {
|
||||
cp.append(state.targetFolder)
|
||||
|
||||
fileManager.setLocation(StandardLocation.CLASS_PATH, classpath)
|
||||
fileManager.setProperties(state.callback, InstrumentationUtil.createPseudoClassLoader(cp.toString()))
|
||||
fileManager.setProperties(state.callback, toURLs(cp.toString()))
|
||||
|
||||
Iterable<? extends JavaFileObject> toCompile = fileManager.getJavaFileObjectsFromFiles(filesToCompile)
|
||||
StringWriter out = new StringWriter()
|
||||
@@ -109,4 +109,13 @@ class Java16ApiCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
private URL[] toURLs(final String classPath) {
|
||||
final List urls = new ArrayList();
|
||||
for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
|
||||
final String s = tokenizer.nextToken();
|
||||
urls.add(new File(s).toURL());
|
||||
}
|
||||
return (URL[])urls.toArray(new URL[urls.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.jetbrains.jps.builders.javacApi;
|
||||
|
||||
import com.intellij.ant.InstrumentationUtil;
|
||||
import com.intellij.ant.PseudoClassLoader;
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.DefaultFileManager;
|
||||
import com.sun.tools.javac.util.List;
|
||||
@@ -14,10 +14,9 @@ import javax.lang.model.SourceVersion;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.ForwardingJavaFileObject;
|
||||
import javax.tools.JavaFileObject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -34,11 +33,17 @@ public class OptimizedFileManager extends DefaultFileManager {
|
||||
private final Map<File, Archive> myArchives;
|
||||
private final Map<File, Boolean> myIsFile = new ConcurrentHashMap<File, Boolean>();
|
||||
private Callbacks.Backend callback;
|
||||
private PseudoClassLoader loader;
|
||||
private InstrumentationClassFinder classFinder;
|
||||
private Map<String, byte[]> myCompiledClasses = new HashMap<String, byte[]>();
|
||||
|
||||
public void setProperties(final Callbacks.Backend c, final PseudoClassLoader l) {
|
||||
public void setProperties(final Callbacks.Backend c, final URL[] classpath) {
|
||||
callback = c;
|
||||
loader = l;
|
||||
classFinder = new InstrumentationClassFinder(classpath) {
|
||||
protected InputStream lookupClassBeforeClasspath(String internalClassName) {
|
||||
final byte[] bytes = myCompiledClasses.get(internalClassName);
|
||||
return bytes != null? new ByteArrayInputStream(bytes) : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public OptimizedFileManager() {
|
||||
@@ -201,7 +206,7 @@ public class OptimizedFileManager extends DefaultFileManager {
|
||||
final byte[] buffer = Arrays.copyOfRange(b, off, len);
|
||||
|
||||
if (kind.equals(JavaFileObject.Kind.CLASS)) {
|
||||
loader.defineClass(className.replaceAll("\\.", "/"), buffer);
|
||||
myCompiledClasses.put(className.replace('.', '/'), buffer);
|
||||
|
||||
if (callback != null) {
|
||||
final ClassReader reader = new ClassReader(buffer);
|
||||
@@ -212,7 +217,7 @@ public class OptimizedFileManager extends DefaultFileManager {
|
||||
public void commit() throws IOException {
|
||||
final OutputStream result = superOpenOutputStream();
|
||||
|
||||
final byte[] instrumented = InstrumentationUtil.instrumentNotNull(buffer, loader);
|
||||
final byte[] instrumented = InstrumentationUtil.instrumentNotNull(buffer, classFinder);
|
||||
|
||||
if (instrumented != null) {
|
||||
result.write(instrumented);
|
||||
@@ -247,5 +252,8 @@ public class OptimizedFileManager extends DefaultFileManager {
|
||||
}
|
||||
|
||||
myWriters.clear();
|
||||
if (classFinder != null) {
|
||||
classFinder.releaseResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* Returns the project to which the PSI element belongs.
|
||||
*
|
||||
* @return the project instance.
|
||||
* @throws PsiInvalidElementAccessException if this element is invalid
|
||||
* @throws PsiInvalidElementAccessException
|
||||
* if this element is invalid
|
||||
*/
|
||||
@NotNull
|
||||
Project getProject() throws PsiInvalidElementAccessException;
|
||||
@@ -56,7 +57,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the language instance.
|
||||
*/
|
||||
@NotNull Language getLanguage();
|
||||
@NotNull
|
||||
Language getLanguage();
|
||||
|
||||
/**
|
||||
* Returns the PSI manager for the project to which the PSI element belongs.
|
||||
@@ -71,7 +73,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the array of child elements.
|
||||
*/
|
||||
@NotNull PsiElement[] getChildren();
|
||||
@NotNull
|
||||
PsiElement[] getChildren();
|
||||
|
||||
/**
|
||||
* Returns the parent of the PSI element.
|
||||
@@ -85,34 +88,40 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the first child, or null if the element has no children.
|
||||
*/
|
||||
@Nullable PsiElement getFirstChild();
|
||||
@Nullable
|
||||
PsiElement getFirstChild();
|
||||
|
||||
/**
|
||||
* Returns the last child of the PSI element.
|
||||
*
|
||||
* @return the last child, or null if the element has no children.
|
||||
*/
|
||||
@Nullable PsiElement getLastChild();
|
||||
@Nullable
|
||||
PsiElement getLastChild();
|
||||
|
||||
/**
|
||||
* Returns the next sibling of the PSI element.
|
||||
*
|
||||
* @return the next sibling, or null if the node is the last in the list of siblings.
|
||||
*/
|
||||
@Nullable PsiElement getNextSibling();
|
||||
@Nullable
|
||||
PsiElement getNextSibling();
|
||||
|
||||
/**
|
||||
* Returns the previous sibling of the PSI element.
|
||||
*
|
||||
* @return the previous sibling, or null if the node is the first in the list of siblings.
|
||||
*/
|
||||
@Nullable PsiElement getPrevSibling();
|
||||
@Nullable
|
||||
PsiElement getPrevSibling();
|
||||
|
||||
/**
|
||||
* Returns the file containing the PSI element.
|
||||
* @throws PsiInvalidElementAccessException if this element is invalid
|
||||
*
|
||||
* @return the file instance, or null if the PSI element is not contained in a file (for example,
|
||||
* the element represents a package or directory).
|
||||
* the element represents a package or directory).
|
||||
* @throws PsiInvalidElementAccessException
|
||||
* if this element is invalid
|
||||
*/
|
||||
PsiFile getContainingFile() throws PsiInvalidElementAccessException;
|
||||
|
||||
@@ -178,7 +187,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the element text as a character array.
|
||||
*/
|
||||
@NotNull char[] textToCharArray();
|
||||
@NotNull
|
||||
char[] textToCharArray();
|
||||
|
||||
/**
|
||||
* Returns the PSI element which should be used as a navigation target
|
||||
@@ -246,7 +256,7 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
/**
|
||||
* Creates a copy of the file containing the PSI element and returns the corresponding
|
||||
* element in the created copy. Resolve operations performed on elements in the copy
|
||||
* of the file will resolve to elements in the copy, not in the original file.
|
||||
* of the file will resolve to elements in the copy, not in the original file.
|
||||
*
|
||||
* @return the element in the file copy corresponding to this element.
|
||||
*/
|
||||
@@ -304,9 +314,9 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
/**
|
||||
* Adds a range of elements as children to this PSI element, before the specified anchor element.
|
||||
*
|
||||
* @param first the first child element to add.
|
||||
* @param last the last child element to add (must have the same parent as <code>first</code>)
|
||||
* @param anchor the anchor before which the child element is inserted (must be a child of this PSI element)
|
||||
* @param first the first child element to add.
|
||||
* @param last the last child element to add (must have the same parent as <code>first</code>)
|
||||
* @param anchor the anchor before which the child element is inserted (must be a child of this PSI element)
|
||||
* @return the first child element which was actually added (either <code>first</code> or its copy).
|
||||
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
|
||||
*/
|
||||
@@ -315,9 +325,9 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
/**
|
||||
* Adds a range of elements as children to this PSI element, after the specified anchor element.
|
||||
*
|
||||
* @param first the first child element to add.
|
||||
* @param last the last child element to add (must have the same parent as <code>first</code>)
|
||||
* @param anchor the anchor after which the child element is inserted (must be a child of this PSI element)
|
||||
* @param first the first child element to add.
|
||||
* @param last the last child element to add (must have the same parent as <code>first</code>)
|
||||
* @param anchor the anchor after which the child element is inserted (must be a child of this PSI element)
|
||||
* @return the first child element which was actually added (either <code>first</code> or its copy).
|
||||
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
|
||||
*/
|
||||
@@ -327,7 +337,7 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* Deletes this PSI element from the tree.
|
||||
*
|
||||
* @throws IncorrectOperationException if the modification is not supported
|
||||
* or not possible for some reason (for example, the file containing the element is read-only).
|
||||
* or not possible for some reason (for example, the file containing the element is read-only).
|
||||
*/
|
||||
void delete() throws IncorrectOperationException;
|
||||
|
||||
@@ -382,7 +392,7 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* associated reference.
|
||||
*
|
||||
* @return the reference instance, or null if the PSI element does not have any
|
||||
* associated references.
|
||||
* associated references.
|
||||
*/
|
||||
@Nullable
|
||||
PsiReference getReference();
|
||||
@@ -394,15 +404,16 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* contains only one text fragment which acts as a reference but the reference has
|
||||
* multiple possible targets, {@link PsiPolyVariantReference} should be used instead
|
||||
* of returning multiple references.
|
||||
*
|
||||
* <p/>
|
||||
* Actually, it's preferable to call {@link com.intellij.psi.PsiReferenceService#getReferences} instead
|
||||
* as it allows adding references by plugins when the element implements {@link com.intellij.psi.ContributedReferenceHost}.
|
||||
*
|
||||
* @return the array of references, or an empty array if the element has no associated
|
||||
* references.
|
||||
* references.
|
||||
* @see com.intellij.psi.PsiReferenceService#getReferences
|
||||
*/
|
||||
@NotNull PsiReference[] getReferences();
|
||||
@NotNull
|
||||
PsiReference[] getReferences();
|
||||
|
||||
/**
|
||||
* Returns a copyable user data object attached to this element.
|
||||
@@ -411,13 +422,14 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* @return the user data object, or null if no such object is found in the current element.
|
||||
* @see #putCopyableUserData(com.intellij.openapi.util.Key, Object)
|
||||
*/
|
||||
@Nullable <T> T getCopyableUserData(Key<T> key);
|
||||
@Nullable
|
||||
<T> T getCopyableUserData(Key<T> key);
|
||||
|
||||
/**
|
||||
* Attaches a copyable user data object to this element. Copyable user data objects are copied
|
||||
* when the PSI elements are copied.
|
||||
*
|
||||
* @param key the key for accessing the user data object.
|
||||
* @param key the key for accessing the user data object.
|
||||
* @param value the user data object to attach.
|
||||
* @see #getCopyableUserData(com.intellij.openapi.util.Key)
|
||||
*/
|
||||
@@ -427,12 +439,12 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* Passes the declarations contained in this PSI element and its children
|
||||
* for processing to the specified scope processor.
|
||||
*
|
||||
* @param processor the processor receiving the declarations.
|
||||
* @param processor the processor receiving the declarations.
|
||||
* @param state
|
||||
* @param lastParent the child of this element has been processed during the previous
|
||||
* step of the tree up walk (declarations under this element do not need
|
||||
* to be processed again)
|
||||
* @param place the original element from which the tree up walk was initiated.
|
||||
* @param lastParent the child of this element has been processed during the previous
|
||||
* step of the tree up walk (declarations under this element do not need
|
||||
* to be processed again)
|
||||
* @param place the original element from which the tree up walk was initiated.
|
||||
* @return true if the declaration processing should continue or false if it should be stopped.
|
||||
*/
|
||||
boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@@ -444,11 +456,12 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* Returns the element which should be used as the parent of this element in a tree up
|
||||
* walk during a resolve operation. For most elements, this returns <code>getParent()</code>,
|
||||
* but the context can be overridden for some elements like code fragments (see
|
||||
* {@link PsiElementFactory#createCodeBlockCodeFragment(String, PsiElement, boolean)}).
|
||||
* {@link PsiElementFactory#createCodeBlockCodeFragment(String, PsiElement, boolean)}).
|
||||
*
|
||||
* @return the resolve context element.
|
||||
*/
|
||||
@Nullable PsiElement getContext();
|
||||
@Nullable
|
||||
PsiElement getContext();
|
||||
|
||||
/**
|
||||
* Checks if an actual source or class file corresponds to the element. Non-physical elements include,
|
||||
@@ -465,7 +478,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
*
|
||||
* @return the resolve scope instance.
|
||||
*/
|
||||
@NotNull GlobalSearchScope getResolveScope();
|
||||
@NotNull
|
||||
GlobalSearchScope getResolveScope();
|
||||
|
||||
/**
|
||||
* Returns the scope in which references to this element are searched.
|
||||
@@ -473,7 +487,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
* @return the search scope instance.
|
||||
* @see {@link com.intellij.psi.search.PsiSearchHelper#getUseScope(PsiElement)}
|
||||
*/
|
||||
@NotNull SearchScope getUseScope();
|
||||
@NotNull
|
||||
SearchScope getUseScope();
|
||||
|
||||
/**
|
||||
* Returns the AST node corresponding to the element.
|
||||
@@ -485,7 +500,8 @@ public interface PsiElement extends UserDataHolder, Iconable {
|
||||
/**
|
||||
* toString() should never be presented to the user.
|
||||
*/
|
||||
@NonNls String toString();
|
||||
@NonNls
|
||||
String toString();
|
||||
|
||||
boolean isEquivalentTo(PsiElement another);
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user