Merge remote-tracking branch 'origin/master'

This commit is contained in:
Andrey Vlasovskikh
2015-09-09 11:50:54 +03:00
14 changed files with 207 additions and 20 deletions
@@ -63,6 +63,7 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi
private JCheckBox myGenerateAccessorsCb;
private final JavaVisibilityPanel myVisibilityPanel;
private final JCheckBox extractAsEnum;
private final JCheckBox createInner;
private final List<MemberInfo> enumConstants = new ArrayList<MemberInfo>();
ExtractClassDialog(PsiClass sourceClass, PsiMember selectedMember) {
@@ -129,6 +130,7 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi
if (!hasConstants) {
extractAsEnum.setVisible(false);
}
createInner = new JCheckBox("Create nested class");
super.init();
validateButtons();
}
@@ -152,9 +154,8 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi
false),
newClassName, myVisibilityPanel.getVisibility(),
isGenerateAccessors(),
isExtractAsEnum()
? enumConstants
: Collections.<MemberInfo>emptyList());
isExtractAsEnum() ? enumConstants : Collections.<MemberInfo>emptyList());
processor.setExtractInnerClass(createInner.isSelected());
if (processor.getCreatedClass() == null) {
Messages.showErrorDialog(myVisibilityPanel, "Unable to create class with the given name");
classNameField.requestFocusInWindow();
@@ -243,12 +244,15 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi
}
protected JComponent createNorthPanel() {
final JPanel checkboxPanel = new JPanel(new BorderLayout());
checkboxPanel.add(createInner, BorderLayout.WEST);
checkboxPanel.add(extractAsEnum, BorderLayout.EAST);
FormBuilder builder = FormBuilder.createFormBuilder()
.addComponent(
JBLabelDecorator.createJBLabelDecorator(RefactorJBundle.message("extract.class.from.label", sourceClass.getQualifiedName()))
.setBold(true))
.addLabeledComponent(RefactorJBundle.message("name.for.new.class.label"), classNameField, UIUtil.LARGE_VGAP)
.addLabeledComponent(new JLabel(), extractAsEnum)
.addLabeledComponent(new JLabel(), checkboxPanel)
.addLabeledComponent(RefactorJBundle.message("package.for.new.class.label"), packageTextField);
if (JavaProjectRootsUtil.getSuitableDestinationSourceRoots(myProject).size() > 1) {
@@ -349,6 +353,14 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi
table.repaint();
}
});
createInner.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final boolean isCreateInner = createInner.isSelected();
packageTextField.setEnabled(!isCreateInner);
myDestinationFolderComboBox.setEnabled(!isCreateInner);
}
});
myGenerateAccessorsCb = new JCheckBox("Generate accessors");
myGenerateAccessorsCb.setMnemonic('G');
panel.add(myGenerateAccessorsCb, BorderLayout.SOUTH);
@@ -84,6 +84,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
private boolean delegationRequired = false;
private final ExtractEnumProcessor myExtractEnumProcessor;
private final PsiClass myClass;
private boolean extractInnerClass;
public ExtractClassProcessor(PsiClass sourceClass,
List<PsiField> fields,
@@ -150,6 +151,10 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
return myClass;
}
public void setExtractInnerClass(boolean extractInnerClass) {
this.extractInnerClass = extractInnerClass;
}
@Override
protected boolean preprocessUsages(@NotNull final Ref<UsageInfo[]> refUsages) {
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
@@ -166,7 +171,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
final Project project = sourceClass.getProject();
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
final PsiClass existingClass =
JavaPsiFacade.getInstance(project).findClass(StringUtil.getQualifiedName(newPackageName, newClassName), scope);
JavaPsiFacade.getInstance(project).findClass(getQualifiedName(), scope);
if (existingClass != null) {
conflicts.putValue(existingClass, RefactorJBundle.message("cannot.perform.the.refactoring") +
RefactorJBundle.message("there.already.exists.a.class.with.the.chosen.name"));
@@ -193,6 +198,10 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
return showConflicts(conflicts, refUsages.get());
}
private String getQualifiedName() {
return extractInnerClass ? newClassName : StringUtil.getQualifiedName(newPackageName, newClassName);
}
private void calculateInitializersConflicts(MultiMap<PsiElement, String> conflicts) {
final PsiClassInitializer[] initializers = sourceClass.getInitializers();
@@ -412,7 +421,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
final String delegateVisibility = calculateDelegateVisibility();
if (delegateVisibility.length() > 0) fieldBuffer.append(delegateVisibility).append(' ');
fieldBuffer.append("final ");
final String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName);
final String fullyQualifiedName = getQualifiedName();
fieldBuffer.append(fullyQualifiedName);
if (!typeParams.isEmpty()) {
fieldBuffer.append('<');
@@ -497,7 +506,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
assert innerName != null;
final String sourceClassQualifiedName = sourceClass.getQualifiedName();
assert sourceClassQualifiedName != null;
final String newInnerClassName = StringUtil.getQualifiedName(newPackageName, newClassName) + innerName.substring(sourceClassQualifiedName.length());
final String newInnerClassName = getQualifiedName() + innerName.substring(sourceClassQualifiedName.length());
boolean hasExternalReference = false;
for (PsiReference reference : calls) {
final PsiElement referenceElement = reference.getElement();
@@ -552,7 +561,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
final Project project = psiManager.getProject();
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
final Iterable<PsiReference> calls = ReferencesSearch.search(method, scope);
final String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName);
final String fullyQualifiedName = getQualifiedName();
for (PsiReference reference : calls) {
final PsiElement referenceElement = reference.getElement();
@@ -594,7 +603,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
final Project project = psiManager.getProject();
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
final String qualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName);
final String qualifiedName = getQualifiedName();
@NonNls String getter = null;
if (myGenerateAccessors) {
getter = GenerateMembersUtil.suggestGetterName(field);
@@ -683,6 +692,19 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
}
final String classString = extractedClassBuilder.buildBeanClass();
if (extractInnerClass) {
final PsiFileFactory factory = PsiFileFactory.getInstance(project);
final PsiJavaFile newFile = (PsiJavaFile)factory.createFileFromText(newClassName + ".java", JavaFileType.INSTANCE, classString);
final PsiClass psiClass = newFile.getClasses()[0];
if (!psiClass.isEnum()) {
final PsiModifierList modifierList = psiClass.getModifierList();
assert modifierList != null;
modifierList.setModifierProperty(PsiModifier.STATIC, true);
}
final PsiElement addedClass = sourceClass.add(psiClass);
return (PsiClass)CodeStyleManager.getInstance(manager)
.reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedClass));
}
try {
final PsiFile containingFile = sourceClass.getContainingFile();
@@ -0,0 +1,29 @@
class Test {
final Extracted extracted = new Extracted(this);
void bar(){
System.out.println(extracted.getMyT());
}
String foo() {
return "";
}
void bazz() {
bar();
}
public static class Extracted {
private final Test test;
String myT;
public String getMyT() {
return myT;
}
public Extracted(Test test) {
this.test = test;
this.myT = test.foo();
}
}
}
@@ -0,0 +1,15 @@
class Test {
String myT = foo();
void bar(){
System.out.println(myT);
}
String foo() {
return "";
}
void bazz() {
bar();
}
}
@@ -192,11 +192,37 @@ public class ExtractClassTest extends MultiFileTestCase{
});
}
private static void doTest(final PsiClass aClass, final ArrayList<PsiMethod> methods, final ArrayList<PsiField> fields, final String conflicts,
public void testInnerClass() throws Exception {
doTest((rootDir, rootAfter) -> {
PsiClass aClass = myJavaFacade.findClass("Test", GlobalSearchScope.projectScope(myProject));
assertNotNull("Class Test not found", aClass);
final ArrayList<PsiField> fields = new ArrayList<>();
fields.add(aClass.findFieldByName("myT", false));
doTest(aClass, new ArrayList<>(), fields, null, true, true);
});
}
private static void doTest(final PsiClass aClass,
final ArrayList<PsiMethod> methods,
final ArrayList<PsiField> fields,
final String conflicts,
boolean generateGettersSetters) {
doTest(aClass, methods, fields, conflicts, generateGettersSetters, false);
}
private static void doTest(final PsiClass aClass,
final ArrayList<PsiMethod> methods,
final ArrayList<PsiField> fields,
final String conflicts,
boolean generateGettersSetters,
boolean inner) {
try {
ExtractClassProcessor processor = new ExtractClassProcessor(aClass, fields, methods, new ArrayList<>(), StringUtil.getPackageName(aClass.getQualifiedName()), null,
"Extracted", null, generateGettersSetters, Collections.<MemberInfo>emptyList());
processor.setExtractInnerClass(inner);
processor.run();
LocalFileSystem.getInstance().refresh(false);
FileDocumentManager.getInstance().saveAllDocuments();
@@ -71,7 +71,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
boolean exported,
String libName,
String url,
String srcUrl, ExpandMacroToPathMap macroMap);
String srcUrl, String nativeRoot, ExpandMacroToPathMap macroMap);
protected abstract String expandEclipsePath2Url(T rootModel, String path);
@@ -178,7 +178,12 @@ public abstract class AbstractEclipseClasspathReader<T> {
}
}
addModuleLibrary(rootModel, element, exported, getPresentableName(path, libs), url, srcUrl, macroMap);
String nativeRoot = getNativeLibraryRoot(element);
if (nativeRoot != null) {
nativeRoot = expandEclipsePath2Url(rootModel, nativeRoot);
}
addModuleLibrary(rootModel, element, exported, getPresentableName(path, libs), url, srcUrl, nativeRoot, macroMap);
}
else if (kind.equals(EclipseXml.VAR_KIND)) {
int slash = path.indexOf("/");
@@ -201,7 +206,11 @@ public abstract class AbstractEclipseClasspathReader<T> {
eclipseModuleManager.registerEclipseSrcVariablePath(srcUrl, srcPathAttr);
}
}
addModuleLibrary(rootModel, element, exported, libName, url, srcUrl, macroMap);
String nativeRoot = getNativeLibraryRoot(element);
if (nativeRoot != null) {
nativeRoot = expandEclipsePath2Url(rootModel, nativeRoot);
}
addModuleLibrary(rootModel, element, exported, libName, url, srcUrl, nativeRoot, macroMap);
}
else if (kind.equals(EclipseXml.CON_KIND)) {
if (path.equals(EclipseXml.ECLIPSE_PLATFORM)) {
@@ -242,6 +251,18 @@ public abstract class AbstractEclipseClasspathReader<T> {
}
}
private static String getNativeLibraryRoot(Element element) {
final Element attributes = element.getChild(EclipseXml.ATTRIBUTES_TAG);
if (attributes != null) {
for (Element attributeElement : attributes.getChildren(EclipseXml.ATTRIBUTE_TAG)) {
if (EclipseXml.DLL_LINK.equals(attributeElement.getAttributeValue(EclipseXml.NAME_ATTR))) {
return attributeElement.getAttributeValue(EclipseXml.VALUE_ATTR);
}
}
}
return null;
}
protected static int srcVarStart(String srcPath) {
return srcPath.startsWith("/") ? 1 : 0;
}
@@ -76,4 +76,5 @@ public interface EclipseXml {
@NonNls String LINKED_RESOURCES = "linkedResources";
@NonNls String LINK = "link";
@NonNls String JAVADOC_LOCATION = "javadoc_location";
@NonNls String DLL_LINK = "org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY";
}
@@ -151,6 +151,7 @@ class JpsEclipseClasspathReader extends AbstractEclipseClasspathReader<JpsModule
String libName,
String url,
String srcUrl,
String nativeRoot,
ExpandMacroToPathMap macroMap) {
final JpsLibrary jpsLibrary = rootModel.addModuleLibrary(libName, JpsJavaLibraryType.INSTANCE);
final JpsDependenciesList dependenciesList = rootModel.getDependenciesList();
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
import com.intellij.util.Function;
import org.jdom.Element;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.eclipse.EPathCommonUtil;
@@ -202,10 +203,21 @@ public class EJavadocUtil {
}
static void setupJavadocAttributes(Element orderEntry, LibraryOrderEntry libraryOrderEntry, final ModuleRootModel model) {
setupAttributes(orderEntry, new Function<String, String>() {
@Override
public String fun(String s) {
return toEclipseJavadocPath(model, s);
}
}, JAVADOC_LOCATION, libraryOrderEntry.getRootUrls(JavadocOrderRootType.getInstance()));
}
static void setupAttributes(Element orderEntry,
Function<String, String> fun,
String attributeName,
String[] roots) {
final List<String> eclipseUrls = new ArrayList<String>();
final String[] docUrls = libraryOrderEntry.getRootUrls(JavadocOrderRootType.getInstance());
if (docUrls.length > 0) {
eclipseUrls.add(toEclipseJavadocPath(model, docUrls[0]));
if (roots.length > 0) {
eclipseUrls.add(fun.fun(roots[0]));
}
final List children = new ArrayList(orderEntry.getChildren(ATTRIBUTES_TAG));
@@ -214,7 +226,7 @@ public class EJavadocUtil {
final ArrayList attTags = new ArrayList(attsElement.getChildren(ATTRIBUTE_TAG));
for (Object a : attTags) {
Element attElement = (Element)a;
if (Comparing.strEqual(attElement.getAttributeValue("name"), JAVADOC_LOCATION)) {
if (Comparing.strEqual(attElement.getAttributeValue("name"), attributeName)) {
final String javadocPath = attElement.getAttributeValue("value");
if (!eclipseUrls.remove(javadocPath)) {
attElement.detach();
@@ -232,7 +244,7 @@ public class EJavadocUtil {
final Element attrElement = new Element(ATTRIBUTE_TAG);
child.addContent(attrElement);
attrElement.setAttribute("name", JAVADOC_LOCATION);
attrElement.setAttribute("name", attributeName);
attrElement.setAttribute("value", docUrl);
}
}
@@ -153,13 +153,20 @@ public class EclipseClasspathReader extends AbstractEclipseClasspathReader<Modif
boolean exported,
String libName,
String url,
String srcUrl, ExpandMacroToPathMap macroMap) {
String srcUrl,
String nativeRoot,
ExpandMacroToPathMap macroMap) {
final Library library = rootModel.getModuleLibraryTable().getModifiableModel().createLibrary(libName);
final Library.ModifiableModel modifiableModel = library.getModifiableModel();
modifiableModel.addRoot(url, OrderRootType.CLASSES);
if (srcUrl != null) {
modifiableModel.addRoot(srcUrl, OrderRootType.SOURCES);
}
if (nativeRoot != null) {
modifiableModel.addRoot(nativeRoot, NativeLibraryOrderRootType.getInstance());
}
EJavadocUtil.appendJavadocRoots(element, rootModel, myCurrentRoots, modifiableModel);
modifiableModel.commit();
@@ -28,6 +28,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -86,7 +87,7 @@ public class EclipseClasspathWriter {
return classpathElement;
}
private void createClasspathEntry(@NotNull OrderEntry entry, @NotNull Element classpathRoot, @NotNull ModuleRootModel model) throws ConversionException {
private void createClasspathEntry(@NotNull OrderEntry entry, @NotNull Element classpathRoot, @NotNull final ModuleRootModel model) throws ConversionException {
EclipseModuleManager eclipseModuleManager = EclipseModuleManagerImpl.getInstance(entry.getOwnerModule());
if (entry instanceof ModuleSourceOrderEntry) {
boolean shouldPlaceSeparately = eclipseModuleManager.isExpectedModuleSourcePlace(Arrays.binarySearch(model.getOrderEntries(), entry));
@@ -185,6 +186,16 @@ public class EclipseClasspathWriter {
setOrRemoveAttribute(orderEntry, EclipseXml.SOURCEPATH_ATTR, addSrcRoots ? (eclipseSrcVariablePath != null ? eclipseSrcVariablePath : srcRelativePath) : null);
EJavadocUtil.setupJavadocAttributes(orderEntry, libraryOrderEntry, model);
final String[] nativeRoots = libraryOrderEntry.getUrls(NativeLibraryOrderRootType.getInstance());
if (nativeRoots.length > 0) {
EJavadocUtil.setupAttributes(orderEntry, new Function<String, String>() {
@Override
public String fun(String nativeRoot) {
return EPathUtil.collapse2EclipsePath(nativeRoot, model);
}
}, EclipseXml.DLL_LINK, nativeRoots);
}
setExported(orderEntry, libraryOrderEntry);
}
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry including="**" kind="src" path="src" />
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" />
<classpathentry kind="lib" path="test.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="target"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin" />
</classpath>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>test</name>
<comment/>
<projects/>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments/>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -150,6 +150,10 @@ public class EclipseClasspathTest extends IdeaTestCase {
doTest();
}
public void testNativeLibs() throws Exception {
doTest();
}
public void testAccessrulez() throws Exception {
doTest();
}