Merge branch 'master' into uta-python
@@ -9,6 +9,6 @@
|
||||
<plugin id="com.intellij.properties" />
|
||||
<plugin id="com.intellij.uiDesigner" />
|
||||
<plugin id="org.intellij.groovy" />
|
||||
<plugin id="org.jetbrains.kotlin" min-version="1.0.0-beta-2423" max-version="1.1" />
|
||||
<plugin id="org.jetbrains.kotlin" min-version="1.0.0-beta-3595" max-version="1.1" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -4,11 +4,11 @@
|
||||
<root url="file://$PROJECT_DIR$/lib/annotations/netty"/>
|
||||
</ANNOTATIONS>
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/netty-all-4.1.0.Beta7.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/netty-all-4.1.0.Beta8.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/netty-all-4.1.0.Beta7-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/netty-all-4.1.0.Beta8-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -230,7 +230,6 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/groovy/structuralsearch-groovy/structuralsearch-groovy.iml" filepath="$PROJECT_DIR$/plugins/groovy/structuralsearch-groovy/structuralsearch-groovy.iml" group="plugins/Groovy" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/structuralsearch-java/structuralsearch-java.iml" filepath="$PROJECT_DIR$/java/structuralsearch-java/structuralsearch-java.iml" group="java" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/structuralsearch/structuralsearch-tests.iml" filepath="$PROJECT_DIR$/platform/structuralsearch/structuralsearch-tests.iml" group="plugins/structuralsearch" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/structure-view-api/structure-view-api.iml" filepath="$PROJECT_DIR$/platform/structure-view-api/structure-view-api.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/structure-view-impl/structure-view-impl.iml" filepath="$PROJECT_DIR$/platform/structure-view-impl/structure-view-impl.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/svn4idea/svn4idea.iml" filepath="$PROJECT_DIR$/plugins/svn4idea/svn4idea.iml" group="plugins/VCS" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/svn4idea/svn4idea-tests.iml" filepath="$PROJECT_DIR$/plugins/svn4idea/svn4idea-tests.iml" group="plugins/VCS" />
|
||||
|
||||
@@ -61,6 +61,9 @@ if [ -n "$@@product_uc@@_JDK" -a -x "$@@product_uc@@_JDK/bin/java" ]; then
|
||||
JDK="$@@product_uc@@_JDK"
|
||||
elif [ -s "$HOME/.@@system_selector@@/config/@@vm_options@@.jdk" ]; then
|
||||
JDK=`$CAT $HOME/.@@system_selector@@/config/@@vm_options@@.jdk`
|
||||
if [ ! -d $JDK ]; then
|
||||
JDK=$IDE_HOME/$JDK
|
||||
fi
|
||||
elif [ -x "$IDE_HOME/jre/jre/bin/java" ] && "$IDE_HOME/jre/jre/bin/java" -version > /dev/null 2>&1 ; then
|
||||
JDK="$IDE_HOME/jre"
|
||||
elif [ -n "$JDK_HOME" -a -x "$JDK_HOME/bin/java" ]; then
|
||||
@@ -184,6 +187,7 @@ LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JAVA_BIN" \
|
||||
$VM_OPTIONS \
|
||||
"-Djb.vmOptionsFile=$VM_OPTIONS_FILE" \
|
||||
"-XX:ErrorFile=$HOME/java_error_in_@@product_uc@@_%p.log" \
|
||||
"-XX:HeapDumpPath=$HOME/java_error_in_@@product_uc@@.hprof" \
|
||||
-Djb.restart.code=88 -Didea.paths.selector=@@system_selector@@ \
|
||||
$IDE_PROPERTIES_PROPERTY \
|
||||
@@ide_jvm_args@@ \
|
||||
|
||||
@@ -49,7 +49,7 @@ SET ACC=
|
||||
FOR /F "usebackq delims=" %%i IN ("%VM_OPTIONS_FILE%") DO CALL "%IDE_BIN_DIR%\append.bat" "%%i"
|
||||
IF EXIST "%VM_OPTIONS_FILE%" SET ACC=%ACC% -Djb.vmOptionsFile="%VM_OPTIONS_FILE%"
|
||||
|
||||
SET COMMON_JVM_ARGS="-XX:ErrorFile=%USERPROFILE%\java_error_in_@@product_uc@@_%%p.log" "-Xbootclasspath/a:%IDE_HOME%/lib/boot.jar" -Didea.paths.selector=@@system_selector@@ %IDE_PROPERTIES_PROPERTY%
|
||||
SET COMMON_JVM_ARGS="-XX:ErrorFile=%USERPROFILE%\java_error_in_@@product_uc@@_%%p.log" "-XX:HeapDumpPath=%USERPROFILE%\java_error_in_@@product_uc@@.hprof" "-Xbootclasspath/a:%IDE_HOME%/lib/boot.jar" -Didea.paths.selector=@@system_selector@@ %IDE_PROPERTIES_PROPERTY%
|
||||
SET IDE_JVM_ARGS=@@ide_jvm_args@@
|
||||
SET ALL_JVM_ARGS=%ACC% %COMMON_JVM_ARGS% %IDE_JVM_ARGS%
|
||||
|
||||
|
||||
@@ -995,7 +995,8 @@ FunctionEnd
|
||||
Function un.ConfirmDeleteSettings
|
||||
!insertmacro MUI_HEADER_TEXT "$(uninstall_options)" "$(uninstall_options_prompt)"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 1" "Text" "$(prompt_delete_settings)"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 2" "Text" $INSTDIR
|
||||
${UnStrRep} $R1 $INSTDIR '\' '\\'
|
||||
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 2" "Text" $R1
|
||||
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 3" "Text" "$(text_delete_settings)"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 4" "Text" "$(confirm_delete_caches)"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 5" "Text" "$(confirm_delete_settings)"
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.intellij.util.text.VersionComparatorUtil
|
||||
import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
|
||||
includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant")
|
||||
|
||||
String kotlinBuildConfigurationOnPublicTeamCity = "Kotlin_Beta2_Idea142branch150versionNoTests"
|
||||
String kotlinBuildConfigurationOnPublicTeamCity = "Kotlin_Beta3_Idea142branch150versionNoTests"
|
||||
|
||||
target('default': 'Ensures that build/kotlinc directory contains JARs from Kotlin plugin compatible with current IDEA sources. These JARs are used by build scripts.') {
|
||||
def communityHome = guessHome(this)
|
||||
|
||||
@@ -39,6 +39,14 @@ binding.setVariable("p", {String key, String defaultValue = null ->
|
||||
}
|
||||
})
|
||||
|
||||
binding.setVariable("versionSelector", {
|
||||
def fullVersion = p("component.version.major") + "." + p("component.version.minor")
|
||||
def versionParts = fullVersion.split("\\.")
|
||||
|
||||
def minor = versionParts[1]
|
||||
versionParts[0] + (minor == "0" ? "": "." + minor)
|
||||
})
|
||||
|
||||
binding.setVariable("guessJdk", {
|
||||
String javaHome = p("java.home")
|
||||
|
||||
@@ -379,7 +387,6 @@ binding.setVariable("platformApiModules", [
|
||||
"projectModel-api",
|
||||
"remote-servers-agent-rt",
|
||||
"remote-servers-api",
|
||||
"structure-view-api",
|
||||
"usageView",
|
||||
"vcs-api-core",
|
||||
"vcs-api",
|
||||
@@ -1255,7 +1262,6 @@ binding.setVariable("analysisApiModules", [
|
||||
"jps-model-api",
|
||||
"jps-model-serialization",
|
||||
"projectModel-api",
|
||||
"structure-view-api",
|
||||
"util",
|
||||
"util-rt",
|
||||
"xml-analysis-api",
|
||||
|
||||
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 83 KiB |
@@ -1,11 +1,12 @@
|
||||
<component>
|
||||
<version codename="Community Edition" major="15" minor="1" eap="true"/>
|
||||
<version codename="Community Edition" major="16" minor="0" eap="true"/>
|
||||
<company name="JetBrains s.r.o." url="https://www.jetbrains.com/?fromIDE"/>
|
||||
<build number="__BUILD_NUMBER__" date="__BUILD_DATE__"/>
|
||||
<install-over minbuild="129.1" maxbuild="139.9999" version="14"/>
|
||||
<logo url="/idea_community_logo.png" textcolor="aaaaaa" progressColor="FDA916" progressY="230" progressTailIcon="/community_progress_tail.png"/>
|
||||
<about url="/idea_community_about.png" foreground="333333" copyrightForeground="7A858F" linkColor="9b5121" logoX="300" logoY="265" logoW="75" logoH="30"/>
|
||||
<icon size32="/icon_CE.png" size16="/icon_CEsmall.png" size12="/toolwindows/toolWindowProject.png" size128="/icon_CE_128.png" ico="idea_CE.ico"/>
|
||||
<logo url="/idea_community_logo.png" textcolor="444444" progressColor="f87206" progressX="0" progressY="271" progressHeight="3" licenseOffsetY="30" />
|
||||
<about url="/idea_community_about.png" foreground="444444" copyrightForeground="7A858F" linkColor="9b5121" logoX="300" logoY="265" logoW="75" logoH="30"/>
|
||||
<icon size32="/icon_CE.png" size16="/icon_CEsmall.png" size128="/icon_CE_128.png" ico="idea_CE.ico"/>
|
||||
<package code="__PACKAGE_CODE__"/>
|
||||
<names product="IDEA" fullname="IntelliJ IDEA" script="idea"/>
|
||||
|
||||
<welcome-screen logo-url="/Logo_welcomeScreen.png"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 263 KiB |
@@ -53,7 +53,8 @@ com.android.tools.idea.wizard.TemplateWizardStateTest
|
||||
com.android.tools.idea.wizard.TemplateWizardModuleBuilderTest
|
||||
com.android.tools.idea.wizard.NewTemplateObjectWizardTest
|
||||
org.jetbrains.android.run.AndroidRunConfigurationTest
|
||||
org.jetbrains.android.run.GradleApkProviderTest
|
||||
com.android.tools.idea.run.GradleApkProviderTest
|
||||
com.android.tools.idea.run.LaunchUtilsTest
|
||||
org.jetbrains.android.facet.IdeaSourceProviderTest
|
||||
com.android.tools.idea.gradle.service.resolve.AndroidResolveTest
|
||||
com.android.tools.idea.gradle.service.resolve.AndroidDslContributorTest
|
||||
@@ -91,6 +92,7 @@ com.android.tools.idea.sdk.IdeSdksTest
|
||||
com.android.tools.idea.welcome.wizard.FirstRunWizardTest
|
||||
com.android.tools.idea.wizard.template.TemplateWizardStateTest
|
||||
com.android.tools.swing.layoutlib.GraphicsLayoutRendererTest
|
||||
org.jetbrains.android.databinding.GeneratedCodeMatchTest
|
||||
|
||||
[ANDROID_BOMBED]
|
||||
com.android.tools.idea.gradle.project.GradleModuleImportTest
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<vendor>JetBrains</vendor>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
|
||||
<search.topHitProvider implementation="org.intellij.images.options.impl.ImagesOptionsTopHitProvider"/>
|
||||
<applicationConfigurable groupId="editor" instance="org.intellij.images.options.impl.OptionsConfigurabe" id="Images" displayName="Images"/>
|
||||
<fileEditorProvider implementation="org.intellij.images.editor.impl.ImageFileEditorProvider"/>
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.intellij.images.editor.ImageEditor;
|
||||
import org.intellij.images.editor.ImageZoomModel;
|
||||
import org.intellij.images.fileTypes.ImageFileTypeManager;
|
||||
import org.intellij.images.thumbnail.actionSystem.ThumbnailViewActions;
|
||||
import org.intellij.images.ui.ImageComponent;
|
||||
import org.intellij.images.vfs.IfsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -79,7 +80,7 @@ final class ImageEditorImpl implements ImageEditor {
|
||||
return document.getValue() != null;
|
||||
}
|
||||
|
||||
public JComponent getComponent() {
|
||||
public ImageEditorUI getComponent() {
|
||||
return editorUI;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ final class ImageEditorUI extends JPanel implements DataProvider, CopyProvider,
|
||||
private static final String IMAGE_PANEL = "image";
|
||||
@NonNls
|
||||
private static final String ERROR_PANEL = "error";
|
||||
@NonNls
|
||||
private static final String ZOOM_FACTOR_PROP = "ImageEditor.zoomFactor";
|
||||
|
||||
private final @Nullable ImageEditor editor;
|
||||
private final DeleteProvider deleteProvider;
|
||||
@@ -348,6 +350,8 @@ final class ImageEditorUI extends JPanel implements DataProvider, CopyProvider,
|
||||
}
|
||||
|
||||
public void setZoomFactor(double zoomFactor) {
|
||||
double oldZoomFactor = getZoomFactor();
|
||||
|
||||
// Change current size
|
||||
Dimension size = imageComponent.getCanvasSize();
|
||||
BufferedImage image = imageComponent.getDocument().getValue();
|
||||
@@ -359,6 +363,8 @@ final class ImageEditorUI extends JPanel implements DataProvider, CopyProvider,
|
||||
revalidate();
|
||||
repaint();
|
||||
myZoomLevelChanged = false;
|
||||
|
||||
imageComponent.firePropertyChange(ZOOM_FACTOR_PROP, oldZoomFactor, zoomFactor);
|
||||
}
|
||||
|
||||
private double getMinimumZoomFactor() {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import org.intellij.images.editor.ImageEditor;
|
||||
import org.intellij.images.editor.ImageFileEditor;
|
||||
import org.intellij.images.editor.ImageZoomModel;
|
||||
@@ -31,6 +32,7 @@ import org.intellij.images.options.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
/**
|
||||
@@ -38,10 +40,11 @@ import java.beans.PropertyChangeListener;
|
||||
*
|
||||
* @author <a href="mailto:aefimov.box@gmail.com">Alexey Efimov</a>
|
||||
*/
|
||||
final class ImageFileEditorImpl extends UserDataHolderBase implements ImageFileEditor {
|
||||
final class ImageFileEditorImpl extends UserDataHolderBase implements ImageFileEditor, PropertyChangeListener {
|
||||
private static final String NAME = "ImageFileEditor";
|
||||
|
||||
private final ImageEditor imageEditor;
|
||||
private final EventDispatcher<PropertyChangeListener> myDispatcher = EventDispatcher.create(PropertyChangeListener.class);
|
||||
|
||||
ImageFileEditorImpl(@NotNull Project project, @NotNull VirtualFile file) {
|
||||
imageEditor = new ImageEditorImpl(project, file);
|
||||
@@ -54,6 +57,8 @@ final class ImageFileEditorImpl extends UserDataHolderBase implements ImageFileE
|
||||
TransparencyChessboardOptions transparencyChessboardOptions = editorOptions.getTransparencyChessboardOptions();
|
||||
imageEditor.setGridVisible(gridOptions.isShowDefault());
|
||||
imageEditor.setTransparencyChessboardVisible(transparencyChessboardOptions.isShowDefault());
|
||||
|
||||
((ImageEditorImpl)imageEditor).getComponent().getImageComponent().addPropertyChangeListener(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -104,9 +109,17 @@ final class ImageFileEditorImpl extends UserDataHolderBase implements ImageFileE
|
||||
}
|
||||
|
||||
public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
|
||||
myDispatcher.addListener(listener);
|
||||
}
|
||||
|
||||
public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
|
||||
myDispatcher.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(@NotNull PropertyChangeEvent event) {
|
||||
PropertyChangeEvent editorEvent = new PropertyChangeEvent(this, event.getPropertyName(), event.getOldValue(), event.getNewValue());
|
||||
myDispatcher.getMulticaster().propertyChange(editorEvent);
|
||||
}
|
||||
|
||||
public BackgroundEditorHighlighter getBackgroundHighlighter() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.compiler.instrumentation;
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader;
|
||||
import org.jetbrains.org.objectweb.asm.ClassWriter;
|
||||
|
||||
/**
|
||||
@@ -9,6 +10,11 @@ import org.jetbrains.org.objectweb.asm.ClassWriter;
|
||||
public class InstrumenterClassWriter extends ClassWriter {
|
||||
private final InstrumentationClassFinder myFinder;
|
||||
|
||||
public InstrumenterClassWriter(ClassReader reader, int flags, final InstrumentationClassFinder finder) {
|
||||
super(reader, flags);
|
||||
myFinder = finder;
|
||||
}
|
||||
|
||||
public InstrumenterClassWriter(int flags, final InstrumentationClassFinder finder) {
|
||||
super(flags);
|
||||
myFinder = finder;
|
||||
|
||||
@@ -437,7 +437,7 @@ public class Javac2 extends Javac {
|
||||
int version = getClassFileVersion(reader);
|
||||
|
||||
if (version >= Opcodes.V1_5 && !shouldBeSkippedByAnnotationPattern(reader)) {
|
||||
ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
|
||||
ClassWriter writer = new InstrumenterClassWriter(reader, getAsmClassWriterFlags(version), finder);
|
||||
|
||||
if (NotNullVerifyingInstrumenter.processClassFile(reader, writer)) {
|
||||
final FileOutputStream fileOutputStream = new FileOutputStream(path);
|
||||
|
||||
@@ -171,6 +171,9 @@ public class CompoundPositionManager extends PositionManagerEx implements MultiR
|
||||
return xStackFrame;
|
||||
}
|
||||
}
|
||||
catch (VMDisconnectedException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
|
||||
@@ -2104,6 +2104,9 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
@Override
|
||||
public void contextAction() {
|
||||
breakpointManager.applyThreadFilter(DebugProcessImpl.this, null); // clear the filter on resume
|
||||
if (myReturnValueWatcher != null) {
|
||||
myReturnValueWatcher.clear();
|
||||
}
|
||||
super.contextAction();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.debugger.impl.PositionUtil;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.ArgumentValueDescriptorImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.MethodReturnValueDescriptorImpl;
|
||||
import com.intellij.debugger.ui.tree.FieldDescriptor;
|
||||
import com.intellij.debugger.ui.tree.LocalVariableDescriptor;
|
||||
import com.intellij.debugger.ui.tree.NodeDescriptor;
|
||||
@@ -61,14 +62,20 @@ public class DefaultSourcePositionProvider extends SourcePositionProvider {
|
||||
return getSourcePositionForLocalVariable(names.iterator().next(), project, context, nearest);
|
||||
}
|
||||
}
|
||||
else if (descriptor instanceof MethodReturnValueDescriptorImpl) {
|
||||
DebugProcessImpl debugProcess = context.getDebugProcess();
|
||||
if (debugProcess != null) {
|
||||
return debugProcess.getPositionManager().getSourcePosition(((MethodReturnValueDescriptorImpl)descriptor).getMethod().location());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected SourcePosition getSourcePositionForField(@NotNull FieldDescriptor descriptor,
|
||||
@NotNull Project project,
|
||||
@NotNull DebuggerContextImpl context,
|
||||
boolean nearest) {
|
||||
private SourcePosition getSourcePositionForField(@NotNull FieldDescriptor descriptor,
|
||||
@NotNull Project project,
|
||||
@NotNull DebuggerContextImpl context,
|
||||
boolean nearest) {
|
||||
final ReferenceType type = descriptor.getField().declaringType();
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
|
||||
final String fieldName = descriptor.getField().name();
|
||||
@@ -134,10 +141,10 @@ public class DefaultSourcePositionProvider extends SourcePositionProvider {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected SourcePosition getSourcePositionForLocalVariable(String name,
|
||||
@NotNull Project project,
|
||||
@NotNull DebuggerContextImpl context,
|
||||
boolean nearest) {
|
||||
private SourcePosition getSourcePositionForLocalVariable(String name,
|
||||
@NotNull Project project,
|
||||
@NotNull DebuggerContextImpl context,
|
||||
boolean nearest) {
|
||||
PsiElement place = PositionUtil.getContextElement(context);
|
||||
if (place == null) return null;
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ public class JavaDebuggerEvaluator extends XDebuggerEvaluator {
|
||||
public void evaluate(@NotNull final XExpression expression,
|
||||
@NotNull final XEvaluationCallback callback,
|
||||
@Nullable XSourcePosition expressionPosition) {
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext()) {
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext(),
|
||||
myStackFrame.getStackFrameProxy().threadProxy()) {
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.NORMAL;
|
||||
|
||||
@@ -149,8 +149,7 @@ public class MethodReturnValueWatcher {
|
||||
|
||||
public void setFeatureEnabled(final boolean featureEnabled) {
|
||||
myFeatureEnabled = featureEnabled;
|
||||
myLastExecutedMethod = null;
|
||||
myLastMethodReturnValue = null;
|
||||
clear();
|
||||
}
|
||||
|
||||
public void enable(ThreadReference thread) {
|
||||
@@ -166,6 +165,12 @@ public class MethodReturnValueWatcher {
|
||||
updateRequestState(trackingEnabled && myFeatureEnabled, thread);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myLastExecutedMethod = null;
|
||||
myLastMethodReturnValue = null;
|
||||
myThread = null;
|
||||
}
|
||||
|
||||
private void updateRequestState(final boolean enabled, @Nullable final ThreadReference thread) {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread();
|
||||
try {
|
||||
@@ -178,8 +183,7 @@ public class MethodReturnValueWatcher {
|
||||
myExitRequest = null;
|
||||
}
|
||||
if (enabled) {
|
||||
myLastExecutedMethod = null;
|
||||
myLastMethodReturnValue = null;
|
||||
clear();
|
||||
myThread = thread;
|
||||
|
||||
if (Registry.is("debugger.watch.return.speedup")) {
|
||||
|
||||
@@ -388,7 +388,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
|
||||
public void dispose() {
|
||||
getProcess().dispose();
|
||||
Disposer.dispose(myUpdateAlarm);
|
||||
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
|
||||
DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getContextManager().setState(SESSION_EMPTY_CONTEXT, State.DISPOSED, Event.DISPOSE, null);
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.intellij.ui.content.Content;
|
||||
import com.intellij.unscramble.ThreadDumpPanel;
|
||||
import com.intellij.unscramble.ThreadState;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
@@ -556,6 +557,23 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static String methodNameWithArguments(Method m) {
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append(m.name()).append("(");
|
||||
res.append(StringUtil.join(m.argumentTypeNames(), new Function<String, String>() {
|
||||
@Override
|
||||
public String fun(String s) {
|
||||
return getSimpleName(s);
|
||||
}
|
||||
}, ", "));
|
||||
res.append(")");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public static String getSimpleName(String fqn) {
|
||||
return fqn.substring(fqn.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
public static String methodName(final Method m) {
|
||||
return methodName(signatureToName(m.declaringType().signature()), m.name(), m.signature());
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
|
||||
StringUtil.equals(EVALUATE_FINALLY_ON_POP_FRAME, secondSettings.EVALUATE_FINALLY_ON_POP_FRAME) &&
|
||||
FORCE_CLASSIC_VM == secondSettings.FORCE_CLASSIC_VM &&
|
||||
DISABLE_JIT == secondSettings.DISABLE_JIT &&
|
||||
SHOW_ALTERNATIVE_SOURCE == secondSettings.SHOW_ALTERNATIVE_SOURCE &&
|
||||
HOTSWAP_IN_BACKGROUND == secondSettings.HOTSWAP_IN_BACKGROUND &&
|
||||
SKIP_SYNTHETIC_METHODS == secondSettings.SKIP_SYNTHETIC_METHODS &&
|
||||
SKIP_CLASSLOADERS == secondSettings.SKIP_CLASSLOADERS &&
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<grid id="a2574" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="126" y="76" width="271" height="203"/>
|
||||
<xy x="126" y="76" width="271" height="217"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@@ -43,7 +43,7 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="f4cba" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
|
||||
<grid id="f4cba" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
|
||||
@@ -84,6 +84,14 @@
|
||||
<text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.package"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="9be9b" class="javax.swing.JCheckBox" binding="myArgsTypesCheckBox">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.prams.types"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
|
||||
@@ -38,6 +38,7 @@ public class ThreadsViewConfigurable extends BaseConfigurable {
|
||||
private JCheckBox myShowSyntheticsCheckBox;
|
||||
private JCheckBox myShowCurrentThreadChechBox;
|
||||
private JCheckBox myPackageCheckBox;
|
||||
private JCheckBox myArgsTypesCheckBox;
|
||||
private final CompositeDataBinding myDataBinding = new CompositeDataBinding();
|
||||
|
||||
public ThreadsViewConfigurable(ThreadsViewSettings settings) {
|
||||
@@ -45,6 +46,7 @@ public class ThreadsViewConfigurable extends BaseConfigurable {
|
||||
|
||||
myDataBinding.addBinding(new ToggleButtonBinding("SHOW_CLASS_NAME", myClassNameCheckBox));
|
||||
myDataBinding.addBinding(new ToggleButtonBinding("SHOW_PACKAGE_NAME", myPackageCheckBox));
|
||||
myDataBinding.addBinding(new ToggleButtonBinding("SHOW_ARGUMENTS_TYPES", myArgsTypesCheckBox));
|
||||
myDataBinding.addBinding(new ToggleButtonBinding("SHOW_LINE_NUMBER", myLineNumberCheckBox));
|
||||
myDataBinding.addBinding(new ToggleButtonBinding("SHOW_SOURCE_NAME", mySourceCheckBox));
|
||||
myDataBinding.addBinding(new ToggleButtonBinding("SHOW_THREAD_GROUPS", myShowGroupsCheckBox));
|
||||
|
||||
@@ -33,6 +33,7 @@ public class ThreadsViewSettings implements PersistentStateComponent<ThreadsView
|
||||
public boolean SHOW_SOURCE_NAME = false;
|
||||
public boolean SHOW_SYNTHETIC_FRAMES = true;
|
||||
public boolean SHOW_CURRENT_THREAD = true;
|
||||
public boolean SHOW_ARGUMENTS_TYPES = false;
|
||||
|
||||
public static ThreadsViewSettings getInstance() {
|
||||
return ServiceManager.getService(ThreadsViewSettings.class);
|
||||
|
||||
@@ -81,8 +81,6 @@ public class AlternativeSourceNotificationProvider extends EditorNotifications.P
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file.getFileType() == JavaClassFileType.INSTANCE) return null;
|
||||
|
||||
final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
|
||||
if (psiFile == null) return null;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -18,12 +18,15 @@ package com.intellij.debugger.ui.impl.watch;
|
||||
import com.intellij.debugger.DebuggerContext;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.settings.NodeRendererSettings;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.sun.jdi.ClassNotLoadedException;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.Type;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: lex
|
||||
@@ -34,7 +37,7 @@ public class MethodReturnValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
private final Method myMethod;
|
||||
private final Value myValue;
|
||||
|
||||
public MethodReturnValueDescriptorImpl(Project project, final Method method, Value value) {
|
||||
public MethodReturnValueDescriptorImpl(Project project, @NotNull Method method, Value value) {
|
||||
super(project);
|
||||
myMethod = method;
|
||||
myValue = value;
|
||||
@@ -44,9 +47,14 @@ public class MethodReturnValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Method getMethod() {
|
||||
return myMethod;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
//noinspection HardCodedStringLiteral
|
||||
return myMethod.toString();
|
||||
return NodeRendererSettings.getInstance().getClassRenderer().renderTypeName(myMethod.declaringType().name()) + "." +
|
||||
DebuggerUtilsEx.methodNameWithArguments(myMethod);
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
@@ -61,7 +69,7 @@ public class MethodReturnValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
}
|
||||
|
||||
public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
|
||||
throw new EvaluateException("Evaluation not supported for method return value");
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean canSetValue() {
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.*;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.settings.ThreadsViewSettings;
|
||||
import com.intellij.debugger.ui.tree.StackFrameDescriptor;
|
||||
@@ -180,8 +181,7 @@ public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements Stac
|
||||
Method method = myMethodOccurrence.getMethod();
|
||||
if (method != null) {
|
||||
myName = method.name();
|
||||
label.append(myName);
|
||||
label.append("()");
|
||||
label.append(settings.SHOW_ARGUMENTS_TYPES ? DebuggerUtilsEx.methodNameWithArguments(method) : myName);
|
||||
}
|
||||
if (settings.SHOW_LINE_NUMBER) {
|
||||
String lineNumber;
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.options.ex.SingleConfigurableEditor;
|
||||
import com.intellij.openapi.options.newEditor.OptionsEditorDialog;
|
||||
import com.intellij.openapi.options.newEditor.SettingsDialog;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
@@ -40,7 +40,7 @@ public class ShowStructureSettingsAction extends AnAction implements DumbAware {
|
||||
|
||||
static void showDialog(Project project) {
|
||||
if (Registry.is("ide.new.project.settings")) {
|
||||
new SingleConfigurableEditor(project, ProjectStructureConfigurable.getInstance(project), OptionsEditorDialog.DIMENSION_KEY) {
|
||||
new SingleConfigurableEditor(project, ProjectStructureConfigurable.getInstance(project), SettingsDialog.DIMENSION_KEY) {
|
||||
@NotNull
|
||||
@Override
|
||||
protected DialogStyle getStyle() {
|
||||
@@ -50,7 +50,7 @@ public class ShowStructureSettingsAction extends AnAction implements DumbAware {
|
||||
}
|
||||
else {
|
||||
ShowSettingsUtil
|
||||
.getInstance().editConfigurable(project, OptionsEditorDialog.DIMENSION_KEY, ProjectStructureConfigurable.getInstance(project));
|
||||
.getInstance().editConfigurable(project, SettingsDialog.DIMENSION_KEY, ProjectStructureConfigurable.getInstance(project));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public class RootDetectionProcessor {
|
||||
}
|
||||
|
||||
final File parentToSkip = result.getParentToSkip();
|
||||
if (parentToSkip != null && !parentToSkip.equals(dir)) {
|
||||
if (parentToSkip != null && !FileUtil.filesEqual(parentToSkip, dir)) {
|
||||
parentsToSkip.add(Pair.create(parentToSkip, i));
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public class RootDetectionProcessor {
|
||||
}
|
||||
for (Pair<File, Integer> pair : toSkip) {
|
||||
enabledForChildren.set(pair.getSecond(), false);
|
||||
if (!pair.getFirst().equals(dir)) {
|
||||
if (!FileUtil.filesEqual(pair.getFirst(), dir)) {
|
||||
parentsToSkip.add(pair);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ public abstract class AbstractProjectWizard extends AbstractWizard<ModuleWizardS
|
||||
}
|
||||
|
||||
protected boolean isLastStep() {
|
||||
return myCurrentStep == mySteps.size() - 1 || isLastStep(getCurrentStep());
|
||||
return isLastStep(getCurrentStep());
|
||||
}
|
||||
|
||||
private boolean isLastStep(int step) {
|
||||
|
||||
@@ -57,6 +57,10 @@ public class JavaModuleSourceRoot extends DetectedSourceRoot {
|
||||
|
||||
@NotNull
|
||||
public JavaModuleSourceRoot combineWith(@NotNull JavaModuleSourceRoot root) {
|
||||
return new JavaModuleSourceRoot(getDirectory(), getPackagePrefix(), ContainerUtil.concat(myLanguages, root.myLanguages));
|
||||
List<String> union = new ArrayList<String>(myLanguages.size() + root.myLanguages.size());
|
||||
union.addAll(myLanguages);
|
||||
union.addAll(root.myLanguages);
|
||||
ContainerUtil.removeDuplicates(union);
|
||||
return new JavaModuleSourceRoot(getDirectory(), getPackagePrefix(), union);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,24 +35,41 @@ public abstract class JavaSourceRootDetector extends ProjectStructureDetector {
|
||||
@NotNull List<DetectedProjectRoot> result) {
|
||||
final String fileExtension = getFileExtension();
|
||||
for (File child : children) {
|
||||
if (child.isFile()) {
|
||||
if (FileUtilRt.extensionEquals(child.getName(), fileExtension)) {
|
||||
Pair<File, String> root = CommonSourceRootDetectionUtil.IO_FILE.suggestRootForFileWithPackageStatement(child, base,
|
||||
getPackageNameFetcher(),
|
||||
true);
|
||||
if (root != null) {
|
||||
result.add(new JavaModuleSourceRoot(root.getFirst(), root.getSecond(), getLanguageName()));
|
||||
if (child.isFile() && FileUtilRt.extensionEquals(child.getName(), fileExtension)) {
|
||||
Pair<File, String> root = CommonSourceRootDetectionUtil.IO_FILE.suggestRootForFileWithPackageStatement(child, base,
|
||||
getPackageNameFetcher(),
|
||||
true);
|
||||
if (root != null) {
|
||||
JavaModuleSourceRoot sourceRoot = new JavaModuleSourceRoot(root.getFirst(), root.getSecond(), getLanguageName());
|
||||
result.add(sourceRoot);
|
||||
// sometimes java files from test data have package statement which includes names of all parent directories
|
||||
// (e.g. files in jdk/test/java/awt/regtesthelpers in JDK sources have package 'test.java.awt.regtesthelpers')
|
||||
// This check allows us to not skip searching for other java source roots when first such java file is found.
|
||||
if (areLastRootsTheSame(result, sourceRoot, 20)) {
|
||||
return DirectoryProcessingResult.skipChildrenAndParentsUpTo(root.getFirst());
|
||||
}
|
||||
else {
|
||||
return DirectoryProcessingResult.SKIP_CHILDREN;
|
||||
}
|
||||
}
|
||||
return DirectoryProcessingResult.SKIP_CHILDREN;
|
||||
}
|
||||
}
|
||||
return DirectoryProcessingResult.PROCESS_CHILDREN;
|
||||
}
|
||||
|
||||
private static boolean areLastRootsTheSame(List<DetectedProjectRoot> result, JavaModuleSourceRoot root, int threshold) {
|
||||
if (result.size() < threshold) return false;
|
||||
|
||||
List<DetectedProjectRoot> lastItems = result.subList(result.size() - threshold, result.size());
|
||||
for (DetectedProjectRoot item : lastItems) {
|
||||
if (!(item instanceof JavaModuleSourceRoot)) return false;
|
||||
JavaModuleSourceRoot oldRoot = (JavaModuleSourceRoot)item;
|
||||
if (!FileUtil.filesEqual(oldRoot.getDirectory(), root.getDirectory()) || !oldRoot.getPackagePrefix().equals(root.getPackagePrefix())
|
||||
|| !oldRoot.getRootTypeName().equals(root.getRootTypeName())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetectorId() {
|
||||
return "Java";
|
||||
|
||||
@@ -1339,7 +1339,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
|
||||
if (!myHolder.hasErrorResults()) {
|
||||
if (results.length == 0) {
|
||||
if (results.length == 0 || results[0] instanceof MethodCandidateInfo &&
|
||||
!((MethodCandidateInfo)results[0]).isApplicable() &&
|
||||
expression.getFunctionalInterfaceType() != null) {
|
||||
String description = null;
|
||||
if (expression.isConstructor()) {
|
||||
final PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass();
|
||||
@@ -1359,7 +1361,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (description != null) {
|
||||
final PsiElement referenceNameElement = expression.getReferenceNameElement();
|
||||
final HighlightInfo highlightInfo =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).descriptionAndTooltip(description).range(referenceNameElement).create();
|
||||
HighlightInfo.newHighlightInfo(results.length == 0 ? HighlightInfoType.WRONG_REF
|
||||
: HighlightInfoType.ERROR)
|
||||
.descriptionAndTooltip(description).range(referenceNameElement).create();
|
||||
myHolder.add(highlightInfo);
|
||||
final TextRange fixRange = HighlightMethodUtil.getFixRange(referenceNameElement);
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().createCreateMethodFromUsageFix(expression));
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -119,7 +120,8 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
map.put(methodReferenceExpression, functionalInterfaceType);
|
||||
final JavaResolveResult result = methodReferenceExpression.advancedResolve(false);
|
||||
final PsiElement element = result.getElement();
|
||||
if (element != null && result.isAccessible()) {
|
||||
if (element != null && result.isAccessible() &&
|
||||
!(result instanceof MethodCandidateInfo && !((MethodCandidateInfo)result).isApplicable())) {
|
||||
if (element instanceof PsiMethod && !isSimpleCall(parameters, callExpression, (PsiMethod)element)) {
|
||||
return null;
|
||||
}
|
||||
@@ -290,9 +292,9 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static String createMethodReferenceText(final PsiElement element,
|
||||
final PsiType functionalInterfaceType,
|
||||
final PsiParameter[] parameters) {
|
||||
public static String createMethodReferenceText(final PsiElement element,
|
||||
final PsiType functionalInterfaceType,
|
||||
final PsiParameter[] parameters) {
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -29,6 +29,7 @@ import com.intellij.ToolExtensionPoints;
|
||||
import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtilBase;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.EntryPointsManager;
|
||||
@@ -78,7 +79,7 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
private Set<RefElement> myProcessedSuspicious = null;
|
||||
private int myPhase;
|
||||
public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.dead.code.display.name");
|
||||
@NonNls public static final String SHORT_NAME = "unused";
|
||||
@NonNls public static final String SHORT_NAME = HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME;
|
||||
@NonNls public static final String ALTERNATIVE_ID = "UnusedDeclaration";
|
||||
|
||||
final List<EntryPoint> myExtensions = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.codeInspection.visibility;
|
||||
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil;
|
||||
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
|
||||
import com.intellij.codeInspection.InspectionProfile;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.fixes.ChangeModifierFix;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
private final VisibilityInspection myVisibilityInspection;
|
||||
|
||||
AccessCanBeTightenedInspection(@NotNull VisibilityInspection visibilityInspection) {
|
||||
myVisibilityInspection = visibilityInspection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return GroupNames.VISIBILITY_GROUP_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return "Member access can be tightened";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return VisibilityInspection.SHORT_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
|
||||
return new MyVisitor(holder);
|
||||
}
|
||||
|
||||
private class MyVisitor extends JavaElementVisitor {
|
||||
private final ProblemsHolder myHolder;
|
||||
private final UnusedDeclarationInspectionBase myDeadCodeInspection;
|
||||
|
||||
public MyVisitor(@NotNull ProblemsHolder holder) {
|
||||
myHolder = holder;
|
||||
InspectionProfile profile = InspectionProjectProfileManager.getInstance(holder.getProject()).getInspectionProfile();
|
||||
UnusedDeclarationInspectionBase tool = (UnusedDeclarationInspectionBase)profile.getUnwrappedTool(UnusedDeclarationInspectionBase.SHORT_NAME, holder.getFile());
|
||||
myDeadCodeInspection = tool == null ? new UnusedDeclarationInspectionBase() : tool;
|
||||
}
|
||||
private final Set<PsiClass> childMembersAreUsedOutsideMyPackage = ContainerUtil.newConcurrentSet();
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
checkMember(aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
checkMember(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitField(PsiField field) {
|
||||
checkMember(field);
|
||||
}
|
||||
|
||||
private void checkMember(@NotNull final PsiMember member) {
|
||||
if (member.hasModifierProperty(PsiModifier.PRIVATE) || member.hasModifierProperty(PsiModifier.NATIVE)) return;
|
||||
if (member instanceof PsiMethod && member instanceof SyntheticElement || !member.isPhysical()) return;
|
||||
|
||||
if (member instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)member;
|
||||
if (!method.getHierarchicalMethodSignature().getSuperSignatures().isEmpty()) {
|
||||
log(member.getName() + " overrides");
|
||||
return; // overrides
|
||||
}
|
||||
if (MethodUtils.isOverridden(method)) {
|
||||
log(member.getName() + " overridden");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (member instanceof PsiEnumConstant) return;
|
||||
if (member instanceof PsiClass && (member instanceof PsiAnonymousClass ||
|
||||
member instanceof PsiTypeParameter ||
|
||||
member instanceof PsiSyntheticClass ||
|
||||
PsiUtil.isLocalClass((PsiClass)member))) {
|
||||
return;
|
||||
}
|
||||
final PsiClass memberClass = member.getContainingClass();
|
||||
if (memberClass != null && (memberClass.isInterface() || memberClass.isEnum() || memberClass.isAnnotationType() || PsiUtil.isLocalClass(memberClass) && member instanceof PsiClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiFile memberFile = member.getContainingFile();
|
||||
Project project = memberFile.getProject();
|
||||
|
||||
if (myDeadCodeInspection.isEntryPoint(member)) {
|
||||
log(member.getName() +" is entry point");
|
||||
return;
|
||||
}
|
||||
|
||||
PsiModifierList memberModifierList = member.getModifierList();
|
||||
if (memberModifierList == null) return;
|
||||
final int currentLevel = PsiUtil.getAccessLevel(memberModifierList);
|
||||
final AtomicInteger maxLevel = new AtomicInteger(PsiUtil.ACCESS_LEVEL_PRIVATE);
|
||||
final AtomicBoolean foundUsage = new AtomicBoolean();
|
||||
PsiDirectory memberDirectory = memberFile.getContainingDirectory();
|
||||
final PsiPackage memberPackage = memberDirectory == null ? null : JavaDirectoryService.getInstance().getPackage(memberDirectory);
|
||||
log(member.getName()+ ": checking effective level for "+member);
|
||||
boolean result =
|
||||
UnusedSymbolUtil.processUsages(project, memberFile, member, new EmptyProgressIndicator(), null, new Processor<UsageInfo>() {
|
||||
@Override
|
||||
public boolean process(UsageInfo info) {
|
||||
foundUsage.set(true);
|
||||
PsiFile psiFile = info.getFile();
|
||||
if (psiFile == null) return true;
|
||||
if (!(psiFile instanceof PsiJavaFile)) {
|
||||
log(" refd from " + psiFile.getName() + "; set to public");
|
||||
maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC);
|
||||
if (memberClass != null) {
|
||||
childMembersAreUsedOutsideMyPackage.add(memberClass);
|
||||
}
|
||||
return false; // referenced from XML, has to be public
|
||||
}
|
||||
//int offset = info.getNavigationOffset();
|
||||
//if (offset == -1) return true;
|
||||
PsiElement element = info.getElement();
|
||||
if (element == null) return true;
|
||||
@PsiUtil.AccessLevel
|
||||
int level = getEffectiveLevel(element, psiFile, member, memberFile, memberClass, memberPackage);
|
||||
log(" ref in file " + psiFile.getName() + "; level = " + PsiUtil.getAccessModifier(level) + "; (" + element + ")");
|
||||
while (true) {
|
||||
int oldLevel = maxLevel.get();
|
||||
if (level <= oldLevel || maxLevel.compareAndSet(oldLevel, level)) break;
|
||||
}
|
||||
if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) {
|
||||
childMembersAreUsedOutsideMyPackage.add(memberClass);
|
||||
}
|
||||
|
||||
return level != PsiUtil.ACCESS_LEVEL_PUBLIC;
|
||||
}
|
||||
});
|
||||
|
||||
if (!foundUsage.get()) {
|
||||
log(member.getName() + " unused; ignore");
|
||||
return; // do not propose private for unused method
|
||||
}
|
||||
int max = maxLevel.get();
|
||||
if (max == PsiUtil.ACCESS_LEVEL_PRIVATE && memberClass == null) {
|
||||
max = suggestPackageLocal(member);
|
||||
}
|
||||
|
||||
log(member.getName()+": effective level is '" + PsiUtil.getAccessModifier(max) + "'");
|
||||
|
||||
if (max < currentLevel) {
|
||||
if (max == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL && member instanceof PsiClass && childMembersAreUsedOutsideMyPackage.contains(member)) {
|
||||
log(member.getName() + " children used outside my package; ignore");
|
||||
return; // e.g. some public method is used outside my package (without importing class)
|
||||
}
|
||||
PsiElement toHighlight = currentLevel == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL ? ((PsiNameIdentifierOwner)member).getNameIdentifier() : ContainerUtil.find(
|
||||
memberModifierList.getChildren(), new Condition<PsiElement>() {
|
||||
@Override
|
||||
public boolean value(PsiElement element) {
|
||||
return element instanceof PsiKeyword && element.getText().equals(PsiUtil.getAccessModifier(currentLevel));
|
||||
}
|
||||
});
|
||||
assert toHighlight != null : member +" ; " + ((PsiNameIdentifierOwner)member).getNameIdentifier() + "; "+ memberModifierList.getText();
|
||||
myHolder.registerProblem(toHighlight, "Access can be "+PsiUtil.getAccessModifier(max), new ChangeModifierFix(PsiUtil.getAccessModifier(max)));
|
||||
}
|
||||
}
|
||||
|
||||
@PsiUtil.AccessLevel
|
||||
private int getEffectiveLevel(@NotNull PsiElement element,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull PsiMember member,
|
||||
@NotNull PsiFile memberFile,
|
||||
PsiClass memberClass,
|
||||
PsiPackage memberPackage) {
|
||||
PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
if (memberClass != null && PsiTreeUtil.isAncestor(aClass, memberClass, false) ||
|
||||
aClass != null && PsiTreeUtil.isAncestor(memberClass, aClass, false)) {
|
||||
// access from the same file can be via private
|
||||
// except when used in annotation:
|
||||
// @Ann(value = C.VAL) class C { public static final String VAL = "xx"; }
|
||||
PsiAnnotation annotation = PsiTreeUtil.getParentOfType(element, PsiAnnotation.class);
|
||||
if (annotation != null && annotation.getParent() instanceof PsiModifierList && annotation.getParent().getParent() == aClass) {
|
||||
return suggestPackageLocal(member);
|
||||
}
|
||||
return myVisibilityInspection.SUGGEST_PRIVATE_FOR_INNERS || memberClass == aClass ? PsiUtil.ACCESS_LEVEL_PRIVATE : suggestPackageLocal(member);
|
||||
}
|
||||
//if (file == memberFile) {
|
||||
// return PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL;
|
||||
//}
|
||||
PsiDirectory directory = file.getContainingDirectory();
|
||||
PsiPackage aPackage = directory == null ? null : JavaDirectoryService.getInstance().getPackage(directory);
|
||||
if (aPackage == memberPackage || aPackage != null && memberPackage != null && Comparing.strEqual(aPackage.getQualifiedName(), memberPackage.getQualifiedName())) {
|
||||
return suggestPackageLocal(element);
|
||||
}
|
||||
if (aClass != null && memberClass != null && aClass.isInheritor(memberClass, true)) {
|
||||
//access from subclass can be via protected, except for constructors
|
||||
PsiElement resolved = element instanceof PsiReference ? ((PsiReference)element).resolve() : null;
|
||||
boolean isConstructor = resolved instanceof PsiClass && element.getParent() instanceof PsiNewExpression
|
||||
|| resolved instanceof PsiMethod && ((PsiMethod)resolved).isConstructor();
|
||||
if (!isConstructor) {
|
||||
return PsiUtil.ACCESS_LEVEL_PROTECTED;
|
||||
}
|
||||
}
|
||||
return PsiUtil.ACCESS_LEVEL_PUBLIC;
|
||||
}
|
||||
}
|
||||
|
||||
private int suggestPackageLocal(@NotNull PsiElement member) {
|
||||
boolean suggestPackageLocal = member instanceof PsiClass && ClassUtil.isTopLevelClass((PsiClass)member)
|
||||
? myVisibilityInspection.SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES
|
||||
: myVisibilityInspection.SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS;
|
||||
return suggestPackageLocal ? PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL : PsiUtil.ACCESS_LEVEL_PUBLIC;
|
||||
}
|
||||
|
||||
private static void log(String s) {
|
||||
//System.out.println(s);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -124,6 +124,12 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool {
|
||||
return new OptionsPanel();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LocalInspectionTool getSharedLocalInspectionTool() {
|
||||
return new AccessCanBeTightenedInspection(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -47,6 +47,7 @@ import com.intellij.xml.util.XmlStringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -85,7 +86,7 @@ public class ExternalAnnotationsLineMarkerProvider extends LineMarkerProviderDes
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LineMarkerInfo<PsiElement>(element, element.getTextRange().getStartOffset(),
|
||||
return new LineMarkerInfo<PsiElement>(element, element.getTextRange(),
|
||||
AllIcons.Gutter.ExtAnnotation,
|
||||
Pass.UPDATE_ALL,
|
||||
ourTooltipProvider, MyIconGutterHandler.INSTANCE,
|
||||
@@ -160,6 +161,12 @@ public class ExternalAnnotationsLineMarkerProvider extends LineMarkerProviderDes
|
||||
return "External annotations";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return AllIcons.Gutter.ExtAnnotation;
|
||||
}
|
||||
|
||||
private static class MyIconGutterHandler implements GutterIconNavigationHandler<PsiElement> {
|
||||
static final MyIconGutterHandler INSTANCE = new MyIconGutterHandler();
|
||||
|
||||
|
||||
@@ -352,9 +352,9 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle
|
||||
final TypeMigrationRules rules = new TypeMigrationRules();
|
||||
final PsiSubstitutor compoundSubstitutor =
|
||||
TypeConversionUtil.getSuperClassSubstitutor(superClass, derivedClass, PsiSubstitutor.EMPTY).putAll(psiSubstitutor);
|
||||
rules.setMigrationRootType(JavaPsiFacade.getElementFactory(project).createType(baseClass, compoundSubstitutor));
|
||||
rules.setBoundScope(new LocalSearchScope(derivedClass));
|
||||
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, referenceParameterList);
|
||||
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, referenceParameterList,
|
||||
JavaPsiFacade.getElementFactory(project).createType(baseClass, compoundSubstitutor));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -72,10 +72,9 @@ public class VariableTypeFromCallFix implements IntentionAction {
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final TypeMigrationRules rules = new TypeMigrationRules();
|
||||
rules.setMigrationRootType(myExpressionType);
|
||||
rules.setBoundScope(PsiSearchHelper.SERVICE.getInstance(project).getUseScope(myVar));
|
||||
|
||||
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, myVar);
|
||||
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, myVar, myExpressionType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -386,7 +386,9 @@ public class PseudoLambdaReplaceTemplate {
|
||||
lambdaExpression = convertClassTypeExpression(lambdaExpression);
|
||||
lambdaExpression = convertToJavaLambda(lambdaExpression);
|
||||
}
|
||||
LOG.assertTrue(lambdaExpression != null);
|
||||
if (lambdaExpression == null) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
final String lambdaExpressionText;
|
||||
final String elementText;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -29,6 +29,7 @@ import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
|
||||
@@ -147,28 +148,14 @@ public class ClassesTreeStructureProvider implements SelectableTreeStructureProv
|
||||
return viewProvider.getPsi(viewProvider.getBaseLanguage());
|
||||
}
|
||||
|
||||
private static boolean isTopLevelClass(final PsiElement element, PsiFile baseRootFile) {
|
||||
|
||||
private static boolean isTopLevelClass(final PsiElement element, @NotNull PsiFile baseRootFile) {
|
||||
if (!(element instanceof PsiClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (element instanceof PsiAnonymousClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiFile parentFile = parentFileOf((PsiClass)element);
|
||||
// do not select JspClass
|
||||
return parentFile != null && parentFile.getLanguage() == baseRootFile.getLanguage();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiFile parentFileOf(final PsiClass psiClass) {
|
||||
return psiClass.getContainingClass() == null ? psiClass.getContainingFile() : null;
|
||||
return ClassUtil.isTopLevelClass((PsiClass)element);
|
||||
}
|
||||
|
||||
private static class PsiClassOwnerTreeNode extends PsiFileNode {
|
||||
|
||||
public PsiClassOwnerTreeNode(PsiClassOwner classOwner, ViewSettings settings) {
|
||||
super(classOwner.getProject(), classOwner, settings);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.intellij.refactoring.util.EnumConstantsUtil;
|
||||
import com.intellij.refactoring.util.FixableUsageInfo;
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Functions;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
import java.util.*;
|
||||
@@ -146,10 +147,11 @@ public class ExtractEnumProcessor {
|
||||
|
||||
final TypeMigrationRules rules = new TypeMigrationRules();
|
||||
rules.addConversionDescriptor(new EnumTypeConversionRule(myEnumConstants));
|
||||
rules.setMigrationRootType(
|
||||
JavaPsiFacade.getElementFactory(myProject).createType(myClass));
|
||||
rules.setBoundScope(GlobalSearchScope.projectScope(myProject));
|
||||
myTypeMigrationProcessor = new TypeMigrationProcessor(myProject, PsiUtilCore.toPsiElementArray(myEnumConstants), rules);
|
||||
myTypeMigrationProcessor = new TypeMigrationProcessor(myProject,
|
||||
PsiUtilCore.toPsiElementArray(myEnumConstants),
|
||||
Functions.<PsiElement, PsiType>constant(JavaPsiFacade.getElementFactory(myProject).createType(myClass)),
|
||||
rules);
|
||||
for (UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) {
|
||||
final PsiElement migrateElement = usageInfo.getElement();
|
||||
if (migrateElement instanceof PsiField) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package com.intellij.refactoring.introduceParameter;
|
||||
|
||||
import com.intellij.codeInspection.AnonymousCanBeLambdaInspection;
|
||||
import com.intellij.codeInspection.LambdaCanBeMethodReferenceInspection;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.help.HelpManager;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
@@ -275,15 +276,25 @@ public class IntroduceParameterDialog extends RefactoringDialog {
|
||||
isDeleteLocalVariable = myPanel.isDeleteLocalVariable();
|
||||
}
|
||||
|
||||
final PsiType selectedType = getSelectedType();
|
||||
final IntroduceParameterProcessor processor = new IntroduceParameterProcessor(
|
||||
myProject, myMethodToReplaceIn, myMethodToSearchFor,
|
||||
parameterInitializer, myExpression,
|
||||
myLocalVar, isDeleteLocalVariable,
|
||||
getParameterName(), myPanel.isReplaceAllOccurences(),
|
||||
myPanel.getReplaceFieldsWithGetters(), isDeclareFinal(), myPanel.isGenerateDelegate(), getSelectedType(), myPanel.getParametersToRemove());
|
||||
myPanel.getReplaceFieldsWithGetters(), isDeclareFinal(), myPanel.isGenerateDelegate(), selectedType, myPanel.getParametersToRemove());
|
||||
if (myCbCollapseToLambda.isVisible() && myCbCollapseToLambda.isSelected() && parameterInitializer != null) {
|
||||
PsiExpression lambda = AnonymousCanBeLambdaInspection.replaceAnonymousWithLambda(parameterInitializer, getSelectedType());
|
||||
PsiExpression lambda = AnonymousCanBeLambdaInspection.replaceAnonymousWithLambda(parameterInitializer, selectedType);
|
||||
if (lambda != null) {
|
||||
final PsiParameter[] lambdaParameters = ((PsiLambdaExpression)lambda).getParameterList().getParameters();
|
||||
final PsiCallExpression toConvertCall = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(((PsiLambdaExpression)lambda).getBody(), lambdaParameters, selectedType);
|
||||
if (toConvertCall != null) {
|
||||
final String methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(toConvertCall, selectedType, lambdaParameters);
|
||||
if (methodReferenceText != null) {
|
||||
lambda = JavaPsiFacade.getElementFactory(getProject()).createExpressionFromText(methodReferenceText, lambda);
|
||||
}
|
||||
}
|
||||
|
||||
processor.setParameterInitializer(lambda);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +558,9 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
|
||||
? new PsiElement[] {exprInRange}
|
||||
: CodeInsightUtil.findStatementsInRange(copy, elements[0].getTextRange().getStartOffset(),
|
||||
elements[elements.length - 1].getTextRange().getEndOffset());
|
||||
final MyExtractMethodProcessor processor = new MyExtractMethodProcessor(project, editor, elementsCopy);
|
||||
final List<PsiMethod> enclosingMethodsInCopy = getEnclosingMethods(Util.getContainingMethod(elementsCopy[0]));
|
||||
final MyExtractMethodProcessor processor = new MyExtractMethodProcessor(project, editor, elementsCopy,
|
||||
enclosingMethodsInCopy.get(enclosingMethodsInCopy.size() - 1));
|
||||
try {
|
||||
if (!processor.prepare()) return false;
|
||||
processor.showDialog();
|
||||
@@ -700,8 +702,11 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
|
||||
}
|
||||
|
||||
private static class MyExtractMethodProcessor extends ExtractMethodProcessor {
|
||||
public MyExtractMethodProcessor(Project project, Editor editor, PsiElement[] elements) {
|
||||
private final PsiMethod myTopEnclosingMethod;
|
||||
|
||||
public MyExtractMethodProcessor(Project project, Editor editor, PsiElement[] elements, PsiMethod topEnclosing) {
|
||||
super(project, editor, elements, null, REFACTORING_NAME, null, null);
|
||||
myTopEnclosingMethod = topEnclosing;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -755,7 +760,8 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
|
||||
final InputVariables inputVariables = getInputVariables();
|
||||
List<VariableData> datas = new ArrayList<VariableData>();
|
||||
for (VariableData data : inputVariables.getInputVariables()) {
|
||||
if (data.variable instanceof PsiParameter) {
|
||||
final PsiVariable variable = data.variable;
|
||||
if (variable instanceof PsiParameter && myTopEnclosingMethod.equals(((PsiParameter)variable).getDeclarationScope())) {
|
||||
continue;
|
||||
}
|
||||
datas.add(data);
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.typeMigration.ui.TypeMigrationDialog;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
|
||||
@@ -42,7 +43,7 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
|
||||
while (typeElement != null) {
|
||||
final PsiElement parent = typeElement.getParent();
|
||||
if (parent instanceof PsiVariable || (parent instanceof PsiMember && !(parent instanceof PsiClass)) || isClassArgument(parent)) {
|
||||
invoke(project, parent, null, editor);
|
||||
invoke(project, parent, null, null, editor);
|
||||
return;
|
||||
}
|
||||
typeElement = PsiTreeUtil.getParentOfType(parent, PsiTypeElement.class, false);
|
||||
@@ -61,11 +62,11 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
|
||||
|
||||
public static boolean invokeOnElement(final Project project, final PsiElement element) {
|
||||
if (element instanceof PsiVariable || (element instanceof PsiMember && !(element instanceof PsiClass)) || element instanceof PsiFile) {
|
||||
invoke(project, element, null, null);
|
||||
invoke(project, element, null, null, null);
|
||||
return true;
|
||||
}
|
||||
if (isClassArgument(element)) {
|
||||
invoke(project, element, null, null);
|
||||
invoke(project, element, null, null, null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -87,9 +88,9 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void invoke(final Project project, final PsiElement root, final TypeMigrationRules rules, final Editor editor) {
|
||||
public static void invoke(final Project project, final PsiElement root, final PsiType type, final TypeMigrationRules rules, final Editor editor) {
|
||||
if (Util.canBeMigrated(root)) {
|
||||
TypeMigrationDialog dialog = new TypeMigrationDialog(project, root, rules);
|
||||
TypeMigrationDialog dialog = new TypeMigrationDialog.SingleElement(project, root, type, rules);
|
||||
dialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.refactoring.typeMigration;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
class MigrateGetterNameSetting {
|
||||
private static final String CODE_ALWAYS_YES = "Always Migrate Method Names";
|
||||
private static final String CODE_ALWAYS_NO = "Never Migrate Method Names";
|
||||
private static final String[] CODES = new String[]{CODE_ALWAYS_YES, Messages.YES_BUTTON, CODE_ALWAYS_NO, Messages.NO_BUTTON};
|
||||
|
||||
private final AtomicReference<Boolean> myGlobalValue = new AtomicReference<Boolean>();
|
||||
|
||||
void askUserIfNeed(final OverridenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) {
|
||||
final Boolean globalValue = myGlobalValue.get();
|
||||
if (globalValue == null) {
|
||||
final String currentName = ((PsiMethod)info.getElement()).getName();
|
||||
final String messageText = String.format("Do migrate getter name from '%s' to '%s' since return type is migrated to '%s'?",
|
||||
currentName,
|
||||
newMethodName,
|
||||
migrationReturnType.getCanonicalText());
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Boolean globalValue = myGlobalValue.get();
|
||||
if (globalValue == null) {
|
||||
final int code = showChooserDialog(messageText);
|
||||
if (code == 0) {
|
||||
myGlobalValue.set(true);
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
else if (code == 1) {
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
else if (code == 2) {
|
||||
myGlobalValue.set(false);
|
||||
}
|
||||
}
|
||||
else if (globalValue.equals(Boolean.TRUE)) {
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (globalValue.equals(Boolean.TRUE)) {
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
private static int showChooserDialog(String messageText) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return messageText.contains("dontMigrateName") ? 3 : 1;
|
||||
} else {
|
||||
return Messages.showIdeaMessageDialog(null, messageText, "Type Migration", CODES, 0, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TypeConversionDescriptorBase {
|
||||
@@ -54,7 +55,7 @@ public class TypeConversionDescriptorBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PsiExpression replace(PsiExpression expression) throws IncorrectOperationException {
|
||||
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,18 +47,19 @@ public class TypeEvaluator {
|
||||
private final TypeMigrationRules myRules;
|
||||
private final TypeMigrationLabeler myLabeler;
|
||||
|
||||
|
||||
public TypeEvaluator(final LinkedList<Pair<TypeMigrationUsageInfo, PsiType>> types, final TypeMigrationLabeler labeler) {
|
||||
myLabeler = labeler;
|
||||
myRules = labeler.getRules();
|
||||
myRules = labeler == null ? new TypeMigrationRules() : labeler.getRules();
|
||||
myTypeMap = new HashMap<TypeMigrationUsageInfo, LinkedList<PsiType>>();
|
||||
|
||||
for (final Pair<TypeMigrationUsageInfo, PsiType> p : types) {
|
||||
final LinkedList<PsiType> e = new LinkedList<PsiType>();
|
||||
if (types != null) {
|
||||
for (final Pair<TypeMigrationUsageInfo, PsiType> p : types) {
|
||||
final LinkedList<PsiType> e = new LinkedList<PsiType>();
|
||||
|
||||
e.addFirst(p.getSecond());
|
||||
e.addFirst(p.getSecond());
|
||||
|
||||
myTypeMap.put(p.getFirst(), e);
|
||||
myTypeMap.put(p.getFirst(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -475,7 +476,15 @@ public class TypeEvaluator {
|
||||
}
|
||||
|
||||
void bindTypeParameters(PsiType formal, final PsiType actual) {
|
||||
if (formal instanceof PsiWildcardType) formal = ((PsiWildcardType)formal).getBound();
|
||||
if (formal instanceof PsiWildcardType) {
|
||||
if (actual instanceof PsiCapturedWildcardType &&
|
||||
((PsiWildcardType)formal).isExtends() == ((PsiCapturedWildcardType)actual).getWildcard().isExtends()) {
|
||||
bindTypeParameters(((PsiWildcardType)formal).getBound(), ((PsiCapturedWildcardType)actual).getWildcard().getBound());
|
||||
return;
|
||||
} else {
|
||||
formal = ((PsiWildcardType)formal).getBound();
|
||||
}
|
||||
}
|
||||
|
||||
if (formal instanceof PsiArrayType && actual instanceof PsiArrayType) {
|
||||
bindTypeParameters(((PsiArrayType)formal).getComponentType(), ((PsiArrayType)actual).getComponentType());
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.refactoring.typeMigration;
|
||||
|
||||
import com.intellij.codeInsight.generation.GenerateMembersUtil;
|
||||
import com.intellij.codeInsight.generation.GetterSetterPrototypeProvider;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -35,13 +37,14 @@ import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.*;
|
||||
import com.intellij.util.graph.DFSTBuilder;
|
||||
import com.intellij.util.graph.GraphGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -50,6 +53,8 @@ import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @author db
|
||||
@@ -65,6 +70,7 @@ public class TypeMigrationLabeler {
|
||||
}
|
||||
|
||||
private final TypeMigrationRules myRules;
|
||||
private final Function<PsiElement, PsiType> myMigrationRootTypeFunction;
|
||||
private TypeEvaluator myTypeEvaluator;
|
||||
private final LinkedHashMap<PsiElement, Object> myConversions;
|
||||
private final HashSet<Pair<SmartPsiElementPointer<PsiExpression>, PsiType>> myFailedConversions;
|
||||
@@ -80,10 +86,14 @@ public class TypeMigrationLabeler {
|
||||
private final Map<Pair<TypeMigrationUsageInfo, TypeMigrationUsageInfo>, Set<PsiElement>> myRootUsagesTree = new HashMap<Pair<TypeMigrationUsageInfo, TypeMigrationUsageInfo>, Set<PsiElement>>();
|
||||
private final Set<TypeMigrationUsageInfo> myProcessedRoots = new HashSet<TypeMigrationUsageInfo>();
|
||||
|
||||
public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) {
|
||||
this(rules, Functions.<PsiElement, PsiType>constant(rootType));
|
||||
}
|
||||
|
||||
public TypeMigrationLabeler(final TypeMigrationRules rules) {
|
||||
public TypeMigrationLabeler(final TypeMigrationRules rules, Function<PsiElement, PsiType> migrationRootTypeFunction) {
|
||||
myRules = rules;
|
||||
|
||||
myMigrationRootTypeFunction = migrationRootTypeFunction;
|
||||
|
||||
myConversions = new LinkedHashMap<PsiElement, Object>();
|
||||
myFailedConversions = new HashSet<Pair<SmartPsiElementPointer<PsiExpression>, PsiType>>();
|
||||
myNewExpressionTypeChange = new LinkedHashMap<TypeMigrationUsageInfo, PsiType>();
|
||||
@@ -94,6 +104,10 @@ public class TypeMigrationLabeler {
|
||||
return myFailedConversions.size() > 0;
|
||||
}
|
||||
|
||||
public Function<PsiElement, PsiType> getMigrationRootTypeFunction() {
|
||||
return myMigrationRootTypeFunction;
|
||||
}
|
||||
|
||||
public String[] getFailedConversionsReport() {
|
||||
final String[] report = new String[myFailedConversions.size()];
|
||||
int j = 0;
|
||||
@@ -245,45 +259,77 @@ public class TypeMigrationLabeler {
|
||||
return infos;
|
||||
}
|
||||
|
||||
MigrationProducer createMigratorFor(UsageInfo[] usages) {
|
||||
final Map<UsageInfo, Object> conversions = new com.intellij.util.containers.HashMap<UsageInfo, Object>();
|
||||
for (UsageInfo usage : usages) {
|
||||
final Object conversion = getConversion(usage.getElement());
|
||||
if (conversion != null) {
|
||||
conversions.put(usage, conversion);
|
||||
}
|
||||
}
|
||||
return new MigrationProducer(conversions);
|
||||
}
|
||||
|
||||
public void change(final TypeMigrationUsageInfo usageInfo, @NotNull Consumer<PsiNewExpression> consumer) {
|
||||
final PsiElement element = usageInfo.getElement();
|
||||
if (element == null) return;
|
||||
final Project project = element.getProject();
|
||||
if (element instanceof PsiExpression) {
|
||||
final PsiExpression expression = (PsiExpression)element;
|
||||
if (element instanceof PsiNewExpression) {
|
||||
for (Map.Entry<TypeMigrationUsageInfo, PsiType> info : myNewExpressionTypeChange.entrySet()) {
|
||||
final PsiElement expressionToReplace = info.getKey().getElement();
|
||||
if (expression.equals(expressionToReplace)) {
|
||||
final PsiNewExpression newExpression =
|
||||
TypeMigrationReplacementUtil.replaceNewExpressionType(project, (PsiNewExpression)expressionToReplace, info);
|
||||
if (newExpression != null) {
|
||||
consumer.consume(newExpression);
|
||||
class MigrationProducer {
|
||||
private final Map<UsageInfo, Object> myRemainConversions;
|
||||
|
||||
private MigrationProducer(Map<UsageInfo, Object> conversions) {
|
||||
myRemainConversions = conversions;
|
||||
}
|
||||
|
||||
public void change(final TypeMigrationUsageInfo usageInfo, @NotNull Consumer<PsiNewExpression> consumer) {
|
||||
final PsiElement element = usageInfo.getElement();
|
||||
if (element == null) return;
|
||||
final Project project = element.getProject();
|
||||
if (element instanceof PsiExpression) {
|
||||
final PsiExpression expression = (PsiExpression)element;
|
||||
if (element instanceof PsiNewExpression) {
|
||||
for (Map.Entry<TypeMigrationUsageInfo, PsiType> info : myNewExpressionTypeChange.entrySet()) {
|
||||
final PsiElement expressionToReplace = info.getKey().getElement();
|
||||
if (expression.equals(expressionToReplace)) {
|
||||
final PsiNewExpression newExpression =
|
||||
TypeMigrationReplacementUtil.replaceNewExpressionType(project, (PsiNewExpression)expressionToReplace, info);
|
||||
if (newExpression != null) {
|
||||
consumer.consume(newExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final Object conversion = myRemainConversions.get(usageInfo);
|
||||
if (conversion != null) {
|
||||
myRemainConversions.remove(usageInfo);
|
||||
TypeMigrationReplacementUtil.replaceExpression(expression, project, conversion, myTypeEvaluator);
|
||||
}
|
||||
} else if (element instanceof PsiReferenceParameterList) {
|
||||
for (Map.Entry<TypeMigrationUsageInfo, PsiClassType> entry : myClassTypeArgumentsChange.entrySet()) {
|
||||
if (element.equals(entry.getKey().getElement())) { //todo check null
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
try {
|
||||
element.getParent().replace(factory.createReferenceElementByType(entry.getValue()));
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final Object conversion = myConversions.get(element);
|
||||
if (conversion != null) {
|
||||
myConversions.remove(element);
|
||||
TypeMigrationReplacementUtil.replaceExpression(expression, project, conversion);
|
||||
}
|
||||
} else if (element instanceof PsiReferenceParameterList) {
|
||||
for (Map.Entry<TypeMigrationUsageInfo, PsiClassType> entry : myClassTypeArgumentsChange.entrySet()) {
|
||||
if (element.equals(entry.getKey().getElement())) { //todo check null
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
try {
|
||||
element.getParent().replace(factory.createReferenceElementByType(entry.getValue()));
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
else {
|
||||
TypeMigrationReplacementUtil.migratePsiMemberType(element, project, getTypeEvaluator().getType(usageInfo));
|
||||
if (usageInfo instanceof OverridenUsageInfo) {
|
||||
final String migrationName = ((OverridenUsageInfo)usageInfo).getMigrateMethodName();
|
||||
if (migrationName != null) {
|
||||
new RenameProcessor(project, element, migrationName, false, false).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
TypeMigrationReplacementUtil.migratePsiMemberType(element, project, getTypeEvaluator().getType(usageInfo));
|
||||
|
||||
Object getConversion(UsageInfo info) {
|
||||
return myRemainConversions.remove(info);
|
||||
}
|
||||
|
||||
boolean allOfConversionsUsed() {
|
||||
return myRemainConversions.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,12 +576,16 @@ public class TypeMigrationLabeler {
|
||||
|
||||
|
||||
final PsiMethod[] methods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY);
|
||||
final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method);
|
||||
final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length];
|
||||
for (int i = -1; i < methods.length; i++) {
|
||||
final TypeMigrationUsageInfo m;
|
||||
if (i < 0) {
|
||||
final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method);
|
||||
m = overridenUsageInfo;
|
||||
final String newMethodName = isMethodNameCanBeChanged(method);
|
||||
if (newMethodName != null) {
|
||||
myRules.getMigrateGetterNameSetting().askUserIfNeed(overridenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot));
|
||||
}
|
||||
}
|
||||
else {
|
||||
overriders[i] = new OverriderUsageInfo(methods[i], method);
|
||||
@@ -544,7 +594,6 @@ public class TypeMigrationLabeler {
|
||||
|
||||
alreadyProcessed = addRoot(m, type, place, alreadyProcessed);
|
||||
}
|
||||
overridenUsageInfo.setOverriders(overriders);
|
||||
|
||||
return !alreadyProcessed;
|
||||
}
|
||||
@@ -570,8 +619,6 @@ public class TypeMigrationLabeler {
|
||||
alreadyProcessed = addRoot(paramUsageInfo, type, place, alreadyProcessed);
|
||||
}
|
||||
|
||||
overridenUsageInfo.setOverriders(overriders);
|
||||
|
||||
return !alreadyProcessed;
|
||||
}
|
||||
else {
|
||||
@@ -579,6 +626,47 @@ public class TypeMigrationLabeler {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String isMethodNameCanBeChanged(PsiMethod method) {
|
||||
if (myCurrentRoot == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiElement root = myCurrentRoot.getElement();
|
||||
if (!(root instanceof PsiField)) {
|
||||
return null;
|
||||
}
|
||||
PsiField field = (PsiField) root;
|
||||
final PsiType migrationType = myTypeEvaluator.getType(root);
|
||||
if (migrationType == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiType sourceType = field.getType();
|
||||
if (TypeConversionUtil.isAssignable(migrationType, sourceType)) {
|
||||
return null;
|
||||
}
|
||||
if (!(migrationType.equals(PsiType.BOOLEAN) || migrationType.equals(PsiType.BOOLEAN.getBoxedType(field))) &&
|
||||
!(sourceType.equals(PsiType.BOOLEAN) || sourceType.equals(PsiType.BOOLEAN.getBoxedType(field)))) {
|
||||
return null;
|
||||
}
|
||||
final PsiMethod[] getters =
|
||||
GetterSetterPrototypeProvider.findGetters(field.getContainingClass(), field.getName(), field.hasModifierProperty(PsiModifier.STATIC));
|
||||
if (getters != null) {
|
||||
for (PsiMethod getter : getters) {
|
||||
if (getter.isEquivalentTo(method)) {
|
||||
final String suggestedName = GenerateMembersUtil.suggestGetterName(field.getName(), migrationType, method.getProject());
|
||||
if (!suggestedName.equals(method.getName())) {
|
||||
if (getter.getContainingClass().findMethodsByName(suggestedName, true).length == 0) {
|
||||
return null;
|
||||
}
|
||||
return suggestedName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static boolean typeContainsTypeParameters(@Nullable PsiType originalType, @NotNull Set<PsiTypeParameter> excluded) {
|
||||
if (originalType instanceof PsiClassType) {
|
||||
final PsiClassType psiClassType = (PsiClassType)originalType;
|
||||
@@ -884,9 +972,8 @@ public class TypeMigrationLabeler {
|
||||
myTypeEvaluator = new TypeEvaluator(myMigrationRoots, this);
|
||||
|
||||
|
||||
final PsiType rootType = myRules.getMigrationRootType();
|
||||
for (PsiElement victim : victims) {
|
||||
addMigrationRoot(victim, rootType, null, false, true, true);
|
||||
addMigrationRoot(victim, myMigrationRootTypeFunction.fun(victim), null, false, true, true);
|
||||
}
|
||||
|
||||
if (autoMigrate) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.refactoring.typeMigration;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
@@ -34,49 +35,64 @@ import com.intellij.ui.content.Content;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.usageView.UsageViewManager;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.usages.Usage;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.*;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
|
||||
public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
private final static Logger LOG = Logger.getInstance(TypeMigrationProcessor.class);
|
||||
private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3;
|
||||
|
||||
private PsiElement[] myRoot;
|
||||
private Function<PsiElement, PsiType> myRootTypes;
|
||||
private final TypeMigrationRules myRules;
|
||||
private TypeMigrationLabeler myLabeler;
|
||||
|
||||
public TypeMigrationProcessor(final Project project, final PsiElement root, final TypeMigrationRules rules) {
|
||||
this(project, new PsiElement[]{root}, rules);
|
||||
}
|
||||
|
||||
public TypeMigrationProcessor(final Project project, final PsiElement[] roots, final TypeMigrationRules rules) {
|
||||
public TypeMigrationProcessor(final Project project, final PsiElement[] roots, final Function<PsiElement, PsiType> rootTypes, final TypeMigrationRules rules) {
|
||||
super(project);
|
||||
myRoot = roots;
|
||||
myRules = rules;
|
||||
myRootTypes = rootTypes;
|
||||
}
|
||||
|
||||
public static void runHighlightingTypeMigration(final Project project,
|
||||
final Editor editor,
|
||||
final TypeMigrationRules rules,
|
||||
final PsiElement root,
|
||||
final PsiType migrationType) {
|
||||
runHighlightingTypeMigration(project, editor, rules, root, migrationType, false);
|
||||
}
|
||||
|
||||
public static void runHighlightingTypeMigration(final Project project,
|
||||
final Editor editor,
|
||||
final TypeMigrationRules rules,
|
||||
final PsiElement root,
|
||||
final PsiType migrationType,
|
||||
final boolean optimizeImports) {
|
||||
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.<PsiElement, PsiType>constant(migrationType), optimizeImports);
|
||||
}
|
||||
|
||||
|
||||
public static void runHighlightingTypeMigration(final Project project,
|
||||
final Editor editor,
|
||||
final TypeMigrationRules rules,
|
||||
final PsiElement root) {
|
||||
runHighlightingTypeMigration(project, editor, rules, root, false);
|
||||
}
|
||||
|
||||
public static void runHighlightingTypeMigration(final Project project,
|
||||
final Editor editor,
|
||||
final TypeMigrationRules rules,
|
||||
final PsiElement root,
|
||||
final boolean optimizeImports) {
|
||||
final PsiFile containingFile = root.getContainingFile();
|
||||
final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, root, rules) {
|
||||
final Editor editor,
|
||||
final TypeMigrationRules rules,
|
||||
final PsiElement[] roots,
|
||||
final Function<PsiElement, PsiType> migrationTypeFunction,
|
||||
final boolean optimizeImports) {
|
||||
final Set<PsiFile> containingFiles = ContainerUtil.map2Set(roots, new Function<PsiElement, PsiFile>() {
|
||||
@Override
|
||||
public PsiFile fun(PsiElement element) {
|
||||
return element.getContainingFile();
|
||||
}
|
||||
});
|
||||
final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules) {
|
||||
@Override
|
||||
public void performRefactoring(@NotNull final UsageInfo[] usages) {
|
||||
super.performRefactoring(usages);
|
||||
@@ -86,7 +102,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
final List<PsiElement> result = new ArrayList<PsiElement>();
|
||||
for (UsageInfo usage : usages) {
|
||||
final PsiElement element = usage.getElement();
|
||||
if (element == null || containingFile != element.getContainingFile()) continue;
|
||||
if (element == null || !containingFiles.contains(element.getContainingFile())) continue;
|
||||
if (element instanceof PsiMethod) {
|
||||
result.add(((PsiMethod)element).getReturnTypeElement());
|
||||
}
|
||||
@@ -120,6 +136,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
processor.run();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
|
||||
@@ -152,35 +169,56 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
|
||||
@Override
|
||||
protected void previewRefactoring(@NotNull final UsageInfo[] usages) {
|
||||
MigrationPanel panel = new MigrationPanel(myRoot[0], myLabeler, myProject, isPreviewUsages());
|
||||
String text;
|
||||
if (myRoot[0] instanceof PsiField) {
|
||||
text = "field \'" + ((PsiField)myRoot[0]).getName() + "\'";
|
||||
MigrationPanel panel = new MigrationPanel(myRoot, myLabeler, myProject, isPreviewUsages());
|
||||
String name;
|
||||
if (myRoot.length == 1) {
|
||||
String fromType = assertNotNull(TypeMigrationLabeler.getElementType(myRoot[0])).getPresentableText();
|
||||
String toType = myRootTypes.fun(myRoot[0]).getPresentableText();
|
||||
String text;
|
||||
text = getPresentation(myRoot[0]);
|
||||
name = "Migrate Type of " + text + " from \'" + fromType + "\' to \'" + toType + "\'";
|
||||
} else {
|
||||
final int rootsInPresentationCount = myRoot.length > MAX_ROOT_IN_PREVIEW_PRESENTATION ? MAX_ROOT_IN_PREVIEW_PRESENTATION : myRoot.length;
|
||||
String[] rootsPresentation = new String[rootsInPresentationCount];
|
||||
for (int i = 0; i < rootsInPresentationCount; i++) {
|
||||
final PsiElement root = myRoot[i];
|
||||
rootsPresentation[i] = root instanceof PsiNamedElement ? ((PsiNamedElement)root).getName() : root.getText();
|
||||
}
|
||||
rootsPresentation = StringUtil.surround(rootsPresentation, "\'", "\'");
|
||||
name = "Migrate Type of " + StringUtil.join(rootsPresentation, ", ");
|
||||
if (myRoot.length > MAX_ROOT_IN_PREVIEW_PRESENTATION) {
|
||||
name += "...";
|
||||
}
|
||||
}
|
||||
else if (myRoot[0] instanceof PsiParameter) {
|
||||
text = "parameter \'" + ((PsiParameter)myRoot[0]).getName() + "\'";
|
||||
}
|
||||
else if (myRoot[0] instanceof PsiLocalVariable) {
|
||||
text = "variable \'" + ((PsiLocalVariable)myRoot[0]).getName() + "\'";
|
||||
}
|
||||
else if (myRoot[0] instanceof PsiMethod) {
|
||||
text = "method \'" + ((PsiMethod)myRoot[0]).getName() + "\' return";
|
||||
}
|
||||
else {
|
||||
text = Arrays.toString(myRoot);
|
||||
}
|
||||
String fromType = assertNotNull(TypeMigrationLabeler.getElementType(myRoot[0])).getPresentableText();
|
||||
String toType = myRules.getMigrationRootType().getPresentableText();
|
||||
String name = "Migrate Type of " + text + " from \'" + fromType + "\' to \'" + toType + "\'";
|
||||
Content content = UsageViewManager.getInstance(myProject).addContent(name, false, panel, true, true);
|
||||
panel.setContent(content);
|
||||
ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND).activate(null);
|
||||
}
|
||||
|
||||
public static String getPresentation(PsiElement element) {
|
||||
String text;
|
||||
if (element instanceof PsiField) {
|
||||
text = "field \'" + ((PsiField)element).getName() + "\'";
|
||||
}
|
||||
else if (element instanceof PsiParameter) {
|
||||
text = "parameter \'" + ((PsiParameter)element).getName() + "\'";
|
||||
}
|
||||
else if (element instanceof PsiLocalVariable) {
|
||||
text = "variable \'" + ((PsiLocalVariable)element).getName() + "\'";
|
||||
}
|
||||
else if (element instanceof PsiMethod) {
|
||||
text = "method \'" + ((PsiMethod)element).getName() + "\' return";
|
||||
}
|
||||
else {
|
||||
text = element.getText();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public UsageInfo[] findUsages() {
|
||||
myLabeler = new TypeMigrationLabeler(myRules);
|
||||
myLabeler = new TypeMigrationLabeler(myRules, myRootTypes);
|
||||
|
||||
try {
|
||||
return myLabeler.getMigratedUsages(!isPreviewUsages(), myRoot);
|
||||
@@ -209,6 +247,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
|
||||
public static void change(TypeMigrationLabeler labeler, UsageInfo[] usages) {
|
||||
final List<PsiNewExpression> newExpressionsToCheckDiamonds = new SmartList<PsiNewExpression>();
|
||||
final TypeMigrationLabeler.MigrationProducer producer = labeler.createMigratorFor(usages);
|
||||
|
||||
List<UsageInfo> nonCodeUsages = new ArrayList<UsageInfo>();
|
||||
for (UsageInfo usage : usages) {
|
||||
@@ -218,7 +257,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
element instanceof PsiMember ||
|
||||
element instanceof PsiExpression ||
|
||||
element instanceof PsiReferenceParameterList) {
|
||||
labeler.change((TypeMigrationUsageInfo)usage, new Consumer<PsiNewExpression>() {
|
||||
producer.change((TypeMigrationUsageInfo)usage, new Consumer<PsiNewExpression>() {
|
||||
@Override
|
||||
public void consume(@NotNull PsiNewExpression expression) {
|
||||
newExpressionsToCheckDiamonds.add(expression);
|
||||
@@ -239,7 +278,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
if (element != null) {
|
||||
final PsiReference reference = element.getReference();
|
||||
if (reference != null) {
|
||||
final Object target = labeler.getConversion(element);
|
||||
final Object target = producer.getConversion(usageInfo);
|
||||
if (target instanceof PsiMember) {
|
||||
try {
|
||||
reference.bindToElement((PsiElement)target);
|
||||
|
||||
@@ -39,10 +39,13 @@ public class TypeMigrationReplacementUtil {
|
||||
private TypeMigrationReplacementUtil() {
|
||||
}
|
||||
|
||||
public static PsiElement replaceExpression(PsiExpression expression, final Project project, Object conversion) {
|
||||
public static PsiElement replaceExpression(PsiExpression expression,
|
||||
final Project project,
|
||||
Object conversion,
|
||||
TypeEvaluator typeEvaluator) {
|
||||
if (conversion instanceof TypeConversionDescriptorBase) {
|
||||
try {
|
||||
return ((TypeConversionDescriptorBase)conversion).replace(expression);
|
||||
return ((TypeConversionDescriptorBase)conversion).replace(expression, typeEvaluator);
|
||||
} catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
|
||||
@@ -35,24 +35,16 @@ import java.util.LinkedList;
|
||||
*/
|
||||
public class TypeMigrationRules {
|
||||
private final LinkedList<TypeConversionRule> myConversionRules = new LinkedList<TypeConversionRule>();
|
||||
|
||||
private PsiType myMigrationRootType;
|
||||
private SearchScope mySearchScope;
|
||||
|
||||
private final MigrateGetterNameSetting myMigrateGetterNameSetting = new MigrateGetterNameSetting();
|
||||
|
||||
public TypeMigrationRules() {
|
||||
myConversionRules.add(new RootTypeConversionRule());
|
||||
myConversionRules.add(new DisjunctionTypeConversionRule());
|
||||
ContainerUtil.addAll(myConversionRules, Extensions.getExtensions(TypeConversionRule.EP_NAME));
|
||||
}
|
||||
|
||||
public void setMigrationRootType(PsiType migrationRootType) {
|
||||
myMigrationRootType = migrationRootType;
|
||||
}
|
||||
|
||||
public PsiType getMigrationRootType() {
|
||||
return myMigrationRootType;
|
||||
}
|
||||
|
||||
public void addConversionDescriptor(TypeConversionRule rule) {
|
||||
myConversionRules.add(rule);
|
||||
}
|
||||
@@ -92,6 +84,10 @@ public class TypeMigrationRules {
|
||||
return mySearchScope;
|
||||
}
|
||||
|
||||
public MigrateGetterNameSetting getMigrateGetterNameSetting() {
|
||||
return myMigrateGetterNameSetting;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Pair<PsiType, PsiType> bindTypeParameters(final PsiType from, final PsiType to, final PsiMethod method,
|
||||
final PsiExpression context, final TypeMigrationLabeler labeler) {
|
||||
|
||||
@@ -506,7 +506,10 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
|
||||
case TypeInfection.LEFT_INFECTED:
|
||||
final PsiType valueType = right.getType();
|
||||
if (valueType != null && declarationType != null) {
|
||||
myLabeler.migrateExpressionType(value, declarationType, myStatement, TypeConversionUtil.isAssignable(declarationType, valueType), true);
|
||||
myLabeler.migrateExpressionType(value,
|
||||
adjustMigrationTypeIfGenericArrayCreation(declarationType, value),
|
||||
myStatement,
|
||||
TypeConversionUtil.isAssignable(declarationType, valueType), true);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -515,7 +518,11 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
|
||||
if (psiType != null && declarationType != null &&
|
||||
!myLabeler.addMigrationRoot(variable, psiType, myStatement, TypeConversionUtil.isAssignable(declarationType, psiType), true) &&
|
||||
!TypeConversionUtil.isAssignable(left.getType(), psiType)) {
|
||||
myLabeler.convertExpression(value, psiType, left.getType(), isCovariantPosition);
|
||||
PsiType initialType = left.getType();
|
||||
if (initialType instanceof PsiEllipsisType) {
|
||||
initialType = ((PsiEllipsisType)initialType).getComponentType();
|
||||
}
|
||||
myLabeler.convertExpression(value, psiType, initialType, isCovariantPosition);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -528,6 +535,21 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiType adjustMigrationTypeIfGenericArrayCreation(PsiType migrationType, PsiExpression expression) {
|
||||
if (expression instanceof PsiNewExpression) {
|
||||
if (migrationType instanceof PsiArrayType) {
|
||||
final PsiType componentType = migrationType.getDeepComponentType();
|
||||
if (componentType instanceof PsiClassType) {
|
||||
final PsiClassType rawType = ((PsiClassType)componentType).rawType();
|
||||
if (!rawType.equals(componentType)) {
|
||||
return com.intellij.refactoring.typeCook.Util.createArrayType(rawType, migrationType.getArrayDimensions());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return migrationType;
|
||||
}
|
||||
|
||||
|
||||
private void addTypeUsage(final PsiElement typedElement) {
|
||||
if (typedElement instanceof PsiReferenceExpression) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
|
||||
import com.intellij.refactoring.typeMigration.TypeEvaluator;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.ig.style.UnnecessarilyQualifiedStaticUsageInspection;
|
||||
@@ -64,7 +65,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
|
||||
if (Comparing.equal(functionalInterfaceType, to) && method.isEquivalentTo(LambdaUtil.getFunctionalInterfaceMethod(from))) {
|
||||
return new TypeConversionDescriptorBase() {
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression) throws IncorrectOperationException {
|
||||
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
final PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)expression;
|
||||
final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression();
|
||||
if (qualifierExpression != null) {
|
||||
@@ -139,7 +140,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression) throws IncorrectOperationException {
|
||||
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(expression.getProject());
|
||||
|
||||
@@ -38,7 +38,6 @@ public class MigrationNode extends AbstractTreeNode<TypeMigrationUsageInfo> impl
|
||||
private List<MigrationNode> myCachedChildren;
|
||||
private final TypeMigrationLabeler myLabeler;
|
||||
private final PsiType myMigrationType;
|
||||
private final TypeMigrationTreeBuilder myBuilder;
|
||||
private final HashMap<TypeMigrationUsageInfo, Set<MigrationNode>> myProcessed;
|
||||
private final HashSet<TypeMigrationUsageInfo> myParents;
|
||||
|
||||
@@ -46,13 +45,11 @@ public class MigrationNode extends AbstractTreeNode<TypeMigrationUsageInfo> impl
|
||||
final TypeMigrationUsageInfo info,
|
||||
final PsiType migrationType,
|
||||
final TypeMigrationLabeler labeler,
|
||||
final TypeMigrationTreeBuilder builder,
|
||||
final HashSet<TypeMigrationUsageInfo> parents,
|
||||
final HashMap<TypeMigrationUsageInfo, Set<MigrationNode>> processed) {
|
||||
super(project, info);
|
||||
myLabeler = labeler;
|
||||
myMigrationType = migrationType;
|
||||
myBuilder = builder;
|
||||
myProcessed = processed;
|
||||
myParents = parents;
|
||||
|
||||
@@ -99,7 +96,7 @@ public class MigrationNode extends AbstractTreeNode<TypeMigrationUsageInfo> impl
|
||||
parents.add(info);
|
||||
|
||||
final MigrationNode migrationNode =
|
||||
new MigrationNode(getProject(), info, root.getSecond(), myLabeler, myBuilder, parents, myProcessed);
|
||||
new MigrationNode(getProject(), info, root.getSecond(), myLabeler, parents, myProcessed);
|
||||
|
||||
if (myInfo.isExcluded()) {
|
||||
info.setExcluded(true);
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.typeMigration.ChangeTypeSignatureHandler;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationProcessor;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
|
||||
@@ -68,7 +67,9 @@ import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -79,7 +80,7 @@ public class MigrationPanel extends JPanel implements Disposable {
|
||||
@NonNls private static final String MIGRATION_USAGES = "migration.usages";
|
||||
private static final DataKey<TypeMigrationUsageInfo[]> MIGRATION_USAGES_KEYS = DataKey.create(MIGRATION_USAGES);
|
||||
|
||||
private final PsiElement myInitialRoot;
|
||||
private final PsiElement[] myInitialRoots;
|
||||
private final TypeMigrationLabeler myLabeler;
|
||||
|
||||
|
||||
@@ -89,15 +90,16 @@ public class MigrationPanel extends JPanel implements Disposable {
|
||||
private final MigrationUsagesPanel myUsagesPanel;
|
||||
private final MigrationConflictsPanel myConflictsPanel;
|
||||
|
||||
public MigrationPanel(final PsiElement root, TypeMigrationLabeler labeler, final Project project, final boolean previewUsages) {
|
||||
public MigrationPanel(final PsiElement[] roots, TypeMigrationLabeler labeler, final Project project, final boolean previewUsages) {
|
||||
super(new BorderLayout());
|
||||
myInitialRoot = root;
|
||||
myInitialRoots = roots;
|
||||
myLabeler = labeler;
|
||||
myProject = project;
|
||||
|
||||
myRootsTree = new MyTree(new DefaultTreeModel(new DefaultMutableTreeNode()));
|
||||
final TypeMigrationTreeBuilder builder = new TypeMigrationTreeBuilder(myRootsTree, project);
|
||||
final MigrationRootNode currentRoot = new MigrationRootNode(project, myLabeler, builder, root, previewUsages);
|
||||
|
||||
final MigrationRootNode currentRoot = new MigrationRootNode(project, myLabeler, roots, previewUsages);
|
||||
builder.setRoot(currentRoot);
|
||||
initTree(myRootsTree);
|
||||
myRootsTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||
@@ -254,7 +256,9 @@ public class MigrationPanel extends JPanel implements Disposable {
|
||||
UsageViewManager.getInstance(myProject).closeContent(myContent);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
ChangeTypeSignatureHandler.invoke(myProject, myInitialRoot, myLabeler.getRules(), null);
|
||||
final TypeMigrationDialog.MultipleElements dialog =
|
||||
new TypeMigrationDialog.MultipleElements(myProject, myInitialRoots, myLabeler.getMigrationRootTypeFunction(), myLabeler.getRules());
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,18 +37,16 @@ import java.util.*;
|
||||
public class MigrationRootNode extends AbstractTreeNode<TypeMigrationLabeler> implements DuplicateNodeRenderer.DuplicatableNode {
|
||||
private final TypeMigrationLabeler myLabeler;
|
||||
private List<MigrationNode> myCachedChildren;
|
||||
private final TypeMigrationTreeBuilder myBuilder;
|
||||
private final PsiElement myRoot;
|
||||
private final PsiElement myRoots[];
|
||||
private final boolean myPreviewUsages;
|
||||
|
||||
protected MigrationRootNode(Project project,
|
||||
TypeMigrationLabeler labeler,
|
||||
final TypeMigrationTreeBuilder builder, final PsiElement root,
|
||||
final PsiElement[] roots,
|
||||
final boolean previewUsages) {
|
||||
super(project, labeler);
|
||||
myLabeler = labeler;
|
||||
myBuilder = builder;
|
||||
myRoot = root;
|
||||
myRoots = roots;
|
||||
myPreviewUsages = previewUsages;
|
||||
}
|
||||
|
||||
@@ -62,7 +60,9 @@ public class MigrationRootNode extends AbstractTreeNode<TypeMigrationLabeler> im
|
||||
}
|
||||
}
|
||||
else {
|
||||
addRoot(new TypeMigrationUsageInfo(myRoot), myLabeler.getRules().getMigrationRootType());
|
||||
for (PsiElement root : myRoots) {
|
||||
addRoot(new TypeMigrationUsageInfo(root), myLabeler.getMigrationRootTypeFunction().fun(root));
|
||||
}
|
||||
}
|
||||
}
|
||||
return myCachedChildren;
|
||||
@@ -72,7 +72,7 @@ public class MigrationRootNode extends AbstractTreeNode<TypeMigrationLabeler> im
|
||||
final HashSet<TypeMigrationUsageInfo> parents = new HashSet<TypeMigrationUsageInfo>();
|
||||
parents.add(info);
|
||||
final MigrationNode migrationNode =
|
||||
new MigrationNode(getProject(), info, migrationType, myLabeler, myBuilder, parents, new HashMap<TypeMigrationUsageInfo, Set<MigrationNode>>());
|
||||
new MigrationNode(getProject(), info, migrationType, myLabeler, parents, new HashMap<TypeMigrationUsageInfo, Set<MigrationNode>>());
|
||||
|
||||
myCachedChildren.add(migrationNode);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ import com.intellij.refactoring.typeMigration.TypeMigrationRules;
|
||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.ui.EditorComboBox;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Functions;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -56,52 +58,22 @@ import java.util.List;
|
||||
* @author anna
|
||||
* Date: 25-Mar-2008
|
||||
*/
|
||||
public class TypeMigrationDialog extends RefactoringDialog {
|
||||
public abstract class TypeMigrationDialog extends RefactoringDialog {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.typeMigration.ui.TypeMigrationDialog");
|
||||
|
||||
public static final String REFACTORING_NAME = "Type Migration";
|
||||
|
||||
private final EditorComboBox myToTypeEditor;
|
||||
private final PsiElement myRoot;
|
||||
protected final PsiElement[] myRoots;
|
||||
private TypeMigrationRules myRules;
|
||||
private final PsiTypeCodeFragment myTypeCodeFragment;
|
||||
private final ScopeChooserCombo myScopeChooserCombo;
|
||||
|
||||
public TypeMigrationDialog(@NotNull Project project, PsiElement root, TypeMigrationRules rules) {
|
||||
public TypeMigrationDialog(@NotNull Project project,
|
||||
PsiElement roots[],
|
||||
TypeMigrationRules rules) {
|
||||
super(project, false);
|
||||
myRoot = root;
|
||||
myRoots = roots;
|
||||
myRules = rules;
|
||||
|
||||
final PsiType migrationRootType = rules != null ? rules.getMigrationRootType() : null;
|
||||
final PsiType rootType = getRootType();
|
||||
final String text = migrationRootType != null ? migrationRootType.getCanonicalText(true) :
|
||||
rootType != null ? rootType.getCanonicalText(true) : "";
|
||||
int flags = 0;
|
||||
if (root instanceof PsiParameter) {
|
||||
final PsiElement scope = ((PsiParameter)root).getDeclarationScope();
|
||||
if (scope instanceof PsiMethod) {
|
||||
flags |= JavaCodeFragmentFactory.ALLOW_ELLIPSIS;
|
||||
}
|
||||
else if (scope instanceof PsiCatchSection && PsiUtil.getLanguageLevel(root).isAtLeast(LanguageLevel.JDK_1_7)) {
|
||||
flags |= JavaCodeFragmentFactory.ALLOW_DISJUNCTION;
|
||||
}
|
||||
}
|
||||
myTypeCodeFragment = JavaCodeFragmentFactory.getInstance(project).createTypeCodeFragment(text, root, true, flags);
|
||||
|
||||
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
final Document document = documentManager.getDocument(myTypeCodeFragment);
|
||||
assert document != null;
|
||||
myToTypeEditor = new EditorComboBox(document, project, StdFileTypes.JAVA);
|
||||
final String[] types = getValidTypes(project, root);
|
||||
myToTypeEditor.setHistory(types != null ? types : new String[]{document.getText()});
|
||||
document.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
public void documentChanged(final DocumentEvent e) {
|
||||
documentManager.commitDocument(document);
|
||||
validateButtons();
|
||||
}
|
||||
});
|
||||
|
||||
myScopeChooserCombo = new ScopeChooserCombo(project, false, true, FindSettings.getInstance().getDefaultScopeName());
|
||||
Disposer.register(myDisposable, myScopeChooserCombo);
|
||||
myScopeChooserCombo.getChildComponent().addActionListener(new ActionListener() {
|
||||
@@ -109,115 +81,29 @@ public class TypeMigrationDialog extends RefactoringDialog {
|
||||
validateButtons();
|
||||
}
|
||||
});
|
||||
init();
|
||||
setTitle(REFACTORING_NAME);
|
||||
}
|
||||
|
||||
public PsiElement getRoot() {
|
||||
return myRoot;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiType getMigrationType() {
|
||||
try {
|
||||
return myTypeCodeFragment.getType();
|
||||
}
|
||||
catch (PsiTypeCodeFragment.TypeSyntaxException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
catch (PsiTypeCodeFragment.NoTypeException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String[] getValidTypes(final Project project, final PsiElement root) {
|
||||
if (root instanceof PsiField || root instanceof PsiMethod) {
|
||||
final PsiModifierList modifierList = ((PsiModifierListOwner)root).getModifierList();
|
||||
if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(modifierList), PsiModifier.PRIVATE) < 0) return null;
|
||||
}
|
||||
|
||||
final List<PsiExpression> expressions = new ArrayList<PsiExpression>();
|
||||
for (PsiReference reference : ReferencesSearch.search(root, GlobalSearchScope.fileScope(root.getContainingFile()))) {
|
||||
final PsiElement element = reference.getElement();
|
||||
final PsiExpression expr = PsiTreeUtil.getParentOfType(element, PsiExpression.class, false);
|
||||
if (expr != null) {
|
||||
expressions.add(expr);
|
||||
}
|
||||
}
|
||||
try {
|
||||
final PsiExpression[] occurrences = expressions.toArray(new PsiExpression[expressions.size()]);
|
||||
final PsiType[] psiTypes = new TypeSelectorManagerImpl(project, myTypeCodeFragment.getType(), occurrences).getTypesForAll();
|
||||
if (psiTypes.length > 0) {
|
||||
final String[] history = new String[psiTypes.length];
|
||||
for (int i = 0; i < psiTypes.length; i++) {
|
||||
PsiType psiType = psiTypes[i];
|
||||
history[i] = psiType.getCanonicalText(true);
|
||||
}
|
||||
return history;
|
||||
}
|
||||
}
|
||||
catch (PsiTypeCodeFragment.TypeSyntaxException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
catch (PsiTypeCodeFragment.NoTypeException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void canRun() throws ConfigurationException {
|
||||
if (!checkType(getMigrationType())) throw new ConfigurationException("\'" + myTypeCodeFragment.getText() + "\' is invalid type");
|
||||
if (myScopeChooserCombo.getSelectedScope() == null) throw new ConfigurationException("Scope is not chosen");
|
||||
}
|
||||
|
||||
private static boolean checkType(final PsiType type) {
|
||||
if (type == null) return false;
|
||||
if (!type.isValid()) return false;
|
||||
if (type instanceof PsiClassType){
|
||||
final PsiClassType psiClassType = (PsiClassType)type;
|
||||
if (psiClassType.resolve() == null) return false;
|
||||
final PsiType[] types = psiClassType.getParameters();
|
||||
for (PsiType paramType : types) {
|
||||
if (paramType instanceof PsiPrimitiveType ||
|
||||
(paramType instanceof PsiWildcardType && ((PsiWildcardType)paramType).getBound() instanceof PsiPrimitiveType)) return false;
|
||||
if (!checkType(paramType)) return false;
|
||||
}
|
||||
}
|
||||
if (type instanceof PsiArrayType) {
|
||||
return checkType(type.getDeepComponentType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction() {
|
||||
FindSettings.getInstance().setDefaultScopeName(myScopeChooserCombo.getSelectedScopeName());
|
||||
|
||||
final PsiType rootType = getRootType();
|
||||
final PsiType migrationType = getMigrationType();
|
||||
|
||||
if (migrationType == null || ChangeSignatureUtil.deepTypeEqual(rootType, migrationType)) {
|
||||
close(DialogWrapper.OK_EXIT_CODE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (myRules == null) {
|
||||
myRules = new TypeMigrationRules();
|
||||
myRules.setMigrationRootType(migrationType);
|
||||
myRules.setBoundScope(myScopeChooserCombo.getSelectedScope());
|
||||
}
|
||||
invokeRefactoring(new TypeMigrationProcessor(myProject, myRoot, myRules));
|
||||
invokeRefactoring(new TypeMigrationProcessor(myProject, myRoots, getMigrationTypeFunction(), myRules));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiType getRootType() {
|
||||
return TypeMigrationLabeler.getElementType(myRoot);
|
||||
@NotNull
|
||||
protected abstract Function<PsiElement, PsiType> getMigrationTypeFunction();
|
||||
|
||||
protected void appendMigrationTypeEditor(JPanel panel, GridBagConstraints cs) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -225,11 +111,7 @@ public class TypeMigrationDialog extends RefactoringDialog {
|
||||
final JPanel panel = new JPanel(new GridBagLayout());
|
||||
final GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 0, GridBagConstraints.NORTHWEST,
|
||||
GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0);
|
||||
final PsiType type = getRootType();
|
||||
final String typeText = type != null ? type.getPresentableText() : "<unknown>";
|
||||
panel.add(new JLabel("Migrate " + getElementPresentation(myRoot) + " \"" + typeText + "\" to"), gc);
|
||||
panel.add(myToTypeEditor, gc);
|
||||
|
||||
appendMigrationTypeEditor(panel, gc);
|
||||
LabeledComponent<ScopeChooserCombo> scopeChooserComponent = new LabeledComponent<ScopeChooserCombo>();
|
||||
scopeChooserComponent.setComponent(myScopeChooserCombo);
|
||||
scopeChooserComponent.setText("Choose scope where change signature may occur");
|
||||
@@ -239,42 +121,215 @@ public class TypeMigrationDialog extends RefactoringDialog {
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myToTypeEditor;
|
||||
}
|
||||
|
||||
private static String getElementPresentation(PsiElement element) {
|
||||
if (element instanceof PsiMethod) {
|
||||
return "return type of method " + ((PsiMethod)element).getName();
|
||||
}
|
||||
|
||||
if (element instanceof PsiField) {
|
||||
return "type of field " + ((PsiField)element).getName();
|
||||
}
|
||||
|
||||
if (element instanceof PsiLocalVariable) {
|
||||
return "type of variable " + ((PsiLocalVariable)element).getName();
|
||||
}
|
||||
|
||||
if (element instanceof PsiReferenceParameterList) {
|
||||
return "class type arguments ";
|
||||
}
|
||||
|
||||
if (element instanceof PsiParameter) {
|
||||
final PsiParameter param = (PsiParameter)element;
|
||||
String result = "type of parameter " + param.getName();
|
||||
if (param.getParent() instanceof PsiParameterList) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(param, PsiMethod.class);
|
||||
assert method != null;
|
||||
result += " of method " + method.getName();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return element.toString();
|
||||
return myScopeChooserCombo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHelpAction() {
|
||||
HelpManager.getInstance().invokeHelp("reference.typeMigrationDialog");
|
||||
}
|
||||
|
||||
public static class MultipleElements extends TypeMigrationDialog {
|
||||
private final Function<PsiElement, PsiType> myMigrationTypeFunction;
|
||||
|
||||
public MultipleElements(@NotNull Project project, PsiElement[] roots, Function<PsiElement, PsiType> migrationTypeFunction, TypeMigrationRules rules) {
|
||||
super(project, roots, rules);
|
||||
myMigrationTypeFunction = migrationTypeFunction;
|
||||
init();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Function<PsiElement, PsiType> getMigrationTypeFunction() {
|
||||
return myMigrationTypeFunction;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SingleElement extends TypeMigrationDialog {
|
||||
private final PsiTypeCodeFragment myTypeCodeFragment;
|
||||
private final EditorComboBox myToTypeEditor;
|
||||
|
||||
public SingleElement(@NotNull Project project,
|
||||
PsiElement root,
|
||||
PsiType migrationType,
|
||||
TypeMigrationRules rules) {
|
||||
super(project, new PsiElement[]{root}, rules);
|
||||
final PsiType rootType = getRootType();
|
||||
final String text = migrationType != null ? migrationType.getCanonicalText(true) :
|
||||
rootType != null ? rootType.getCanonicalText(true) : "";
|
||||
int flags = 0;
|
||||
if (root instanceof PsiParameter) {
|
||||
final PsiElement scope = ((PsiParameter)root).getDeclarationScope();
|
||||
if (scope instanceof PsiMethod) {
|
||||
flags |= JavaCodeFragmentFactory.ALLOW_ELLIPSIS;
|
||||
}
|
||||
else if (scope instanceof PsiCatchSection && PsiUtil.getLanguageLevel(root).isAtLeast(LanguageLevel.JDK_1_7)) {
|
||||
flags |= JavaCodeFragmentFactory.ALLOW_DISJUNCTION;
|
||||
}
|
||||
}
|
||||
myTypeCodeFragment = JavaCodeFragmentFactory.getInstance(project).createTypeCodeFragment(text, root, true, flags);
|
||||
|
||||
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
final Document document = documentManager.getDocument(myTypeCodeFragment);
|
||||
assert document != null;
|
||||
myToTypeEditor = new EditorComboBox(document, project, StdFileTypes.JAVA);
|
||||
final String[] types = getValidTypes(project, root);
|
||||
myToTypeEditor.setHistory(types != null ? types : new String[]{document.getText()});
|
||||
document.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
public void documentChanged(final DocumentEvent e) {
|
||||
documentManager.commitDocument(document);
|
||||
validateButtons();
|
||||
}
|
||||
});
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void canRun() throws ConfigurationException {
|
||||
super.canRun();
|
||||
if (!checkType(getMigrationType())) throw new ConfigurationException("\'" + myTypeCodeFragment.getText() + "\' is invalid type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myToTypeEditor;
|
||||
}
|
||||
|
||||
protected void appendMigrationTypeEditor(JPanel panel, GridBagConstraints gc) {
|
||||
final PsiType type = getRootType();
|
||||
final String typeText = type != null ? type.getPresentableText() : "<unknown>";
|
||||
panel.add(new JLabel("Migrate " + getElementPresentation(myRoots[0]) + " \"" + typeText + "\" to"), gc);
|
||||
panel.add(myToTypeEditor, gc);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String[] getValidTypes(final Project project, final PsiElement root) {
|
||||
if (root instanceof PsiField || root instanceof PsiMethod) {
|
||||
final PsiModifierList modifierList = ((PsiModifierListOwner)root).getModifierList();
|
||||
if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(modifierList), PsiModifier.PRIVATE) < 0) return null;
|
||||
}
|
||||
|
||||
final List<PsiExpression> expressions = new ArrayList<PsiExpression>();
|
||||
for (PsiReference reference : ReferencesSearch.search(root, GlobalSearchScope.fileScope(root.getContainingFile()))) {
|
||||
final PsiElement element = reference.getElement();
|
||||
final PsiExpression expr = PsiTreeUtil.getParentOfType(element, PsiExpression.class, false);
|
||||
if (expr != null) {
|
||||
expressions.add(expr);
|
||||
}
|
||||
}
|
||||
try {
|
||||
final PsiExpression[] occurrences = expressions.toArray(new PsiExpression[expressions.size()]);
|
||||
final PsiType[] psiTypes = new TypeSelectorManagerImpl(project, myTypeCodeFragment.getType(), occurrences).getTypesForAll();
|
||||
if (psiTypes.length > 0) {
|
||||
final String[] history = new String[psiTypes.length];
|
||||
for (int i = 0; i < psiTypes.length; i++) {
|
||||
PsiType psiType = psiTypes[i];
|
||||
history[i] = psiType.getCanonicalText(true);
|
||||
}
|
||||
return history;
|
||||
}
|
||||
}
|
||||
catch (PsiTypeCodeFragment.TypeSyntaxException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
catch (PsiTypeCodeFragment.NoTypeException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction() {
|
||||
final PsiType rootType = getRootType();
|
||||
final PsiType migrationType = getMigrationType();
|
||||
if (migrationType == null || ChangeSignatureUtil.deepTypeEqual(rootType, migrationType)) {
|
||||
close(DialogWrapper.OK_EXIT_CODE);
|
||||
return;
|
||||
}
|
||||
super.doAction();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Function<PsiElement, PsiType> getMigrationTypeFunction() {
|
||||
return Functions.constant(getMigrationType());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiType getMigrationType() {
|
||||
try {
|
||||
return myTypeCodeFragment.getType();
|
||||
}
|
||||
catch (PsiTypeCodeFragment.TypeSyntaxException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
catch (PsiTypeCodeFragment.NoTypeException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiType getRootType() {
|
||||
return TypeMigrationLabeler.getElementType(myRoots[0]);
|
||||
}
|
||||
|
||||
private static String getElementPresentation(PsiElement element) {
|
||||
if (element instanceof PsiMethod) {
|
||||
return "return type of method " + ((PsiMethod)element).getName();
|
||||
}
|
||||
|
||||
if (element instanceof PsiField) {
|
||||
return "type of field " + ((PsiField)element).getName();
|
||||
}
|
||||
|
||||
if (element instanceof PsiLocalVariable) {
|
||||
return "type of variable " + ((PsiLocalVariable)element).getName();
|
||||
}
|
||||
|
||||
if (element instanceof PsiReferenceParameterList) {
|
||||
return "class type arguments ";
|
||||
}
|
||||
|
||||
if (element instanceof PsiParameter) {
|
||||
final PsiParameter param = (PsiParameter)element;
|
||||
String result = "type of parameter " + param.getName();
|
||||
if (param.getParent() instanceof PsiParameterList) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(param, PsiMethod.class);
|
||||
assert method != null;
|
||||
result += " of method " + method.getName();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return element.toString();
|
||||
}
|
||||
private static boolean checkType(final PsiType type) {
|
||||
if (type == null) return false;
|
||||
if (!type.isValid()) return false;
|
||||
if (type instanceof PsiClassType){
|
||||
final PsiClassType psiClassType = (PsiClassType)type;
|
||||
if (psiClassType.resolve() == null) return false;
|
||||
final PsiType[] types = psiClassType.getParameters();
|
||||
for (PsiType paramType : types) {
|
||||
if (paramType instanceof PsiPrimitiveType ||
|
||||
(paramType instanceof PsiWildcardType && ((PsiWildcardType)paramType).getBound() instanceof PsiPrimitiveType)) {
|
||||
return false;
|
||||
}
|
||||
if (!checkType(paramType)) return false;
|
||||
}
|
||||
}
|
||||
if (type instanceof PsiArrayType) {
|
||||
return checkType(type.getDeepComponentType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author anna
|
||||
@@ -38,6 +39,6 @@ public class TypeMigrationTreeBuilder extends AbstractTreeBuilder{
|
||||
}
|
||||
|
||||
public void setRoot(MigrationRootNode root) {
|
||||
((TypeMigrationTreeStructure)getTreeStructure()).setRoot(root);
|
||||
((TypeMigrationTreeStructure)getTreeStructure()).setRoots(root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,14 @@
|
||||
*/
|
||||
package com.intellij.refactoring.typeMigration.ui;
|
||||
|
||||
import com.intellij.ide.projectView.PresentationData;
|
||||
import com.intellij.ide.projectView.TreeStructureProvider;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeStructureBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -33,7 +37,7 @@ public class TypeMigrationTreeStructure extends AbstractTreeStructureBase {
|
||||
super(project);
|
||||
}
|
||||
|
||||
public void setRoot(final MigrationRootNode root) {
|
||||
public void setRoots(final MigrationRootNode root) {
|
||||
myRoot = root;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,17 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Date: 27-Mar-2008
|
||||
*/
|
||||
public class OverridenUsageInfo extends TypeMigrationUsageInfo {
|
||||
private OverriderUsageInfo[] myOverriders;
|
||||
private volatile String myMigrateMethodName;
|
||||
|
||||
public OverridenUsageInfo(@NotNull PsiElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
public OverriderUsageInfo[] getOverridingElements() {
|
||||
return myOverriders;
|
||||
public String getMigrateMethodName() {
|
||||
return myMigrateMethodName;
|
||||
}
|
||||
|
||||
public void setOverriders(final OverriderUsageInfo[] overriders) {
|
||||
myOverriders = overriders;
|
||||
public void setMigrateMethodName(String migrateMethodName) {
|
||||
myMigrateMethodName = migrateMethodName;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.util;
|
||||
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -256,4 +257,18 @@ public class ClassUtil {
|
||||
public static PsiClass findPsiClassByJVMName(@NotNull PsiManager manager, @NotNull String jvmClassName) {
|
||||
return findPsiClass(manager, jvmClassName.replace('/', '.'), null, true);
|
||||
}
|
||||
|
||||
public static boolean isTopLevelClass(@NotNull PsiClass aClass) {
|
||||
if (aClass.getContainingClass() != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aClass instanceof PsiAnonymousClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiFile parentFile = aClass.getContainingFile();
|
||||
// do not select JspClass
|
||||
return parentFile != null && parentFile.getLanguage() == JavaLanguage.INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -298,18 +298,32 @@ public class MethodSignatureUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* * 8.4.4 Generic Methods :: same type parameters condition
|
||||
* Two methods or constructors M and N have the same type parameters if both of the following are true:
|
||||
* • M and N have same number of type parameters (possibly zero).
|
||||
* • Where A1, ..., An are the type parameters of M and B1, ..., Bn are the type parameters of N, let θ=[B1:=A1, ..., Bn:=An].
|
||||
* Then, for all i (1 ≤ i ≤ n), the bound of Ai is the same type as θ applied to the bound of Bi.
|
||||
*
|
||||
* @param methodSignature method signature
|
||||
* @param superMethodSignature super method signature
|
||||
* @return null if signatures do not match
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiSubstitutor getSuperMethodSignatureSubstitutor(@NotNull MethodSignature methodSignature, @NotNull MethodSignature superMethodSignature) {
|
||||
PsiSubstitutor result = getSuperMethodSignatureSubstitutorImpl(methodSignature, superMethodSignature);
|
||||
if (result == null) return null;
|
||||
|
||||
PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters();
|
||||
PsiTypeParameter[] superTypeParameters = superMethodSignature.getTypeParameters();
|
||||
PsiSubstitutor methodSubstitutor = methodSignature.getSubstitutor();
|
||||
|
||||
// both methods are parameterized and number of parameters mismatch
|
||||
if (methodTypeParameters.length != superTypeParameters.length) return null;
|
||||
|
||||
PsiSubstitutor result = superMethodSignature.getSubstitutor();
|
||||
for (int i = 0; i < methodTypeParameters.length; i++) {
|
||||
PsiTypeParameter methodTypeParameter = methodTypeParameters[i];
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(methodTypeParameter.getProject()).getElementFactory();
|
||||
result = result.put(superTypeParameters[i], factory.createType(methodTypeParameter));
|
||||
}
|
||||
|
||||
final PsiSubstitutor methodSubstitutor = methodSignature.getSubstitutor();
|
||||
|
||||
//check bounds
|
||||
for (int i = 0; i < methodTypeParameters.length; i++) {
|
||||
@@ -332,26 +346,6 @@ public class MethodSignatureUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl(@NotNull MethodSignature methodSignature, @NotNull MethodSignature superSignature) {
|
||||
// normalize generic method declarations: correlate type parameters
|
||||
// todo: correlate type params by name?
|
||||
PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters();
|
||||
PsiTypeParameter[] superTypeParameters = superSignature.getTypeParameters();
|
||||
|
||||
// both methods are parameterized and number of parameters mismatch
|
||||
if (methodTypeParameters.length != superTypeParameters.length) return null;
|
||||
|
||||
PsiSubstitutor result = superSignature.getSubstitutor();
|
||||
for (int i = 0; i < methodTypeParameters.length; i++) {
|
||||
PsiTypeParameter methodTypeParameter = methodTypeParameters[i];
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(methodTypeParameter.getProject()).getElementFactory();
|
||||
result = result.put(superTypeParameters[i], factory.createType(methodTypeParameter));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiSubstitutor combineSubstitutors(@NotNull PsiSubstitutor substitutor1, @NotNull PsiSubstitutor substitutor2) {
|
||||
if (substitutor1 == PsiSubstitutor.EMPTY) return substitutor2;
|
||||
@@ -398,4 +392,36 @@ public class MethodSignatureUtil {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 8.4.5 Method Result :: return type substitutable
|
||||
*/
|
||||
public static boolean isReturnTypeSubstitutable(MethodSignature d1, MethodSignature d2, PsiType r1, PsiType r2) {
|
||||
//If R1 is void then R2 is void.
|
||||
if (PsiType.VOID.equals(r1)) {
|
||||
return PsiType.VOID.equals(r2);
|
||||
}
|
||||
|
||||
//If R1 is a primitive type then R2 is identical to R1.
|
||||
if (r1 instanceof PsiPrimitiveType) {
|
||||
return r1.equals(r2);
|
||||
}
|
||||
|
||||
if (r1 instanceof PsiClassType && r2 != null) {
|
||||
|
||||
//R1, adapted to the type parameters of d2 (§8.4.4), is a subtype of R2.
|
||||
final PsiSubstitutor adaptingSubstitutor = getSuperMethodSignatureSubstitutor(d1, d2);
|
||||
if (adaptingSubstitutor != null && r2.isAssignableFrom(adaptingSubstitutor.substitute(r1))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//d1 does not have the same signature as d2 (§8.4.2), and R1 = |R2|.
|
||||
if (!areSignaturesEqual(d1, d2)) {
|
||||
return r1.equals(TypeConversionUtil.erasure(r2));
|
||||
}
|
||||
}
|
||||
|
||||
return Comparing.equal(r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,9 @@ public class TypeConversionUtil {
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_7)) {
|
||||
final PsiClassType classType = (PsiClassType)fromType;
|
||||
final PsiClass psiClass = classType.resolve();
|
||||
if (psiClass == null || psiClass instanceof PsiTypeParameter) return false;
|
||||
if (psiClass == null) return false;
|
||||
final PsiClassType boxedType = ((PsiPrimitiveType)toType).getBoxedType(psiClass.getManager(), psiClass.getResolveScope());
|
||||
if (boxedType != null && isAssignable(fromType, boxedType)) {
|
||||
if (boxedType != null && isNarrowingReferenceConversionAllowed(fromType, boxedType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
|
||||
@@ -31,6 +31,8 @@ import com.intellij.psi.util.*;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.containers.hash.EqualityPolicy;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
@@ -135,7 +137,37 @@ public class PsiSuperMethodImplUtil {
|
||||
boolean isInRawContext,
|
||||
GlobalSearchScope resolveScope) {
|
||||
ProgressManager.checkCanceled();
|
||||
Map<MethodSignature, HierarchicalMethodSignature> result = new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>();
|
||||
Map<MethodSignature, HierarchicalMethodSignature> result = new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>(
|
||||
new EqualityPolicy<MethodSignature>() {
|
||||
@Override
|
||||
public int getHashCode(MethodSignature object) {
|
||||
return object.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(MethodSignature o1, MethodSignature o2) {
|
||||
if (o1.equals(o2)) {
|
||||
final PsiMethod method1 = ((MethodSignatureBackedByPsiMethod)o1).getMethod();
|
||||
final PsiType returnType1 = method1.getReturnType();
|
||||
final PsiMethod method2 = ((MethodSignatureBackedByPsiMethod)o2).getMethod();
|
||||
final PsiType returnType2 = method2.getReturnType();
|
||||
if (method1.hasModifierProperty(PsiModifier.STATIC) || method2.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (MethodSignatureUtil.isReturnTypeSubstitutable(o1, o2, returnType1, returnType2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final PsiClass containingClass1 = method1.getContainingClass();
|
||||
final PsiClass containingClass2 = method2.getContainingClass();
|
||||
if (containingClass1 != null && containingClass2 != null) {
|
||||
return containingClass1.isAnnotationType() || containingClass2.isAnnotationType();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
final Map<MethodSignature, List<PsiMethod>> sameParameterErasureMethods = new THashMap<MethodSignature, List<PsiMethod>>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
|
||||
|
||||
Map<MethodSignature, HierarchicalMethodSignatureImpl> map = new THashMap<MethodSignature, HierarchicalMethodSignatureImpl>(new TObjectHashingStrategy<MethodSignature>() {
|
||||
@@ -443,4 +475,4 @@ public class PsiSuperMethodImplUtil {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
}
|
||||
}
|
||||
final PsiElement element = resolve.getElement();
|
||||
if (element == null) {
|
||||
if (element == null || resolve instanceof MethodCandidateInfo && !((MethodCandidateInfo)resolve).isApplicable()) {
|
||||
session.registerIncompatibleErrorMessage("No compile-time declaration for the method reference is found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,15 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
}
|
||||
return session.infer(method.getParameterList().getParameters(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
if (signature == null) return false;
|
||||
final PsiType[] argTypes = signature.getParameterTypes();
|
||||
boolean hasReceiver = PsiMethodReferenceUtil.isSecondSearchPossible(argTypes, qualifierResolveResult, reference);
|
||||
|
||||
return MethodReferenceConflictResolver.isApplicableByFirstSearch(this, argTypes, hasReceiver, interfaceMethod.isVarArgs()) != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -211,8 +220,14 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
protected CandidateInfo guardedOverloadResolution(@NotNull List<CandidateInfo> conflicts) {
|
||||
if (mySignature == null) return null;
|
||||
|
||||
if (conflicts.size() > 1) checkSameSignatures(conflicts);
|
||||
if (conflicts.size() > 1) checkAccessStaticLevels(conflicts, true);
|
||||
if (conflicts.isEmpty()) return null;
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
checkSameSignatures(conflicts);
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
checkAccessStaticLevels(conflicts, true);
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
final PsiType[] argTypes = mySignature.getParameterTypes();
|
||||
boolean hasReceiver = PsiMethodReferenceUtil.isSecondSearchPossible(argTypes, myQualifierResolveResult, myReferenceExpression);
|
||||
@@ -222,23 +237,9 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
|
||||
for (CandidateInfo conflict : conflicts) {
|
||||
if (!(conflict instanceof MethodCandidateInfo)) continue;
|
||||
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
|
||||
|
||||
final PsiSubstitutor substitutor = ((MethodCandidateInfo)conflict).getSubstitutor(false);
|
||||
final PsiType[] parameterTypes = psiMethod.getSignature(substitutor).getParameterTypes();
|
||||
|
||||
final boolean varargs = ((MethodCandidateInfo)conflict).isVarargs();
|
||||
if (varargs && (!psiMethod.isVarArgs() || myFunctionalMethodVarArgs)) continue;
|
||||
|
||||
if ((varargs || argTypes.length == parameterTypes.length) &&
|
||||
PsiMethodReferenceUtil.isCorrectAssignment(parameterTypes, argTypes, varargs, 0)) {
|
||||
firstCandidates.add(conflict);
|
||||
}
|
||||
|
||||
if (hasReceiver &&
|
||||
(varargs || argTypes.length == parameterTypes.length + 1) &&
|
||||
PsiMethodReferenceUtil.isCorrectAssignment(parameterTypes, argTypes, varargs, 1)) {
|
||||
secondCandidates.add(conflict);
|
||||
final Boolean applicableByFirstSearch = isApplicableByFirstSearch(conflict, argTypes, hasReceiver, myFunctionalMethodVarArgs);
|
||||
if (applicableByFirstSearch != null) {
|
||||
(applicableByFirstSearch ? firstCandidates : secondCandidates).add(conflict);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,12 +265,42 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0);
|
||||
}
|
||||
|
||||
if (firstCandidates.isEmpty() && secondCandidates.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
conflicts.clear();
|
||||
firstCandidates.addAll(secondCandidates);
|
||||
conflicts.addAll(firstCandidates);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Boolean isApplicableByFirstSearch(CandidateInfo conflict, PsiType[] argTypes,
|
||||
boolean hasReceiver,
|
||||
boolean functionalMethodVarArgs) {
|
||||
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
|
||||
|
||||
final PsiSubstitutor substitutor = ((MethodCandidateInfo)conflict).getSubstitutor(false);
|
||||
final PsiType[] parameterTypes = psiMethod.getSignature(substitutor).getParameterTypes();
|
||||
|
||||
final boolean varargs = ((MethodCandidateInfo)conflict).isVarargs();
|
||||
if (varargs && (!psiMethod.isVarArgs() || functionalMethodVarArgs)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((varargs || argTypes.length == parameterTypes.length) &&
|
||||
PsiMethodReferenceUtil.isCorrectAssignment(parameterTypes, argTypes, varargs, 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasReceiver &&
|
||||
(varargs || argTypes.length == parameterTypes.length + 1) &&
|
||||
PsiMethodReferenceUtil.isCorrectAssignment(parameterTypes, argTypes, varargs, 1)) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean resolveConflicts(List<CandidateInfo> firstCandidates, List<CandidateInfo> secondCandidates, int applicabilityLevel) {
|
||||
|
||||
final int firstApplicability = checkApplicability(firstCandidates);
|
||||
|
||||
@@ -450,6 +450,10 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
map.remove(this);
|
||||
}
|
||||
|
||||
if (result instanceof MethodCandidateInfo && !((MethodCandidateInfo)result).isApplicable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiElement resolve = result.getElement();
|
||||
if (resolve == null) {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
class Test {
|
||||
public <T> void foo(T valIn){
|
||||
double val = (double ) valIn;
|
||||
}
|
||||
|
||||
public <T extends Double> void foo1(T valIn){
|
||||
double val = (double ) valIn;
|
||||
}
|
||||
|
||||
public <T extends String> void foo2(T valIn){
|
||||
double val = <error descr="Inconvertible types; cannot cast 'T' to 'double'">(double ) valIn</error>;
|
||||
}
|
||||
|
||||
public <T extends S, S extends Double> void foo2(T valIn){
|
||||
double val = (double ) valIn;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo<T> {
|
||||
|
||||
private T _value;
|
||||
|
||||
T getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
static Foo<?> getFoo() {
|
||||
return new Foo<>();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Foo<?> foo = getFoo();
|
||||
double value = (double) foo.getValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
interface I<T, S extends Throwable> {
|
||||
int foo(T x);
|
||||
void foo(S x);
|
||||
}
|
||||
|
||||
class A implements I<Throwable, Throwable>{
|
||||
public <error descr="'foo(Throwable)' in 'A' clashes with 'foo(T)' in 'I'; attempting to use incompatible return type">void</error> foo(Throwable x) { }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
class Foo<T> {
|
||||
|
||||
private T _value;
|
||||
|
||||
T getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
static Foo<?> getFoo() {
|
||||
return new Foo<>();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Foo<?> foo = getFoo();
|
||||
double value = <error descr="Inconvertible types; cannot cast 'capture<?>' to 'double'">(double) foo.getValue()</error>;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ class AlienTest {
|
||||
|
||||
static {
|
||||
IInt i1 = MyTest::<error descr="Cannot resolve method 'abracadabra'">abracadabra</error>;
|
||||
IInt i2 = MyTest::<error descr="Cannot resolve method 'foo'">foo</error>;
|
||||
IInt i2 = <error descr="Bad return type in method reference: cannot convert void to int">MyTest::foo</error>;
|
||||
IInt i3 = MyTest::<error descr="Cannot resolve method 'bar'">bar</error>;
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IIntInt'">IIntInt i4 = MyTest::bar;</error>
|
||||
IInt i5 = <error descr="Non-static method cannot be referenced from a static context">MyTest::baz</error>;
|
||||
|
||||
@@ -70,8 +70,8 @@ class MyTest3<X> {
|
||||
static void test(I<Integer> s) { }
|
||||
|
||||
public static void main(String[] args) {
|
||||
I<Integer> s = MyTest3<String>::<error descr="Cannot resolve constructor 'MyTest3'">new</error>;
|
||||
test(MyTest3<String>::<error descr="Cannot resolve constructor 'MyTest3'">new</error>);
|
||||
I<Integer> s = <error descr="Bad return type in method reference: cannot convert MyTest3<java.lang.String> to MyTest3<java.lang.Integer>">MyTest3<String>::new</error>;
|
||||
test(<error descr="Bad return type in method reference: cannot convert MyTest3<java.lang.String> to MyTest3<java.lang.Integer>">MyTest3<String>::new</error>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ class NonStaticInner2 {
|
||||
|
||||
|
||||
static {
|
||||
I1 i1 = NonStaticInner2.Inner :: <error descr="Cannot resolve constructor 'Inner'">new</error>;
|
||||
I1 i1 = <error descr="An enclosing instance of type NonStaticInner2 is not in scope">NonStaticInner2.Inner :: new</error>;
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ class MyTest {
|
||||
|
||||
{
|
||||
I i = Foo<String> :: foo;
|
||||
I i1 = Foo<Integer> :: <error descr="Cannot resolve method 'foo'">foo</error>;
|
||||
I i1 = <error descr="Non-static method cannot be referenced from a static context">Foo<Integer> :: foo</error>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ class MyTest {
|
||||
|
||||
{
|
||||
I1 i_1 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_1</error>;
|
||||
I1 i_2 = MyTest::<error descr="Cannot resolve method '_2'">_2</error>;
|
||||
I1 i_3 = MyTest::<error descr="Cannot resolve method '_3'">_3</error>;
|
||||
I1 i_2 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_2</error>;
|
||||
I1 i_3 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_3</error>;
|
||||
I1 i_4 = MyTest::<error descr="Cannot resolve method '_4'">_4</error>;
|
||||
|
||||
I1 i1 = this::_1;
|
||||
|
||||
@@ -4,7 +4,7 @@ class Test {
|
||||
void test() {
|
||||
Comparator<Test> r2 = Test::yyy;
|
||||
Comparator1<Test> c1 = <error descr="Non-static method cannot be referenced from a static context">Test::yyy</error>;
|
||||
Comparator1<Test> c2 = Test::<error descr="Cannot resolve method 'xxx'">xxx</error>;
|
||||
Comparator1<Test> c2 = <error descr="Non-static method cannot be referenced from a static context">Test::xxx</error>;
|
||||
}
|
||||
int yyy(Test... p) { return 1; }
|
||||
int xxx(Test t) {return 42;}
|
||||
|
||||
@@ -4,6 +4,6 @@ import java.util.Comparator;
|
||||
|
||||
class Main {
|
||||
public void test() {
|
||||
Collections.sort(new ArrayList<>(), Comparator::<error descr="Cannot resolve method 'reversed'">reversed</error>);
|
||||
Collections.sort(new ArrayList<>(), <error descr="Non-static method cannot be referenced from a static context">Comparator::reversed</error>);
|
||||
}
|
||||
}
|
||||